Revert^2 "Move some image/9patch code to androidfw"
This reverts commit 917043bc2586743afda5a21386893fa8c787800b.
Reason for revert: Roll forward with fix
Test: Automatic
Bug: 296324826
Change-Id: I42a0b48c02fd497b2174c0c65f300265202f7ab1
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 412aa9b..275a0e2 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -92,10 +92,6 @@
srcs: [
"compile/IdAssigner.cpp",
"compile/InlineXmlFormatParser.cpp",
- "compile/NinePatch.cpp",
- "compile/Png.cpp",
- "compile/PngChunkFilter.cpp",
- "compile/PngCrunch.cpp",
"compile/PseudolocaleGenerator.cpp",
"compile/Pseudolocalizer.cpp",
"compile/XmlIdCollector.cpp",
@@ -112,9 +108,7 @@
"format/binary/XmlFlattener.cpp",
"format/proto/ProtoDeserialize.cpp",
"format/proto/ProtoSerialize.cpp",
- "io/BigBufferStream.cpp",
"io/File.cpp",
- "io/FileStream.cpp",
"io/FileSystem.cpp",
"io/StringStream.cpp",
"io/Util.cpp",
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index 6b1fd9f..d6502d8 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -18,12 +18,12 @@
#include "ResourceValues.h"
#include "ValueVisitor.h"
+#include "androidfw/BigBufferStream.h"
#include "format/Archive.h"
#include "format/binary/TableFlattener.h"
#include "format/binary/XmlFlattener.h"
#include "format/proto/ProtoDeserialize.h"
#include "format/proto/ProtoSerialize.h"
-#include "io/BigBufferStream.h"
#include "io/Util.h"
#include "xml/XmlDom.h"
@@ -48,7 +48,7 @@
}
// First try in proto format.
- std::unique_ptr<io::InputStream> manifest_in = manifest_file->OpenInputStream();
+ std::unique_ptr<android::InputStream> manifest_in = manifest_file->OpenInputStream();
if (manifest_in != nullptr) {
pb::XmlNode pb_node;
io::ProtoInputStreamReader proto_reader(manifest_in.get());
@@ -102,7 +102,7 @@
io::IFile* table_file = collection->FindFile(kProtoResourceTablePath);
if (table_file != nullptr) {
pb::ResourceTable pb_table;
- std::unique_ptr<io::InputStream> in = table_file->OpenInputStream();
+ std::unique_ptr<android::InputStream> in = table_file->OpenInputStream();
if (in == nullptr) {
diag->Error(android::DiagMessage(source) << "failed to open " << kProtoResourceTablePath);
return {};
@@ -129,7 +129,7 @@
return {};
}
- std::unique_ptr<io::InputStream> manifest_in = manifest_file->OpenInputStream();
+ std::unique_ptr<android::InputStream> manifest_in = manifest_file->OpenInputStream();
if (manifest_in == nullptr) {
diag->Error(android::DiagMessage(source) << "failed to open " << kAndroidManifestPath);
return {};
@@ -262,7 +262,7 @@
return false;
}
- io::BigBufferInputStream input_stream(&buffer);
+ android::BigBufferInputStream input_stream(&buffer);
if (!io::CopyInputStreamToArchive(context,
&input_stream,
path,
@@ -296,7 +296,7 @@
}
uint32_t compression_flags = file->WasCompressed() ? ArchiveEntry::kCompress : 0u;
- io::BigBufferInputStream manifest_buffer_in(&buffer);
+ android::BigBufferInputStream manifest_buffer_in(&buffer);
if (!io::CopyInputStreamToArchive(context, &manifest_buffer_in, path, compression_flags,
writer)) {
return false;
@@ -321,7 +321,7 @@
std::unique_ptr<xml::XmlResource> doc;
if (format_ == ApkFormat::kProto) {
- std::unique_ptr<io::InputStream> in = file->OpenInputStream();
+ std::unique_ptr<android::InputStream> in = file->OpenInputStream();
if (!in) {
diag->Error(android::DiagMessage() << "failed to open file");
return nullptr;
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index a0b4dab..b351d6e 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -27,6 +27,7 @@
#include "Diagnostics.h"
#include "android-base/stringprintf.h"
#include "android-base/utf8.h"
+#include "androidfw/FileStream.h"
#include "androidfw/IDiagnostics.h"
#include "androidfw/StringPiece.h"
#include "cmd/ApkInfo.h"
@@ -37,7 +38,6 @@
#include "cmd/Dump.h"
#include "cmd/Link.h"
#include "cmd/Optimize.h"
-#include "io/FileStream.h"
#include "trace/TraceBuffer.h"
#include "util/Files.h"
#include "util/Util.h"
@@ -99,7 +99,7 @@
*/
class DaemonCommand : public Command {
public:
- explicit DaemonCommand(io::FileOutputStream* out, android::IDiagnostics* diagnostics)
+ explicit DaemonCommand(android::FileOutputStream* out, android::IDiagnostics* diagnostics)
: Command("daemon", "m"), out_(out), diagnostics_(diagnostics) {
SetDescription("Runs aapt in daemon mode. Each subsequent line is a single parameter to the\n"
"command. The end of an invocation is signaled by providing an empty line.");
@@ -147,7 +147,7 @@
}
private:
- io::FileOutputStream* out_;
+ android::FileOutputStream* out_;
android::IDiagnostics* diagnostics_;
std::optional<std::string> trace_folder_;
};
@@ -167,7 +167,7 @@
// Use a smaller buffer so that there is less latency for printing to stdout.
constexpr size_t kStdOutBufferSize = 1024u;
- aapt::io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
+ android::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
aapt::text::Printer printer(&fout);
aapt::StdErrDiagnostics diagnostics;
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 728ba8a..031dd5b 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -25,13 +25,16 @@
#include "android-base/errors.h"
#include "android-base/file.h"
#include "android-base/utf8.h"
+#include "androidfw/BigBufferStream.h"
#include "androidfw/ConfigDescription.h"
+#include "androidfw/FileStream.h"
#include "androidfw/IDiagnostics.h"
+#include "androidfw/Image.h"
+#include "androidfw/Png.h"
#include "androidfw/StringPiece.h"
#include "cmd/Util.h"
#include "compile/IdAssigner.h"
#include "compile/InlineXmlFormatParser.h"
-#include "compile/Png.h"
#include "compile/PseudolocaleGenerator.h"
#include "compile/XmlIdCollector.h"
#include "format/Archive.h"
@@ -39,8 +42,6 @@
#include "format/proto/ProtoSerialize.h"
#include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
-#include "io/BigBufferStream.h"
-#include "io/FileStream.h"
#include "io/FileSystem.h"
#include "io/StringStream.h"
#include "io/Util.h"
@@ -52,9 +53,9 @@
#include "xml/XmlDom.h"
#include "xml/XmlPullParser.h"
-using ::aapt::io::FileInputStream;
using ::aapt::text::Printer;
using ::android::ConfigDescription;
+using ::android::FileInputStream;
using ::android::StringPiece;
using ::android::base::SystemErrorCodeToString;
using ::google::protobuf::io::CopyingOutputStreamAdaptor;
@@ -241,7 +242,7 @@
}
if (options.generate_text_symbols_path) {
- io::FileOutputStream fout_text(options.generate_text_symbols_path.value());
+ android::FileOutputStream fout_text(options.generate_text_symbols_path.value());
if (fout_text.HadError()) {
context->GetDiagnostics()->Error(android::DiagMessage()
@@ -307,7 +308,7 @@
}
static bool WriteHeaderAndDataToWriter(StringPiece output_path, const ResourceFile& file,
- io::KnownSizeInputStream* in, IArchiveWriter* writer,
+ android::KnownSizeInputStream* in, IArchiveWriter* writer,
android::IDiagnostics* diag) {
TRACE_CALL();
// Start the entry so we can write the header.
@@ -448,7 +449,7 @@
}
if (options.generate_text_symbols_path) {
- io::FileOutputStream fout_text(options.generate_text_symbols_path.value());
+ android::FileOutputStream fout_text(options.generate_text_symbols_path.value());
if (fout_text.HadError()) {
context->GetDiagnostics()->Error(android::DiagMessage()
@@ -498,21 +499,22 @@
}
android::BigBuffer crunched_png_buffer(4096);
- io::BigBufferOutputStream crunched_png_buffer_out(&crunched_png_buffer);
+ android::BigBufferOutputStream crunched_png_buffer_out(&crunched_png_buffer);
// Ensure that we only keep the chunks we care about if we end up
// using the original PNG instead of the crunched one.
const StringPiece content(reinterpret_cast<const char*>(data->data()), data->size());
- PngChunkFilter png_chunk_filter(content);
- std::unique_ptr<Image> image = ReadPng(context, path_data.source, &png_chunk_filter);
+ android::PngChunkFilter png_chunk_filter(content);
+ android::SourcePathDiagnostics source_diag(path_data.source, context->GetDiagnostics());
+ auto image = android::ReadPng(&png_chunk_filter, &source_diag);
if (!image) {
return false;
}
- std::unique_ptr<NinePatch> nine_patch;
+ std::unique_ptr<android::NinePatch> nine_patch;
if (path_data.extension == "9.png") {
std::string err;
- nine_patch = NinePatch::Create(image->rows.get(), image->width, image->height, &err);
+ nine_patch = android::NinePatch::Create(image->rows.get(), image->width, image->height, &err);
if (!nine_patch) {
context->GetDiagnostics()->Error(android::DiagMessage() << err);
return false;
@@ -537,7 +539,8 @@
}
// Write the crunched PNG.
- if (!WritePng(context, image.get(), nine_patch.get(), &crunched_png_buffer_out, {})) {
+ if (!android::WritePng(image.get(), nine_patch.get(), &crunched_png_buffer_out, {},
+ &source_diag, context->IsVerbose())) {
return false;
}
@@ -557,7 +560,7 @@
png_chunk_filter.Rewind();
android::BigBuffer filtered_png_buffer(4096);
- io::BigBufferOutputStream filtered_png_buffer_out(&filtered_png_buffer);
+ android::BigBufferOutputStream filtered_png_buffer_out(&filtered_png_buffer);
io::Copy(&filtered_png_buffer_out, &png_chunk_filter);
buffer.AppendBuffer(std::move(filtered_png_buffer));
}
@@ -567,7 +570,7 @@
// This will help catch exotic cases where the new code may generate larger PNGs.
std::stringstream legacy_stream{std::string(content)};
android::BigBuffer legacy_buffer(4096);
- Png png(context->GetDiagnostics());
+ android::Png png(context->GetDiagnostics());
if (!png.process(path_data.source, &legacy_stream, &legacy_buffer, {})) {
return false;
}
@@ -578,7 +581,7 @@
}
}
- io::BigBufferInputStream buffer_in(&buffer);
+ android::BigBufferInputStream buffer_in(&buffer);
return WriteHeaderAndDataToWriter(output_path, res_file, &buffer_in, writer,
context->GetDiagnostics());
}
diff --git a/tools/aapt2/cmd/Compile_test.cpp b/tools/aapt2/cmd/Compile_test.cpp
index 8880089..9337cb9 100644
--- a/tools/aapt2/cmd/Compile_test.cpp
+++ b/tools/aapt2/cmd/Compile_test.cpp
@@ -341,7 +341,7 @@
// Check resources.pb contains relative sources.
io::IFile* proto_file =
apk.get()->GetFileCollection()->FindFile("resources.pb");
- std::unique_ptr<io::InputStream> proto_stream = proto_file->OpenInputStream();
+ std::unique_ptr<android::InputStream> proto_stream = proto_file->OpenInputStream();
io::ProtoInputStreamReader proto_reader(proto_stream.get());
pb::ResourceTable pb_table;
proto_reader.ReadMessage(&pb_table);
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 387dcfe..c132792 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -24,13 +24,13 @@
#include "android-base/file.h"
#include "android-base/macros.h"
#include "android-base/stringprintf.h"
+#include "androidfw/BigBufferStream.h"
#include "androidfw/StringPiece.h"
#include "cmd/Util.h"
#include "format/binary/TableFlattener.h"
#include "format/binary/XmlFlattener.h"
#include "format/proto/ProtoDeserialize.h"
#include "format/proto/ProtoSerialize.h"
-#include "io/BigBufferStream.h"
#include "io/Util.h"
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
@@ -80,7 +80,7 @@
return false;
}
- io::BigBufferInputStream input_stream(&buffer);
+ android::BigBufferInputStream input_stream(&buffer);
return io::CopyInputStreamToArchive(context_, &input_stream, path, compression_flags, writer);
}
@@ -91,14 +91,14 @@
return false;
}
- io::BigBufferInputStream input_stream(&buffer);
+ android::BigBufferInputStream input_stream(&buffer);
return io::CopyInputStreamToArchive(context_, &input_stream, kApkResourceTablePath,
ArchiveEntry::kAlign, writer);
}
bool SerializeFile(FileReference* file, IArchiveWriter* writer) override {
if (file->type == ResourceFile::Type::kProtoXml) {
- unique_ptr<io::InputStream> in = file->file->OpenInputStream();
+ unique_ptr<android::InputStream> in = file->file->OpenInputStream();
if (in == nullptr) {
context_->GetDiagnostics()->Error(android::DiagMessage(source_)
<< "failed to open file " << *file->path);
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 864af06..6fa9ecb 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -19,19 +19,18 @@
#include <cinttypes>
#include <vector>
-#include "android-base/stringprintf.h"
-#include "androidfw/ConfigDescription.h"
-#include "androidfw/StringPiece.h"
-
#include "Debug.h"
#include "Diagnostics.h"
#include "LoadedApk.h"
#include "Util.h"
+#include "android-base/stringprintf.h"
+#include "androidfw/ConfigDescription.h"
+#include "androidfw/FileStream.h"
+#include "androidfw/StringPiece.h"
#include "format/Container.h"
#include "format/binary/BinaryResourceParser.h"
#include "format/binary/XmlFlattener.h"
#include "format/proto/ProtoDeserialize.h"
-#include "io/FileStream.h"
#include "io/ZipArchive.h"
#include "process/IResourceTableConsumer.h"
#include "text/Printer.h"
@@ -145,7 +144,7 @@
bool error = false;
for (auto container : args) {
- io::FileInputStream input(container);
+ android::FileInputStream input(container);
if (input.HadError()) {
context.GetDiagnostics()->Error(android::DiagMessage(container)
<< "failed to open file: " << input.GetError());
diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h
index 76d33d7..119a59b 100644
--- a/tools/aapt2/cmd/Dump.h
+++ b/tools/aapt2/cmd/Dump.h
@@ -17,7 +17,7 @@
#ifndef AAPT2_DUMP_H
#define AAPT2_DUMP_H
-#include <io/FileStream.h>
+#include <androidfw/FileStream.h>
#include <io/ZipArchive.h>
#include "Command.h"
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index c638873..9ca546f 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -35,6 +35,8 @@
#include "android-base/expected.h"
#include "android-base/file.h"
#include "android-base/stringprintf.h"
+#include "androidfw/BigBufferStream.h"
+#include "androidfw/FileStream.h"
#include "androidfw/IDiagnostics.h"
#include "androidfw/Locale.h"
#include "androidfw/StringPiece.h"
@@ -48,8 +50,6 @@
#include "format/binary/XmlFlattener.h"
#include "format/proto/ProtoDeserialize.h"
#include "format/proto/ProtoSerialize.h"
-#include "io/BigBufferStream.h"
-#include "io/FileStream.h"
#include "io/FileSystem.h"
#include "io/Util.h"
#include "io/ZipArchive.h"
@@ -73,8 +73,8 @@
#include "util/Files.h"
#include "xml/XmlDom.h"
-using ::aapt::io::FileInputStream;
using ::android::ConfigDescription;
+using ::android::FileInputStream;
using ::android::StringPiece;
using ::android::base::expected;
using ::android::base::StringPrintf;
@@ -263,7 +263,7 @@
return false;
}
- io::BigBufferInputStream input_stream(&buffer);
+ android::BigBufferInputStream input_stream(&buffer);
return io::CopyInputStreamToArchive(context, &input_stream, path, ArchiveEntry::kCompress,
writer);
} break;
@@ -284,7 +284,7 @@
static std::unique_ptr<xml::XmlResource> LoadXml(const std::string& path,
android::IDiagnostics* diag) {
TRACE_CALL();
- FileInputStream fin(path);
+ android::FileInputStream fin(path);
if (fin.HadError()) {
diag->Error(android::DiagMessage(path) << "failed to load XML file: " << fin.GetError());
return {};
@@ -687,7 +687,7 @@
static bool WriteStableIdMapToPath(android::IDiagnostics* diag,
const std::unordered_map<ResourceName, ResourceId>& id_map,
const std::string& id_map_path) {
- io::FileOutputStream fout(id_map_path);
+ android::FileOutputStream fout(id_map_path);
if (fout.HadError()) {
diag->Error(android::DiagMessage(id_map_path) << "failed to open: " << fout.GetError());
return false;
@@ -1197,7 +1197,7 @@
return false;
}
- io::BigBufferInputStream input_stream(&buffer);
+ android::BigBufferInputStream input_stream(&buffer);
return io::CopyInputStreamToArchive(context_, &input_stream, kApkResourceTablePath,
ArchiveEntry::kAlign, writer);
} break;
@@ -1221,7 +1221,7 @@
}
std::string out_path;
- std::unique_ptr<io::FileOutputStream> fout;
+ std::unique_ptr<android::FileOutputStream> fout;
if (options_.generate_java_class_path) {
out_path = options_.generate_java_class_path.value();
file::AppendPath(&out_path, file::PackageToPath(out_package));
@@ -1233,7 +1233,7 @@
file::AppendPath(&out_path, "R.java");
- fout = util::make_unique<io::FileOutputStream>(out_path);
+ fout = util::make_unique<android::FileOutputStream>(out_path);
if (fout->HadError()) {
context_->GetDiagnostics()->Error(android::DiagMessage()
<< "failed writing to '" << out_path
@@ -1242,9 +1242,9 @@
}
}
- std::unique_ptr<io::FileOutputStream> fout_text;
+ std::unique_ptr<android::FileOutputStream> fout_text;
if (out_text_symbols_path) {
- fout_text = util::make_unique<io::FileOutputStream>(out_text_symbols_path.value());
+ fout_text = util::make_unique<android::FileOutputStream>(out_text_symbols_path.value());
if (fout_text->HadError()) {
context_->GetDiagnostics()->Error(android::DiagMessage()
<< "failed writing to '" << out_text_symbols_path.value()
@@ -1386,7 +1386,7 @@
file::AppendPath(&out_path, "Manifest.java");
- io::FileOutputStream fout(out_path);
+ android::FileOutputStream fout(out_path);
if (fout.HadError()) {
context_->GetDiagnostics()->Error(android::DiagMessage() << "failed to open '" << out_path
<< "': " << fout.GetError());
@@ -1412,7 +1412,7 @@
}
const std::string& out_path = out.value();
- io::FileOutputStream fout(out_path);
+ android::FileOutputStream fout(out_path);
if (fout.HadError()) {
context_->GetDiagnostics()->Error(android::DiagMessage() << "failed to open '" << out_path
<< "': " << fout.GetError());
@@ -1601,7 +1601,7 @@
}
}
- std::unique_ptr<io::InputStream> input_stream = file->OpenInputStream();
+ std::unique_ptr<android::InputStream> input_stream = file->OpenInputStream();
if (input_stream == nullptr) {
context_->GetDiagnostics()->Error(android::DiagMessage(src) << "failed to open file");
return false;
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index f045dad..762441e 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -30,6 +30,7 @@
#include "ValueVisitor.h"
#include "android-base/file.h"
#include "android-base/stringprintf.h"
+#include "androidfw/BigBufferStream.h"
#include "androidfw/ConfigDescription.h"
#include "androidfw/IDiagnostics.h"
#include "androidfw/ResourceTypes.h"
@@ -39,7 +40,6 @@
#include "filter/AbiFilter.h"
#include "format/binary/TableFlattener.h"
#include "format/binary/XmlFlattener.h"
-#include "io/BigBufferStream.h"
#include "io/Util.h"
#include "optimize/MultiApkGenerator.h"
#include "optimize/Obfuscator.h"
@@ -249,7 +249,7 @@
return false;
}
- io::BigBufferInputStream manifest_buffer_in(&manifest_buffer);
+ android::BigBufferInputStream manifest_buffer_in(&manifest_buffer);
if (!io::CopyInputStreamToArchive(context_, &manifest_buffer_in, "AndroidManifest.xml",
ArchiveEntry::kCompress, writer)) {
return false;
@@ -297,7 +297,7 @@
return false;
}
- io::BigBufferInputStream table_buffer_in(&table_buffer);
+ android::BigBufferInputStream table_buffer_in(&table_buffer);
return io::CopyInputStreamToArchive(context_, &table_buffer_in, "resources.arsc",
ArchiveEntry::kAlign, writer);
}
diff --git a/tools/aapt2/compile/Image.h b/tools/aapt2/compile/Image.h
deleted file mode 100644
index db0b945..0000000
--- a/tools/aapt2/compile/Image.h
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_COMPILE_IMAGE_H
-#define AAPT_COMPILE_IMAGE_H
-
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "android-base/macros.h"
-
-namespace aapt {
-
-/**
- * An in-memory image, loaded from disk, with pixels in RGBA_8888 format.
- */
-class Image {
- public:
- explicit Image() = default;
-
- /**
- * A `height` sized array of pointers, where each element points to a
- * `width` sized row of RGBA_8888 pixels.
- */
- std::unique_ptr<uint8_t* []> rows;
-
- /**
- * The width of the image in RGBA_8888 pixels. This is int32_t because of
- * 9-patch data
- * format limitations.
- */
- int32_t width = 0;
-
- /**
- * The height of the image in RGBA_8888 pixels. This is int32_t because of
- * 9-patch data
- * format limitations.
- */
- int32_t height = 0;
-
- /**
- * Buffer to the raw image data stored sequentially.
- * Use `rows` to access the data on a row-by-row basis.
- */
- std::unique_ptr<uint8_t[]> data;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Image);
-};
-
-/**
- * A range of pixel values, starting at 'start' and ending before 'end'
- * exclusive. Or rather [a, b).
- */
-struct Range {
- int32_t start = 0;
- int32_t end = 0;
-
- explicit Range() = default;
- inline explicit Range(int32_t s, int32_t e) : start(s), end(e) {}
-};
-
-inline bool operator==(const Range& left, const Range& right) {
- return left.start == right.start && left.end == right.end;
-}
-
-/**
- * Inset lengths from all edges of a rectangle. `left` and `top` are measured
- * from the left and top
- * edges, while `right` and `bottom` are measured from the right and bottom
- * edges, respectively.
- */
-struct Bounds {
- int32_t left = 0;
- int32_t top = 0;
- int32_t right = 0;
- int32_t bottom = 0;
-
- explicit Bounds() = default;
- inline explicit Bounds(int32_t l, int32_t t, int32_t r, int32_t b)
- : left(l), top(t), right(r), bottom(b) {}
-
- bool nonZero() const;
-};
-
-inline bool Bounds::nonZero() const {
- return left != 0 || top != 0 || right != 0 || bottom != 0;
-}
-
-inline bool operator==(const Bounds& left, const Bounds& right) {
- return left.left == right.left && left.top == right.top &&
- left.right == right.right && left.bottom == right.bottom;
-}
-
-/**
- * Contains 9-patch data from a source image. All measurements exclude the 1px
- * border of the
- * source 9-patch image.
- */
-class NinePatch {
- public:
- static std::unique_ptr<NinePatch> Create(uint8_t** rows, const int32_t width,
- const int32_t height,
- std::string* err_out);
-
- /**
- * Packs the RGBA_8888 data pointed to by pixel into a uint32_t
- * with format 0xAARRGGBB (the way 9-patch expects it).
- */
- static uint32_t PackRGBA(const uint8_t* pixel);
-
- /**
- * 9-patch content padding/insets. All positions are relative to the 9-patch
- * NOT including the 1px thick source border.
- */
- Bounds padding;
-
- /**
- * Optical layout bounds/insets. This overrides the padding for
- * layout purposes. All positions are relative to the 9-patch
- * NOT including the 1px thick source border.
- * See
- * https://developer.android.com/about/versions/android-4.3.html#OpticalBounds
- */
- Bounds layout_bounds;
-
- /**
- * Outline of the image, calculated based on opacity.
- */
- Bounds outline;
-
- /**
- * The computed radius of the outline. If non-zero, the outline is a
- * rounded-rect.
- */
- float outline_radius = 0.0f;
-
- /**
- * The largest alpha value within the outline.
- */
- uint32_t outline_alpha = 0x000000ffu;
-
- /**
- * Horizontal regions of the image that are stretchable.
- * All positions are relative to the 9-patch
- * NOT including the 1px thick source border.
- */
- std::vector<Range> horizontal_stretch_regions;
-
- /**
- * Vertical regions of the image that are stretchable.
- * All positions are relative to the 9-patch
- * NOT including the 1px thick source border.
- */
- std::vector<Range> vertical_stretch_regions;
-
- /**
- * The colors within each region, fixed or stretchable.
- * For w*h regions, the color of region (x,y) is addressable
- * via index y*w + x.
- */
- std::vector<uint32_t> region_colors;
-
- /**
- * Returns serialized data containing the original basic 9-patch meta data.
- * Optical layout bounds and round rect outline data must be serialized
- * separately using SerializeOpticalLayoutBounds() and
- * SerializeRoundedRectOutline().
- */
- std::unique_ptr<uint8_t[]> SerializeBase(size_t* out_len) const;
-
- /**
- * Serializes the layout bounds.
- */
- std::unique_ptr<uint8_t[]> SerializeLayoutBounds(size_t* out_len) const;
-
- /**
- * Serializes the rounded-rect outline.
- */
- std::unique_ptr<uint8_t[]> SerializeRoundedRectOutline(size_t* out_len) const;
-
- private:
- explicit NinePatch() = default;
-
- DISALLOW_COPY_AND_ASSIGN(NinePatch);
-};
-
-::std::ostream& operator<<(::std::ostream& out, const Range& range);
-::std::ostream& operator<<(::std::ostream& out, const Bounds& bounds);
-::std::ostream& operator<<(::std::ostream& out, const NinePatch& nine_patch);
-
-} // namespace aapt
-
-#endif /* AAPT_COMPILE_IMAGE_H */
diff --git a/tools/aapt2/compile/NinePatch.cpp b/tools/aapt2/compile/NinePatch.cpp
deleted file mode 100644
index 4538ecc..0000000
--- a/tools/aapt2/compile/NinePatch.cpp
+++ /dev/null
@@ -1,698 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "compile/Image.h"
-
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include "androidfw/ResourceTypes.h"
-#include "androidfw/StringPiece.h"
-
-#include "util/Util.h"
-
-using android::StringPiece;
-
-namespace aapt {
-
-// Colors in the format 0xAARRGGBB (the way 9-patch expects it).
-constexpr static const uint32_t kColorOpaqueWhite = 0xffffffffu;
-constexpr static const uint32_t kColorOpaqueBlack = 0xff000000u;
-constexpr static const uint32_t kColorOpaqueRed = 0xffff0000u;
-
-constexpr static const uint32_t kPrimaryColor = kColorOpaqueBlack;
-constexpr static const uint32_t kSecondaryColor = kColorOpaqueRed;
-
-/**
- * Returns the alpha value encoded in the 0xAARRGBB encoded pixel.
- */
-static uint32_t get_alpha(uint32_t color);
-
-/**
- * Determines whether a color on an ImageLine is valid.
- * A 9patch image may use a transparent color as neutral,
- * or a fully opaque white color as neutral, based on the
- * pixel color at (0,0) of the image. One or the other is fine,
- * but we need to ensure consistency throughout the image.
- */
-class ColorValidator {
- public:
- virtual ~ColorValidator() = default;
-
- /**
- * Returns true if the color specified is a neutral color
- * (no padding, stretching, or optical bounds).
- */
- virtual bool IsNeutralColor(uint32_t color) const = 0;
-
- /**
- * Returns true if the color is either a neutral color
- * or one denoting padding, stretching, or optical bounds.
- */
- bool IsValidColor(uint32_t color) const {
- switch (color) {
- case kPrimaryColor:
- case kSecondaryColor:
- return true;
- }
- return IsNeutralColor(color);
- }
-};
-
-// Walks an ImageLine and records Ranges of primary and secondary colors.
-// The primary color is black and is used to denote a padding or stretching
-// range,
-// depending on which border we're iterating over.
-// The secondary color is red and is used to denote optical bounds.
-//
-// An ImageLine is a templated-interface that would look something like this if
-// it
-// were polymorphic:
-//
-// class ImageLine {
-// public:
-// virtual int32_t GetLength() const = 0;
-// virtual uint32_t GetColor(int32_t idx) const = 0;
-// };
-//
-template <typename ImageLine>
-static bool FillRanges(const ImageLine* image_line,
- const ColorValidator* color_validator,
- std::vector<Range>* primary_ranges,
- std::vector<Range>* secondary_ranges,
- std::string* out_err) {
- const int32_t length = image_line->GetLength();
-
- uint32_t last_color = 0xffffffffu;
- for (int32_t idx = 1; idx < length - 1; idx++) {
- const uint32_t color = image_line->GetColor(idx);
- if (!color_validator->IsValidColor(color)) {
- *out_err = "found an invalid color";
- return false;
- }
-
- if (color != last_color) {
- // We are ending a range. Which range?
- // note: encode the x offset without the final 1 pixel border.
- if (last_color == kPrimaryColor) {
- primary_ranges->back().end = idx - 1;
- } else if (last_color == kSecondaryColor) {
- secondary_ranges->back().end = idx - 1;
- }
-
- // We are starting a range. Which range?
- // note: encode the x offset without the final 1 pixel border.
- if (color == kPrimaryColor) {
- primary_ranges->push_back(Range(idx - 1, length - 2));
- } else if (color == kSecondaryColor) {
- secondary_ranges->push_back(Range(idx - 1, length - 2));
- }
- last_color = color;
- }
- }
- return true;
-}
-
-/**
- * Iterates over a row in an image. Implements the templated ImageLine
- * interface.
- */
-class HorizontalImageLine {
- public:
- explicit HorizontalImageLine(uint8_t** rows, int32_t xoffset, int32_t yoffset,
- int32_t length)
- : rows_(rows), xoffset_(xoffset), yoffset_(yoffset), length_(length) {}
-
- inline int32_t GetLength() const { return length_; }
-
- inline uint32_t GetColor(int32_t idx) const {
- return NinePatch::PackRGBA(rows_[yoffset_] + (idx + xoffset_) * 4);
- }
-
- private:
- uint8_t** rows_;
- int32_t xoffset_, yoffset_, length_;
-
- DISALLOW_COPY_AND_ASSIGN(HorizontalImageLine);
-};
-
-/**
- * Iterates over a column in an image. Implements the templated ImageLine
- * interface.
- */
-class VerticalImageLine {
- public:
- explicit VerticalImageLine(uint8_t** rows, int32_t xoffset, int32_t yoffset,
- int32_t length)
- : rows_(rows), xoffset_(xoffset), yoffset_(yoffset), length_(length) {}
-
- inline int32_t GetLength() const { return length_; }
-
- inline uint32_t GetColor(int32_t idx) const {
- return NinePatch::PackRGBA(rows_[yoffset_ + idx] + (xoffset_ * 4));
- }
-
- private:
- uint8_t** rows_;
- int32_t xoffset_, yoffset_, length_;
-
- DISALLOW_COPY_AND_ASSIGN(VerticalImageLine);
-};
-
-class DiagonalImageLine {
- public:
- explicit DiagonalImageLine(uint8_t** rows, int32_t xoffset, int32_t yoffset,
- int32_t xstep, int32_t ystep, int32_t length)
- : rows_(rows),
- xoffset_(xoffset),
- yoffset_(yoffset),
- xstep_(xstep),
- ystep_(ystep),
- length_(length) {}
-
- inline int32_t GetLength() const { return length_; }
-
- inline uint32_t GetColor(int32_t idx) const {
- return NinePatch::PackRGBA(rows_[yoffset_ + (idx * ystep_)] +
- ((idx + xoffset_) * xstep_) * 4);
- }
-
- private:
- uint8_t** rows_;
- int32_t xoffset_, yoffset_, xstep_, ystep_, length_;
-
- DISALLOW_COPY_AND_ASSIGN(DiagonalImageLine);
-};
-
-class TransparentNeutralColorValidator : public ColorValidator {
- public:
- bool IsNeutralColor(uint32_t color) const override {
- return get_alpha(color) == 0;
- }
-};
-
-class WhiteNeutralColorValidator : public ColorValidator {
- public:
- bool IsNeutralColor(uint32_t color) const override {
- return color == kColorOpaqueWhite;
- }
-};
-
-inline static uint32_t get_alpha(uint32_t color) {
- return (color & 0xff000000u) >> 24;
-}
-
-static bool PopulateBounds(const std::vector<Range>& padding,
- const std::vector<Range>& layout_bounds,
- const std::vector<Range>& stretch_regions, const int32_t length,
- int32_t* padding_start, int32_t* padding_end, int32_t* layout_start,
- int32_t* layout_end, StringPiece edge_name, std::string* out_err) {
- if (padding.size() > 1) {
- std::stringstream err_stream;
- err_stream << "too many padding sections on " << edge_name << " border";
- *out_err = err_stream.str();
- return false;
- }
-
- *padding_start = 0;
- *padding_end = 0;
- if (!padding.empty()) {
- const Range& range = padding.front();
- *padding_start = range.start;
- *padding_end = length - range.end;
- } else if (!stretch_regions.empty()) {
- // No padding was defined. Compute the padding from the first and last
- // stretch regions.
- *padding_start = stretch_regions.front().start;
- *padding_end = length - stretch_regions.back().end;
- }
-
- if (layout_bounds.size() > 2) {
- std::stringstream err_stream;
- err_stream << "too many layout bounds sections on " << edge_name
- << " border";
- *out_err = err_stream.str();
- return false;
- }
-
- *layout_start = 0;
- *layout_end = 0;
- if (layout_bounds.size() >= 1) {
- const Range& range = layout_bounds.front();
- // If there is only one layout bound segment, it might not start at 0, but
- // then it should
- // end at length.
- if (range.start != 0 && range.end != length) {
- std::stringstream err_stream;
- err_stream << "layout bounds on " << edge_name
- << " border must start at edge";
- *out_err = err_stream.str();
- return false;
- }
- *layout_start = range.end;
-
- if (layout_bounds.size() >= 2) {
- const Range& range = layout_bounds.back();
- if (range.end != length) {
- std::stringstream err_stream;
- err_stream << "layout bounds on " << edge_name
- << " border must start at edge";
- *out_err = err_stream.str();
- return false;
- }
- *layout_end = length - range.start;
- }
- }
- return true;
-}
-
-static int32_t CalculateSegmentCount(const std::vector<Range>& stretch_regions,
- int32_t length) {
- if (stretch_regions.size() == 0) {
- return 0;
- }
-
- const bool start_is_fixed = stretch_regions.front().start != 0;
- const bool end_is_fixed = stretch_regions.back().end != length;
- int32_t modifier = 0;
- if (start_is_fixed && end_is_fixed) {
- modifier = 1;
- } else if (!start_is_fixed && !end_is_fixed) {
- modifier = -1;
- }
- return static_cast<int32_t>(stretch_regions.size()) * 2 + modifier;
-}
-
-static uint32_t GetRegionColor(uint8_t** rows, const Bounds& region) {
- // Sample the first pixel to compare against.
- const uint32_t expected_color =
- NinePatch::PackRGBA(rows[region.top] + region.left * 4);
- for (int32_t y = region.top; y < region.bottom; y++) {
- const uint8_t* row = rows[y];
- for (int32_t x = region.left; x < region.right; x++) {
- const uint32_t color = NinePatch::PackRGBA(row + x * 4);
- if (get_alpha(color) == 0) {
- // The color is transparent.
- // If the expectedColor is not transparent, NO_COLOR.
- if (get_alpha(expected_color) != 0) {
- return android::Res_png_9patch::NO_COLOR;
- }
- } else if (color != expected_color) {
- return android::Res_png_9patch::NO_COLOR;
- }
- }
- }
-
- if (get_alpha(expected_color) == 0) {
- return android::Res_png_9patch::TRANSPARENT_COLOR;
- }
- return expected_color;
-}
-
-// Fills out_colors with each 9-patch section's color. If the whole section is
-// transparent,
-// it gets the special TRANSPARENT color. If the whole section is the same
-// color, it is assigned
-// that color. Otherwise it gets the special NO_COLOR color.
-//
-// Note that the rows contain the 9-patch 1px border, and the indices in the
-// stretch regions are
-// already offset to exclude the border. This means that each time the rows are
-// accessed,
-// the indices must be offset by 1.
-//
-// width and height also include the 9-patch 1px border.
-static void CalculateRegionColors(
- uint8_t** rows, const std::vector<Range>& horizontal_stretch_regions,
- const std::vector<Range>& vertical_stretch_regions, const int32_t width,
- const int32_t height, std::vector<uint32_t>* out_colors) {
- int32_t next_top = 0;
- Bounds bounds;
- auto row_iter = vertical_stretch_regions.begin();
- while (next_top != height) {
- if (row_iter != vertical_stretch_regions.end()) {
- if (next_top != row_iter->start) {
- // This is a fixed segment.
- // Offset the bounds by 1 to accommodate the border.
- bounds.top = next_top + 1;
- bounds.bottom = row_iter->start + 1;
- next_top = row_iter->start;
- } else {
- // This is a stretchy segment.
- // Offset the bounds by 1 to accommodate the border.
- bounds.top = row_iter->start + 1;
- bounds.bottom = row_iter->end + 1;
- next_top = row_iter->end;
- ++row_iter;
- }
- } else {
- // This is the end, fixed section.
- // Offset the bounds by 1 to accommodate the border.
- bounds.top = next_top + 1;
- bounds.bottom = height + 1;
- next_top = height;
- }
-
- int32_t next_left = 0;
- auto col_iter = horizontal_stretch_regions.begin();
- while (next_left != width) {
- if (col_iter != horizontal_stretch_regions.end()) {
- if (next_left != col_iter->start) {
- // This is a fixed segment.
- // Offset the bounds by 1 to accommodate the border.
- bounds.left = next_left + 1;
- bounds.right = col_iter->start + 1;
- next_left = col_iter->start;
- } else {
- // This is a stretchy segment.
- // Offset the bounds by 1 to accommodate the border.
- bounds.left = col_iter->start + 1;
- bounds.right = col_iter->end + 1;
- next_left = col_iter->end;
- ++col_iter;
- }
- } else {
- // This is the end, fixed section.
- // Offset the bounds by 1 to accommodate the border.
- bounds.left = next_left + 1;
- bounds.right = width + 1;
- next_left = width;
- }
- out_colors->push_back(GetRegionColor(rows, bounds));
- }
- }
-}
-
-// Calculates the insets of a row/column of pixels based on where the largest
-// alpha value begins
-// (on both sides).
-template <typename ImageLine>
-static void FindOutlineInsets(const ImageLine* image_line, int32_t* out_start,
- int32_t* out_end) {
- *out_start = 0;
- *out_end = 0;
-
- const int32_t length = image_line->GetLength();
- if (length < 3) {
- return;
- }
-
- // If the length is odd, we want both sides to process the center pixel,
- // so we use two different midpoints (to account for < and <= in the different
- // loops).
- const int32_t mid2 = length / 2;
- const int32_t mid1 = mid2 + (length % 2);
-
- uint32_t max_alpha = 0;
- for (int32_t i = 0; i < mid1 && max_alpha != 0xff; i++) {
- uint32_t alpha = get_alpha(image_line->GetColor(i));
- if (alpha > max_alpha) {
- max_alpha = alpha;
- *out_start = i;
- }
- }
-
- max_alpha = 0;
- for (int32_t i = length - 1; i >= mid2 && max_alpha != 0xff; i--) {
- uint32_t alpha = get_alpha(image_line->GetColor(i));
- if (alpha > max_alpha) {
- max_alpha = alpha;
- *out_end = length - (i + 1);
- }
- }
- return;
-}
-
-template <typename ImageLine>
-static uint32_t FindMaxAlpha(const ImageLine* image_line) {
- const int32_t length = image_line->GetLength();
- uint32_t max_alpha = 0;
- for (int32_t idx = 0; idx < length && max_alpha != 0xff; idx++) {
- uint32_t alpha = get_alpha(image_line->GetColor(idx));
- if (alpha > max_alpha) {
- max_alpha = alpha;
- }
- }
- return max_alpha;
-}
-
-// Pack the pixels in as 0xAARRGGBB (as 9-patch expects it).
-uint32_t NinePatch::PackRGBA(const uint8_t* pixel) {
- return (pixel[3] << 24) | (pixel[0] << 16) | (pixel[1] << 8) | pixel[2];
-}
-
-std::unique_ptr<NinePatch> NinePatch::Create(uint8_t** rows,
- const int32_t width,
- const int32_t height,
- std::string* out_err) {
- if (width < 3 || height < 3) {
- *out_err = "image must be at least 3x3 (1x1 image with 1 pixel border)";
- return {};
- }
-
- std::vector<Range> horizontal_padding;
- std::vector<Range> horizontal_layout_bounds;
- std::vector<Range> vertical_padding;
- std::vector<Range> vertical_layout_bounds;
- std::vector<Range> unexpected_ranges;
- std::unique_ptr<ColorValidator> color_validator;
-
- if (rows[0][3] == 0) {
- color_validator = util::make_unique<TransparentNeutralColorValidator>();
- } else if (PackRGBA(rows[0]) == kColorOpaqueWhite) {
- color_validator = util::make_unique<WhiteNeutralColorValidator>();
- } else {
- *out_err =
- "top-left corner pixel must be either opaque white or transparent";
- return {};
- }
-
- // Private constructor, can't use make_unique.
- auto nine_patch = std::unique_ptr<NinePatch>(new NinePatch());
-
- HorizontalImageLine top_row(rows, 0, 0, width);
- if (!FillRanges(&top_row, color_validator.get(),
- &nine_patch->horizontal_stretch_regions, &unexpected_ranges,
- out_err)) {
- return {};
- }
-
- if (!unexpected_ranges.empty()) {
- const Range& range = unexpected_ranges[0];
- std::stringstream err_stream;
- err_stream << "found unexpected optical bounds (red pixel) on top border "
- << "at x=" << range.start + 1;
- *out_err = err_stream.str();
- return {};
- }
-
- VerticalImageLine left_col(rows, 0, 0, height);
- if (!FillRanges(&left_col, color_validator.get(),
- &nine_patch->vertical_stretch_regions, &unexpected_ranges,
- out_err)) {
- return {};
- }
-
- if (!unexpected_ranges.empty()) {
- const Range& range = unexpected_ranges[0];
- std::stringstream err_stream;
- err_stream << "found unexpected optical bounds (red pixel) on left border "
- << "at y=" << range.start + 1;
- return {};
- }
-
- HorizontalImageLine bottom_row(rows, 0, height - 1, width);
- if (!FillRanges(&bottom_row, color_validator.get(), &horizontal_padding,
- &horizontal_layout_bounds, out_err)) {
- return {};
- }
-
- if (!PopulateBounds(horizontal_padding, horizontal_layout_bounds,
- nine_patch->horizontal_stretch_regions, width - 2,
- &nine_patch->padding.left, &nine_patch->padding.right,
- &nine_patch->layout_bounds.left,
- &nine_patch->layout_bounds.right, "bottom", out_err)) {
- return {};
- }
-
- VerticalImageLine right_col(rows, width - 1, 0, height);
- if (!FillRanges(&right_col, color_validator.get(), &vertical_padding,
- &vertical_layout_bounds, out_err)) {
- return {};
- }
-
- if (!PopulateBounds(vertical_padding, vertical_layout_bounds,
- nine_patch->vertical_stretch_regions, height - 2,
- &nine_patch->padding.top, &nine_patch->padding.bottom,
- &nine_patch->layout_bounds.top,
- &nine_patch->layout_bounds.bottom, "right", out_err)) {
- return {};
- }
-
- // Fill the region colors of the 9-patch.
- const int32_t num_rows =
- CalculateSegmentCount(nine_patch->horizontal_stretch_regions, width - 2);
- const int32_t num_cols =
- CalculateSegmentCount(nine_patch->vertical_stretch_regions, height - 2);
- if ((int64_t)num_rows * (int64_t)num_cols > 0x7f) {
- *out_err = "too many regions in 9-patch";
- return {};
- }
-
- nine_patch->region_colors.reserve(num_rows * num_cols);
- CalculateRegionColors(rows, nine_patch->horizontal_stretch_regions,
- nine_patch->vertical_stretch_regions, width - 2,
- height - 2, &nine_patch->region_colors);
-
- // Compute the outline based on opacity.
-
- // Find left and right extent of 9-patch content on center row.
- HorizontalImageLine mid_row(rows, 1, height / 2, width - 2);
- FindOutlineInsets(&mid_row, &nine_patch->outline.left,
- &nine_patch->outline.right);
-
- // Find top and bottom extent of 9-patch content on center column.
- VerticalImageLine mid_col(rows, width / 2, 1, height - 2);
- FindOutlineInsets(&mid_col, &nine_patch->outline.top,
- &nine_patch->outline.bottom);
-
- const int32_t outline_width =
- (width - 2) - nine_patch->outline.left - nine_patch->outline.right;
- const int32_t outline_height =
- (height - 2) - nine_patch->outline.top - nine_patch->outline.bottom;
-
- // Find the largest alpha value within the outline area.
- HorizontalImageLine outline_mid_row(
- rows, 1 + nine_patch->outline.left,
- 1 + nine_patch->outline.top + (outline_height / 2), outline_width);
- VerticalImageLine outline_mid_col(
- rows, 1 + nine_patch->outline.left + (outline_width / 2),
- 1 + nine_patch->outline.top, outline_height);
- nine_patch->outline_alpha =
- std::max(FindMaxAlpha(&outline_mid_row), FindMaxAlpha(&outline_mid_col));
-
- // Assuming the image is a round rect, compute the radius by marching
- // diagonally from the top left corner towards the center.
- DiagonalImageLine diagonal(rows, 1 + nine_patch->outline.left,
- 1 + nine_patch->outline.top, 1, 1,
- std::min(outline_width, outline_height));
- int32_t top_left, bottom_right;
- FindOutlineInsets(&diagonal, &top_left, &bottom_right);
-
- /* Determine source radius based upon inset:
- * sqrt(r^2 + r^2) = sqrt(i^2 + i^2) + r
- * sqrt(2) * r = sqrt(2) * i + r
- * (sqrt(2) - 1) * r = sqrt(2) * i
- * r = sqrt(2) / (sqrt(2) - 1) * i
- */
- nine_patch->outline_radius = 3.4142f * top_left;
- return nine_patch;
-}
-
-std::unique_ptr<uint8_t[]> NinePatch::SerializeBase(size_t* outLen) const {
- android::Res_png_9patch data;
- data.numXDivs = static_cast<uint8_t>(horizontal_stretch_regions.size()) * 2;
- data.numYDivs = static_cast<uint8_t>(vertical_stretch_regions.size()) * 2;
- data.numColors = static_cast<uint8_t>(region_colors.size());
- data.paddingLeft = padding.left;
- data.paddingRight = padding.right;
- data.paddingTop = padding.top;
- data.paddingBottom = padding.bottom;
-
- auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[data.serializedSize()]);
- android::Res_png_9patch::serialize(
- data, (const int32_t*)horizontal_stretch_regions.data(),
- (const int32_t*)vertical_stretch_regions.data(), region_colors.data(),
- buffer.get());
- // Convert to file endianness.
- reinterpret_cast<android::Res_png_9patch*>(buffer.get())->deviceToFile();
-
- *outLen = data.serializedSize();
- return buffer;
-}
-
-std::unique_ptr<uint8_t[]> NinePatch::SerializeLayoutBounds(
- size_t* out_len) const {
- size_t chunk_len = sizeof(uint32_t) * 4;
- auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[chunk_len]);
- uint8_t* cursor = buffer.get();
-
- memcpy(cursor, &layout_bounds.left, sizeof(layout_bounds.left));
- cursor += sizeof(layout_bounds.left);
-
- memcpy(cursor, &layout_bounds.top, sizeof(layout_bounds.top));
- cursor += sizeof(layout_bounds.top);
-
- memcpy(cursor, &layout_bounds.right, sizeof(layout_bounds.right));
- cursor += sizeof(layout_bounds.right);
-
- memcpy(cursor, &layout_bounds.bottom, sizeof(layout_bounds.bottom));
- cursor += sizeof(layout_bounds.bottom);
-
- *out_len = chunk_len;
- return buffer;
-}
-
-std::unique_ptr<uint8_t[]> NinePatch::SerializeRoundedRectOutline(
- size_t* out_len) const {
- size_t chunk_len = sizeof(uint32_t) * 6;
- auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[chunk_len]);
- uint8_t* cursor = buffer.get();
-
- memcpy(cursor, &outline.left, sizeof(outline.left));
- cursor += sizeof(outline.left);
-
- memcpy(cursor, &outline.top, sizeof(outline.top));
- cursor += sizeof(outline.top);
-
- memcpy(cursor, &outline.right, sizeof(outline.right));
- cursor += sizeof(outline.right);
-
- memcpy(cursor, &outline.bottom, sizeof(outline.bottom));
- cursor += sizeof(outline.bottom);
-
- *((float*)cursor) = outline_radius;
- cursor += sizeof(outline_radius);
-
- *((uint32_t*)cursor) = outline_alpha;
-
- *out_len = chunk_len;
- return buffer;
-}
-
-::std::ostream& operator<<(::std::ostream& out, const Range& range) {
- return out << "[" << range.start << ", " << range.end << ")";
-}
-
-::std::ostream& operator<<(::std::ostream& out, const Bounds& bounds) {
- return out << "l=" << bounds.left << " t=" << bounds.top
- << " r=" << bounds.right << " b=" << bounds.bottom;
-}
-
-::std::ostream& operator<<(::std::ostream& out, const NinePatch& nine_patch) {
- return out << "horizontalStretch:"
- << util::Joiner(nine_patch.horizontal_stretch_regions, " ")
- << " verticalStretch:"
- << util::Joiner(nine_patch.vertical_stretch_regions, " ")
- << " padding: " << nine_patch.padding
- << ", bounds: " << nine_patch.layout_bounds
- << ", outline: " << nine_patch.outline
- << " rad=" << nine_patch.outline_radius
- << " alpha=" << nine_patch.outline_alpha;
-}
-
-} // namespace aapt
diff --git a/tools/aapt2/compile/NinePatch_test.cpp b/tools/aapt2/compile/NinePatch_test.cpp
deleted file mode 100644
index f54bb2e..0000000
--- a/tools/aapt2/compile/NinePatch_test.cpp
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "compile/Image.h"
-
-#include "test/Test.h"
-
-namespace aapt {
-
-// Pixels are in RGBA_8888 packing.
-
-#define RED "\xff\x00\x00\xff"
-#define BLUE "\x00\x00\xff\xff"
-#define GREEN "\xff\x00\x00\xff"
-#define GR_70 "\xff\x00\x00\xb3"
-#define GR_50 "\xff\x00\x00\x80"
-#define GR_20 "\xff\x00\x00\x33"
-#define BLACK "\x00\x00\x00\xff"
-#define WHITE "\xff\xff\xff\xff"
-#define TRANS "\x00\x00\x00\x00"
-
-static uint8_t* k2x2[] = {
- (uint8_t*)WHITE WHITE, (uint8_t*)WHITE WHITE,
-};
-
-static uint8_t* kMixedNeutralColor3x3[] = {
- (uint8_t*)WHITE BLACK TRANS, (uint8_t*)TRANS RED TRANS,
- (uint8_t*)WHITE WHITE WHITE,
-};
-
-static uint8_t* kTransparentNeutralColor3x3[] = {
- (uint8_t*)TRANS BLACK TRANS, (uint8_t*)BLACK RED BLACK,
- (uint8_t*)TRANS BLACK TRANS,
-};
-
-static uint8_t* kSingleStretch7x6[] = {
- (uint8_t*)WHITE WHITE BLACK BLACK BLACK WHITE WHITE,
- (uint8_t*)WHITE RED RED RED RED RED WHITE,
- (uint8_t*)BLACK RED RED RED RED RED WHITE,
- (uint8_t*)BLACK RED RED RED RED RED WHITE,
- (uint8_t*)WHITE RED RED RED RED RED WHITE,
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE WHITE WHITE,
-};
-
-static uint8_t* kMultipleStretch10x7[] = {
- (uint8_t*)WHITE WHITE BLACK WHITE BLACK BLACK WHITE BLACK WHITE WHITE,
- (uint8_t*)BLACK RED BLUE RED BLUE BLUE RED BLUE RED WHITE,
- (uint8_t*)BLACK RED BLUE RED BLUE BLUE RED BLUE RED WHITE,
- (uint8_t*)WHITE RED BLUE RED BLUE BLUE RED BLUE RED WHITE,
- (uint8_t*)BLACK RED BLUE RED BLUE BLUE RED BLUE RED WHITE,
- (uint8_t*)BLACK RED BLUE RED BLUE BLUE RED BLUE RED WHITE,
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE,
-};
-
-static uint8_t* kPadding6x5[] = {
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE WHITE,
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE WHITE,
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE BLACK,
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE WHITE,
- (uint8_t*)WHITE WHITE BLACK BLACK WHITE WHITE,
-};
-
-static uint8_t* kLayoutBoundsWrongEdge3x3[] = {
- (uint8_t*)WHITE RED WHITE, (uint8_t*)RED WHITE WHITE,
- (uint8_t*)WHITE WHITE WHITE,
-};
-
-static uint8_t* kLayoutBoundsNotEdgeAligned5x5[] = {
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE,
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE,
- (uint8_t*)WHITE WHITE WHITE WHITE RED,
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE,
- (uint8_t*)WHITE WHITE RED WHITE WHITE,
-};
-
-static uint8_t* kLayoutBounds5x5[] = {
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE,
- (uint8_t*)WHITE WHITE WHITE WHITE RED,
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE,
- (uint8_t*)WHITE WHITE WHITE WHITE RED,
- (uint8_t*)WHITE RED WHITE RED WHITE,
-};
-
-static uint8_t* kAsymmetricLayoutBounds5x5[] = {
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE,
- (uint8_t*)WHITE WHITE WHITE WHITE RED,
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE,
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE,
- (uint8_t*)WHITE RED WHITE WHITE WHITE,
-};
-
-static uint8_t* kPaddingAndLayoutBounds5x5[] = {
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE,
- (uint8_t*)WHITE WHITE WHITE WHITE RED,
- (uint8_t*)WHITE WHITE WHITE WHITE BLACK,
- (uint8_t*)WHITE WHITE WHITE WHITE RED,
- (uint8_t*)WHITE RED BLACK RED WHITE,
-};
-
-static uint8_t* kColorfulImage5x5[] = {
- (uint8_t*)WHITE BLACK WHITE BLACK WHITE,
- (uint8_t*)BLACK RED BLUE GREEN WHITE,
- (uint8_t*)BLACK RED GREEN GREEN WHITE,
- (uint8_t*)WHITE TRANS BLUE GREEN WHITE,
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE,
-};
-
-static uint8_t* kOutlineOpaque10x10[] = {
- (uint8_t*)WHITE BLACK BLACK BLACK BLACK BLACK BLACK BLACK BLACK WHITE,
- (uint8_t*)WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
- (uint8_t*)WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
- (uint8_t*)WHITE TRANS TRANS GREEN GREEN GREEN GREEN TRANS TRANS WHITE,
- (uint8_t*)WHITE TRANS TRANS GREEN GREEN GREEN GREEN TRANS TRANS WHITE,
- (uint8_t*)WHITE TRANS TRANS GREEN GREEN GREEN GREEN TRANS TRANS WHITE,
- (uint8_t*)WHITE TRANS TRANS GREEN GREEN GREEN GREEN TRANS TRANS WHITE,
- (uint8_t*)WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
- (uint8_t*)WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE,
-};
-
-static uint8_t* kOutlineTranslucent10x10[] = {
- (uint8_t*)WHITE BLACK BLACK BLACK BLACK BLACK BLACK BLACK BLACK WHITE,
- (uint8_t*)WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
- (uint8_t*)WHITE TRANS TRANS GR_20 GR_20 GR_20 GR_20 TRANS TRANS WHITE,
- (uint8_t*)WHITE TRANS TRANS GR_50 GR_50 GR_50 GR_50 TRANS TRANS WHITE,
- (uint8_t*)WHITE TRANS GR_20 GR_50 GR_70 GR_70 GR_50 GR_20 TRANS WHITE,
- (uint8_t*)WHITE TRANS GR_20 GR_50 GR_70 GR_70 GR_50 GR_20 TRANS WHITE,
- (uint8_t*)WHITE TRANS TRANS GR_50 GR_50 GR_50 GR_50 TRANS TRANS WHITE,
- (uint8_t*)WHITE TRANS TRANS GR_20 GR_20 GR_20 GR_20 TRANS TRANS WHITE,
- (uint8_t*)WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE,
-};
-
-static uint8_t* kOutlineOffsetTranslucent12x10[] = {
- (uint8_t*)
- WHITE WHITE WHITE BLACK BLACK BLACK BLACK BLACK BLACK BLACK BLACK WHITE,
- (uint8_t*)
- WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
- (uint8_t*)
- WHITE TRANS TRANS TRANS TRANS GR_20 GR_20 GR_20 GR_20 TRANS TRANS WHITE,
- (uint8_t*)
- WHITE TRANS TRANS TRANS TRANS GR_50 GR_50 GR_50 GR_50 TRANS TRANS WHITE,
- (uint8_t*)
- WHITE TRANS TRANS TRANS GR_20 GR_50 GR_70 GR_70 GR_50 GR_20 TRANS WHITE,
- (uint8_t*)
- WHITE TRANS TRANS TRANS GR_20 GR_50 GR_70 GR_70 GR_50 GR_20 TRANS WHITE,
- (uint8_t*)
- WHITE TRANS TRANS TRANS TRANS GR_50 GR_50 GR_50 GR_50 TRANS TRANS WHITE,
- (uint8_t*)
- WHITE TRANS TRANS TRANS TRANS GR_20 GR_20 GR_20 GR_20 TRANS TRANS WHITE,
- (uint8_t*)
- WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
- (uint8_t*)
- WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE,
-};
-
-static uint8_t* kOutlineRadius5x5[] = {
- (uint8_t*)WHITE BLACK BLACK BLACK WHITE,
- (uint8_t*)BLACK TRANS GREEN TRANS WHITE,
- (uint8_t*)BLACK GREEN GREEN GREEN WHITE,
- (uint8_t*)BLACK TRANS GREEN TRANS WHITE,
- (uint8_t*)WHITE WHITE WHITE WHITE WHITE,
-};
-
-static uint8_t* kStretchAndPadding5x5[] = {
- (uint8_t*)WHITE WHITE BLACK WHITE WHITE, (uint8_t*)WHITE RED RED RED WHITE,
- (uint8_t*)BLACK RED RED RED BLACK, (uint8_t*)WHITE RED RED RED WHITE,
- (uint8_t*)WHITE WHITE BLACK WHITE WHITE,
-};
-
-TEST(NinePatchTest, Minimum3x3) {
- std::string err;
- EXPECT_EQ(nullptr, NinePatch::Create(k2x2, 2, 2, &err));
- EXPECT_FALSE(err.empty());
-}
-
-TEST(NinePatchTest, MixedNeutralColors) {
- std::string err;
- EXPECT_EQ(nullptr, NinePatch::Create(kMixedNeutralColor3x3, 3, 3, &err));
- EXPECT_FALSE(err.empty());
-}
-
-TEST(NinePatchTest, TransparentNeutralColor) {
- std::string err;
- EXPECT_NE(nullptr,
- NinePatch::Create(kTransparentNeutralColor3x3, 3, 3, &err));
-}
-
-TEST(NinePatchTest, SingleStretchRegion) {
- std::string err;
- std::unique_ptr<NinePatch> nine_patch =
- NinePatch::Create(kSingleStretch7x6, 7, 6, &err);
- ASSERT_NE(nullptr, nine_patch);
-
- ASSERT_EQ(1u, nine_patch->horizontal_stretch_regions.size());
- ASSERT_EQ(1u, nine_patch->vertical_stretch_regions.size());
-
- EXPECT_EQ(Range(1, 4), nine_patch->horizontal_stretch_regions.front());
- EXPECT_EQ(Range(1, 3), nine_patch->vertical_stretch_regions.front());
-}
-
-TEST(NinePatchTest, MultipleStretchRegions) {
- std::string err;
- std::unique_ptr<NinePatch> nine_patch =
- NinePatch::Create(kMultipleStretch10x7, 10, 7, &err);
- ASSERT_NE(nullptr, nine_patch);
-
- ASSERT_EQ(3u, nine_patch->horizontal_stretch_regions.size());
- ASSERT_EQ(2u, nine_patch->vertical_stretch_regions.size());
-
- EXPECT_EQ(Range(1, 2), nine_patch->horizontal_stretch_regions[0]);
- EXPECT_EQ(Range(3, 5), nine_patch->horizontal_stretch_regions[1]);
- EXPECT_EQ(Range(6, 7), nine_patch->horizontal_stretch_regions[2]);
-
- EXPECT_EQ(Range(0, 2), nine_patch->vertical_stretch_regions[0]);
- EXPECT_EQ(Range(3, 5), nine_patch->vertical_stretch_regions[1]);
-}
-
-TEST(NinePatchTest, InferPaddingFromStretchRegions) {
- std::string err;
- std::unique_ptr<NinePatch> nine_patch =
- NinePatch::Create(kMultipleStretch10x7, 10, 7, &err);
- ASSERT_NE(nullptr, nine_patch);
- EXPECT_EQ(Bounds(1, 0, 1, 0), nine_patch->padding);
-}
-
-TEST(NinePatchTest, Padding) {
- std::string err;
- std::unique_ptr<NinePatch> nine_patch =
- NinePatch::Create(kPadding6x5, 6, 5, &err);
- ASSERT_NE(nullptr, nine_patch);
- EXPECT_EQ(Bounds(1, 1, 1, 1), nine_patch->padding);
-}
-
-TEST(NinePatchTest, LayoutBoundsAreOnWrongEdge) {
- std::string err;
- EXPECT_EQ(nullptr, NinePatch::Create(kLayoutBoundsWrongEdge3x3, 3, 3, &err));
- EXPECT_FALSE(err.empty());
-}
-
-TEST(NinePatchTest, LayoutBoundsMustTouchEdges) {
- std::string err;
- EXPECT_EQ(nullptr,
- NinePatch::Create(kLayoutBoundsNotEdgeAligned5x5, 5, 5, &err));
- EXPECT_FALSE(err.empty());
-}
-
-TEST(NinePatchTest, LayoutBounds) {
- std::string err;
- std::unique_ptr<NinePatch> nine_patch =
- NinePatch::Create(kLayoutBounds5x5, 5, 5, &err);
- ASSERT_NE(nullptr, nine_patch);
- EXPECT_EQ(Bounds(1, 1, 1, 1), nine_patch->layout_bounds);
-
- nine_patch = NinePatch::Create(kAsymmetricLayoutBounds5x5, 5, 5, &err);
- ASSERT_NE(nullptr, nine_patch);
- EXPECT_EQ(Bounds(1, 1, 0, 0), nine_patch->layout_bounds);
-}
-
-TEST(NinePatchTest, PaddingAndLayoutBounds) {
- std::string err;
- std::unique_ptr<NinePatch> nine_patch =
- NinePatch::Create(kPaddingAndLayoutBounds5x5, 5, 5, &err);
- ASSERT_NE(nullptr, nine_patch);
- EXPECT_EQ(Bounds(1, 1, 1, 1), nine_patch->padding);
- EXPECT_EQ(Bounds(1, 1, 1, 1), nine_patch->layout_bounds);
-}
-
-TEST(NinePatchTest, RegionColorsAreCorrect) {
- std::string err;
- std::unique_ptr<NinePatch> nine_patch =
- NinePatch::Create(kColorfulImage5x5, 5, 5, &err);
- ASSERT_NE(nullptr, nine_patch);
-
- std::vector<uint32_t> expected_colors = {
- NinePatch::PackRGBA((uint8_t*)RED),
- (uint32_t)android::Res_png_9patch::NO_COLOR,
- NinePatch::PackRGBA((uint8_t*)GREEN),
- (uint32_t)android::Res_png_9patch::TRANSPARENT_COLOR,
- NinePatch::PackRGBA((uint8_t*)BLUE),
- NinePatch::PackRGBA((uint8_t*)GREEN),
- };
- EXPECT_EQ(expected_colors, nine_patch->region_colors);
-}
-
-TEST(NinePatchTest, OutlineFromOpaqueImage) {
- std::string err;
- std::unique_ptr<NinePatch> nine_patch =
- NinePatch::Create(kOutlineOpaque10x10, 10, 10, &err);
- ASSERT_NE(nullptr, nine_patch);
- EXPECT_EQ(Bounds(2, 2, 2, 2), nine_patch->outline);
- EXPECT_EQ(0x000000ffu, nine_patch->outline_alpha);
- EXPECT_EQ(0.0f, nine_patch->outline_radius);
-}
-
-TEST(NinePatchTest, OutlineFromTranslucentImage) {
- std::string err;
- std::unique_ptr<NinePatch> nine_patch =
- NinePatch::Create(kOutlineTranslucent10x10, 10, 10, &err);
- ASSERT_NE(nullptr, nine_patch);
- EXPECT_EQ(Bounds(3, 3, 3, 3), nine_patch->outline);
- EXPECT_EQ(0x000000b3u, nine_patch->outline_alpha);
- EXPECT_EQ(0.0f, nine_patch->outline_radius);
-}
-
-TEST(NinePatchTest, OutlineFromOffCenterImage) {
- std::string err;
- std::unique_ptr<NinePatch> nine_patch =
- NinePatch::Create(kOutlineOffsetTranslucent12x10, 12, 10, &err);
- ASSERT_NE(nullptr, nine_patch);
-
- // TODO(adamlesinski): The old AAPT algorithm searches from the outside to the
- // middle for each inset. If the outline is shifted, the search may not find a
- // closer bounds.
- // This check should be:
- // EXPECT_EQ(Bounds(5, 3, 3, 3), ninePatch->outline);
- // but until I know what behavior I'm breaking, I will leave it at the
- // incorrect:
- EXPECT_EQ(Bounds(4, 3, 3, 3), nine_patch->outline);
-
- EXPECT_EQ(0x000000b3u, nine_patch->outline_alpha);
- EXPECT_EQ(0.0f, nine_patch->outline_radius);
-}
-
-TEST(NinePatchTest, OutlineRadius) {
- std::string err;
- std::unique_ptr<NinePatch> nine_patch =
- NinePatch::Create(kOutlineRadius5x5, 5, 5, &err);
- ASSERT_NE(nullptr, nine_patch);
- EXPECT_EQ(Bounds(0, 0, 0, 0), nine_patch->outline);
- EXPECT_EQ(3.4142f, nine_patch->outline_radius);
-}
-
-::testing::AssertionResult BigEndianOne(uint8_t* cursor) {
- if (cursor[0] == 0 && cursor[1] == 0 && cursor[2] == 0 && cursor[3] == 1) {
- return ::testing::AssertionSuccess();
- }
- return ::testing::AssertionFailure() << "Not BigEndian 1";
-}
-
-TEST(NinePatchTest, SerializePngEndianness) {
- std::string err;
- std::unique_ptr<NinePatch> nine_patch =
- NinePatch::Create(kStretchAndPadding5x5, 5, 5, &err);
- ASSERT_NE(nullptr, nine_patch);
-
- size_t len;
- std::unique_ptr<uint8_t[]> data = nine_patch->SerializeBase(&len);
- ASSERT_NE(nullptr, data);
- ASSERT_NE(0u, len);
-
- // Skip past wasDeserialized + numXDivs + numYDivs + numColors + xDivsOffset +
- // yDivsOffset
- // (12 bytes)
- uint8_t* cursor = data.get() + 12;
-
- // Check that padding is big-endian. Expecting value 1.
- EXPECT_TRUE(BigEndianOne(cursor));
- EXPECT_TRUE(BigEndianOne(cursor + 4));
- EXPECT_TRUE(BigEndianOne(cursor + 8));
- EXPECT_TRUE(BigEndianOne(cursor + 12));
-}
-
-} // namespace aapt
diff --git a/tools/aapt2/compile/Png.cpp b/tools/aapt2/compile/Png.cpp
deleted file mode 100644
index 76db815..0000000
--- a/tools/aapt2/compile/Png.cpp
+++ /dev/null
@@ -1,1319 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Png.h"
-
-#include <png.h>
-#include <zlib.h>
-
-#include <iostream>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include "androidfw/BigBuffer.h"
-#include "androidfw/ResourceTypes.h"
-#include "androidfw/Source.h"
-#include "trace/TraceBuffer.h"
-#include "util/Util.h"
-
-namespace aapt {
-
-constexpr bool kDebug = false;
-
-struct PngInfo {
- ~PngInfo() {
- for (png_bytep row : rows) {
- if (row != nullptr) {
- delete[] row;
- }
- }
-
- delete[] xDivs;
- delete[] yDivs;
- }
-
- void* serialize9Patch() {
- void* serialized = android::Res_png_9patch::serialize(info9Patch, xDivs,
- yDivs, colors.data());
- reinterpret_cast<android::Res_png_9patch*>(serialized)->deviceToFile();
- return serialized;
- }
-
- uint32_t width = 0;
- uint32_t height = 0;
- std::vector<png_bytep> rows;
-
- bool is9Patch = false;
- android::Res_png_9patch info9Patch;
- int32_t* xDivs = nullptr;
- int32_t* yDivs = nullptr;
- std::vector<uint32_t> colors;
-
- // Layout padding.
- bool haveLayoutBounds = false;
- int32_t layoutBoundsLeft;
- int32_t layoutBoundsTop;
- int32_t layoutBoundsRight;
- int32_t layoutBoundsBottom;
-
- // Round rect outline description.
- int32_t outlineInsetsLeft;
- int32_t outlineInsetsTop;
- int32_t outlineInsetsRight;
- int32_t outlineInsetsBottom;
- float outlineRadius;
- uint8_t outlineAlpha;
-};
-
-static void readDataFromStream(png_structp readPtr, png_bytep data,
- png_size_t length) {
- std::istream* input =
- reinterpret_cast<std::istream*>(png_get_io_ptr(readPtr));
- if (!input->read(reinterpret_cast<char*>(data), length)) {
- png_error(readPtr, strerror(errno));
- }
-}
-
-static void writeDataToStream(png_structp writePtr, png_bytep data,
- png_size_t length) {
- android::BigBuffer* outBuffer = reinterpret_cast<android::BigBuffer*>(png_get_io_ptr(writePtr));
- png_bytep buf = outBuffer->NextBlock<png_byte>(length);
- memcpy(buf, data, length);
-}
-
-static void flushDataToStream(png_structp /*writePtr*/) {}
-
-static void logWarning(png_structp readPtr, png_const_charp warningMessage) {
- android::IDiagnostics* diag =
- reinterpret_cast<android::IDiagnostics*>(png_get_error_ptr(readPtr));
- diag->Warn(android::DiagMessage() << warningMessage);
-}
-
-static bool readPng(android::IDiagnostics* diag, png_structp readPtr, png_infop infoPtr,
- PngInfo* outInfo) {
- if (setjmp(png_jmpbuf(readPtr))) {
- diag->Error(android::DiagMessage() << "failed reading png");
- return false;
- }
-
- png_set_sig_bytes(readPtr, kPngSignatureSize);
- png_read_info(readPtr, infoPtr);
-
- int colorType, bitDepth, interlaceType, compressionType;
- png_get_IHDR(readPtr, infoPtr, &outInfo->width, &outInfo->height, &bitDepth,
- &colorType, &interlaceType, &compressionType, nullptr);
-
- if (colorType == PNG_COLOR_TYPE_PALETTE) {
- png_set_palette_to_rgb(readPtr);
- }
-
- if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) {
- png_set_expand_gray_1_2_4_to_8(readPtr);
- }
-
- if (png_get_valid(readPtr, infoPtr, PNG_INFO_tRNS)) {
- png_set_tRNS_to_alpha(readPtr);
- }
-
- if (bitDepth == 16) {
- png_set_strip_16(readPtr);
- }
-
- if (!(colorType & PNG_COLOR_MASK_ALPHA)) {
- png_set_add_alpha(readPtr, 0xFF, PNG_FILLER_AFTER);
- }
-
- if (colorType == PNG_COLOR_TYPE_GRAY ||
- colorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
- png_set_gray_to_rgb(readPtr);
- }
-
- png_set_interlace_handling(readPtr);
- png_read_update_info(readPtr, infoPtr);
-
- const uint32_t rowBytes = png_get_rowbytes(readPtr, infoPtr);
- outInfo->rows.resize(outInfo->height);
- for (size_t i = 0; i < outInfo->height; i++) {
- outInfo->rows[i] = new png_byte[rowBytes];
- }
-
- png_read_image(readPtr, outInfo->rows.data());
- png_read_end(readPtr, infoPtr);
- return true;
-}
-
-static void checkNinePatchSerialization(android::Res_png_9patch* inPatch,
- void* data) {
- size_t patchSize = inPatch->serializedSize();
- void* newData = malloc(patchSize);
- memcpy(newData, data, patchSize);
- android::Res_png_9patch* outPatch = inPatch->deserialize(newData);
- outPatch->fileToDevice();
- // deserialization is done in place, so outPatch == newData
- assert(outPatch == newData);
- assert(outPatch->numXDivs == inPatch->numXDivs);
- assert(outPatch->numYDivs == inPatch->numYDivs);
- assert(outPatch->paddingLeft == inPatch->paddingLeft);
- assert(outPatch->paddingRight == inPatch->paddingRight);
- assert(outPatch->paddingTop == inPatch->paddingTop);
- assert(outPatch->paddingBottom == inPatch->paddingBottom);
- /* for (int i = 0; i < outPatch->numXDivs; i++) {
- assert(outPatch->getXDivs()[i] == inPatch->getXDivs()[i]);
- }
- for (int i = 0; i < outPatch->numYDivs; i++) {
- assert(outPatch->getYDivs()[i] == inPatch->getYDivs()[i]);
- }
- for (int i = 0; i < outPatch->numColors; i++) {
- assert(outPatch->getColors()[i] == inPatch->getColors()[i]);
- }*/
- free(newData);
-}
-
-/*static void dump_image(int w, int h, const png_byte* const* rows, int
-color_type) {
- int i, j, rr, gg, bb, aa;
-
- int bpp;
- if (color_type == PNG_COLOR_TYPE_PALETTE || color_type ==
-PNG_COLOR_TYPE_GRAY) {
- bpp = 1;
- } else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
- bpp = 2;
- } else if (color_type == PNG_COLOR_TYPE_RGB || color_type ==
-PNG_COLOR_TYPE_RGB_ALPHA) {
- // We use a padding byte even when there is no alpha
- bpp = 4;
- } else {
- printf("Unknown color type %d.\n", color_type);
- }
-
- for (j = 0; j < h; j++) {
- const png_byte* row = rows[j];
- for (i = 0; i < w; i++) {
- rr = row[0];
- gg = row[1];
- bb = row[2];
- aa = row[3];
- row += bpp;
-
- if (i == 0) {
- printf("Row %d:", j);
- }
- switch (bpp) {
- case 1:
- printf(" (%d)", rr);
- break;
- case 2:
- printf(" (%d %d", rr, gg);
- break;
- case 3:
- printf(" (%d %d %d)", rr, gg, bb);
- break;
- case 4:
- printf(" (%d %d %d %d)", rr, gg, bb, aa);
- break;
- }
- if (i == (w - 1)) {
- printf("\n");
- }
- }
- }
-}*/
-
-#ifdef MAX
-#undef MAX
-#endif
-#ifdef ABS
-#undef ABS
-#endif
-
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-#define ABS(a) ((a) < 0 ? -(a) : (a))
-
-static void analyze_image(android::IDiagnostics* diag, const PngInfo& imageInfo,
- int grayscaleTolerance, png_colorp rgbPalette, png_bytep alphaPalette,
- int* paletteEntries, bool* hasTransparency, int* colorType,
- png_bytepp outRows) {
- int w = imageInfo.width;
- int h = imageInfo.height;
- int i, j, rr, gg, bb, aa, idx;
- uint32_t colors[256], col;
- int num_colors = 0;
- int maxGrayDeviation = 0;
-
- bool isOpaque = true;
- bool isPalette = true;
- bool isGrayscale = true;
-
- // Scan the entire image and determine if:
- // 1. Every pixel has R == G == B (grayscale)
- // 2. Every pixel has A == 255 (opaque)
- // 3. There are no more than 256 distinct RGBA colors
-
- if (kDebug) {
- printf("Initial image data:\n");
- // dump_image(w, h, imageInfo.rows.data(), PNG_COLOR_TYPE_RGB_ALPHA);
- }
-
- for (j = 0; j < h; j++) {
- const png_byte* row = imageInfo.rows[j];
- png_bytep out = outRows[j];
- for (i = 0; i < w; i++) {
- rr = *row++;
- gg = *row++;
- bb = *row++;
- aa = *row++;
-
- int odev = maxGrayDeviation;
- maxGrayDeviation = MAX(ABS(rr - gg), maxGrayDeviation);
- maxGrayDeviation = MAX(ABS(gg - bb), maxGrayDeviation);
- maxGrayDeviation = MAX(ABS(bb - rr), maxGrayDeviation);
- if (maxGrayDeviation > odev) {
- if (kDebug) {
- printf("New max dev. = %d at pixel (%d, %d) = (%d %d %d %d)\n",
- maxGrayDeviation, i, j, rr, gg, bb, aa);
- }
- }
-
- // Check if image is really grayscale
- if (isGrayscale) {
- if (rr != gg || rr != bb) {
- if (kDebug) {
- printf("Found a non-gray pixel at %d, %d = (%d %d %d %d)\n", i, j,
- rr, gg, bb, aa);
- }
- isGrayscale = false;
- }
- }
-
- // Check if image is really opaque
- if (isOpaque) {
- if (aa != 0xff) {
- if (kDebug) {
- printf("Found a non-opaque pixel at %d, %d = (%d %d %d %d)\n", i, j,
- rr, gg, bb, aa);
- }
- isOpaque = false;
- }
- }
-
- // Check if image is really <= 256 colors
- if (isPalette) {
- col = (uint32_t)((rr << 24) | (gg << 16) | (bb << 8) | aa);
- bool match = false;
- for (idx = 0; idx < num_colors; idx++) {
- if (colors[idx] == col) {
- match = true;
- break;
- }
- }
-
- // Write the palette index for the pixel to outRows optimistically
- // We might overwrite it later if we decide to encode as gray or
- // gray + alpha
- *out++ = idx;
- if (!match) {
- if (num_colors == 256) {
- if (kDebug) {
- printf("Found 257th color at %d, %d\n", i, j);
- }
- isPalette = false;
- } else {
- colors[num_colors++] = col;
- }
- }
- }
- }
- }
-
- *paletteEntries = 0;
- *hasTransparency = !isOpaque;
- int bpp = isOpaque ? 3 : 4;
- int paletteSize = w * h + bpp * num_colors;
-
- if (kDebug) {
- printf("isGrayscale = %s\n", isGrayscale ? "true" : "false");
- printf("isOpaque = %s\n", isOpaque ? "true" : "false");
- printf("isPalette = %s\n", isPalette ? "true" : "false");
- printf("Size w/ palette = %d, gray+alpha = %d, rgb(a) = %d\n", paletteSize,
- 2 * w * h, bpp * w * h);
- printf("Max gray deviation = %d, tolerance = %d\n", maxGrayDeviation,
- grayscaleTolerance);
- }
-
- // Choose the best color type for the image.
- // 1. Opaque gray - use COLOR_TYPE_GRAY at 1 byte/pixel
- // 2. Gray + alpha - use COLOR_TYPE_PALETTE if the number of distinct
- // combinations
- // is sufficiently small, otherwise use COLOR_TYPE_GRAY_ALPHA
- // 3. RGB(A) - use COLOR_TYPE_PALETTE if the number of distinct colors is
- // sufficiently
- // small, otherwise use COLOR_TYPE_RGB{_ALPHA}
- if (isGrayscale) {
- if (isOpaque) {
- *colorType = PNG_COLOR_TYPE_GRAY; // 1 byte/pixel
- } else {
- // Use a simple heuristic to determine whether using a palette will
- // save space versus using gray + alpha for each pixel.
- // This doesn't take into account chunk overhead, filtering, LZ
- // compression, etc.
- if (isPalette && (paletteSize < 2 * w * h)) {
- *colorType = PNG_COLOR_TYPE_PALETTE; // 1 byte/pixel + 4 bytes/color
- } else {
- *colorType = PNG_COLOR_TYPE_GRAY_ALPHA; // 2 bytes per pixel
- }
- }
- } else if (isPalette && (paletteSize < bpp * w * h)) {
- *colorType = PNG_COLOR_TYPE_PALETTE;
- } else {
- if (maxGrayDeviation <= grayscaleTolerance) {
- diag->Note(android::DiagMessage()
- << "forcing image to gray (max deviation = " << maxGrayDeviation << ")");
- *colorType = isOpaque ? PNG_COLOR_TYPE_GRAY : PNG_COLOR_TYPE_GRAY_ALPHA;
- } else {
- *colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
- }
- }
-
- // Perform postprocessing of the image or palette data based on the final
- // color type chosen
-
- if (*colorType == PNG_COLOR_TYPE_PALETTE) {
- // Create separate RGB and Alpha palettes and set the number of colors
- *paletteEntries = num_colors;
-
- // Create the RGB and alpha palettes
- for (int idx = 0; idx < num_colors; idx++) {
- col = colors[idx];
- rgbPalette[idx].red = (png_byte)((col >> 24) & 0xff);
- rgbPalette[idx].green = (png_byte)((col >> 16) & 0xff);
- rgbPalette[idx].blue = (png_byte)((col >> 8) & 0xff);
- alphaPalette[idx] = (png_byte)(col & 0xff);
- }
- } else if (*colorType == PNG_COLOR_TYPE_GRAY ||
- *colorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
- // If the image is gray or gray + alpha, compact the pixels into outRows
- for (j = 0; j < h; j++) {
- const png_byte* row = imageInfo.rows[j];
- png_bytep out = outRows[j];
- for (i = 0; i < w; i++) {
- rr = *row++;
- gg = *row++;
- bb = *row++;
- aa = *row++;
-
- if (isGrayscale) {
- *out++ = rr;
- } else {
- *out++ = (png_byte)(rr * 0.2126f + gg * 0.7152f + bb * 0.0722f);
- }
- if (!isOpaque) {
- *out++ = aa;
- }
- }
- }
- }
-}
-
-static bool writePng(android::IDiagnostics* diag, png_structp writePtr, png_infop infoPtr,
- PngInfo* info, int grayScaleTolerance) {
- if (setjmp(png_jmpbuf(writePtr))) {
- diag->Error(android::DiagMessage() << "failed to write png");
- return false;
- }
-
- uint32_t width, height;
- int colorType, bitDepth, interlaceType, compressionType;
-
- png_unknown_chunk unknowns[3];
- unknowns[0].data = nullptr;
- unknowns[1].data = nullptr;
- unknowns[2].data = nullptr;
-
- png_bytepp outRows =
- (png_bytepp)malloc((int)info->height * sizeof(png_bytep));
- if (outRows == (png_bytepp)0) {
- printf("Can't allocate output buffer!\n");
- exit(1);
- }
- for (uint32_t i = 0; i < info->height; i++) {
- outRows[i] = (png_bytep)malloc(2 * (int)info->width);
- if (outRows[i] == (png_bytep)0) {
- printf("Can't allocate output buffer!\n");
- exit(1);
- }
- }
-
- png_set_compression_level(writePtr, Z_BEST_COMPRESSION);
-
- if (kDebug) {
- diag->Note(android::DiagMessage()
- << "writing image: w = " << info->width << ", h = " << info->height);
- }
-
- png_color rgbPalette[256];
- png_byte alphaPalette[256];
- bool hasTransparency;
- int paletteEntries;
-
- analyze_image(diag, *info, grayScaleTolerance, rgbPalette, alphaPalette,
- &paletteEntries, &hasTransparency, &colorType, outRows);
-
- // If the image is a 9-patch, we need to preserve it as a ARGB file to make
- // sure the pixels will not be pre-dithered/clamped until we decide they are
- if (info->is9Patch &&
- (colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_GRAY ||
- colorType == PNG_COLOR_TYPE_PALETTE)) {
- colorType = PNG_COLOR_TYPE_RGB_ALPHA;
- }
-
- if (kDebug) {
- switch (colorType) {
- case PNG_COLOR_TYPE_PALETTE:
- diag->Note(android::DiagMessage() << "has " << paletteEntries << " colors"
- << (hasTransparency ? " (with alpha)" : "")
- << ", using PNG_COLOR_TYPE_PALLETTE");
- break;
- case PNG_COLOR_TYPE_GRAY:
- diag->Note(android::DiagMessage() << "is opaque gray, using PNG_COLOR_TYPE_GRAY");
- break;
- case PNG_COLOR_TYPE_GRAY_ALPHA:
- diag->Note(android::DiagMessage() << "is gray + alpha, using PNG_COLOR_TYPE_GRAY_ALPHA");
- break;
- case PNG_COLOR_TYPE_RGB:
- diag->Note(android::DiagMessage() << "is opaque RGB, using PNG_COLOR_TYPE_RGB");
- break;
- case PNG_COLOR_TYPE_RGB_ALPHA:
- diag->Note(android::DiagMessage() << "is RGB + alpha, using PNG_COLOR_TYPE_RGB_ALPHA");
- break;
- }
- }
-
- png_set_IHDR(writePtr, infoPtr, info->width, info->height, 8, colorType,
- PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
- PNG_FILTER_TYPE_DEFAULT);
-
- if (colorType == PNG_COLOR_TYPE_PALETTE) {
- png_set_PLTE(writePtr, infoPtr, rgbPalette, paletteEntries);
- if (hasTransparency) {
- png_set_tRNS(writePtr, infoPtr, alphaPalette, paletteEntries,
- (png_color_16p)0);
- }
- png_set_filter(writePtr, 0, PNG_NO_FILTERS);
- } else {
- png_set_filter(writePtr, 0, PNG_ALL_FILTERS);
- }
-
- if (info->is9Patch) {
- int chunkCount = 2 + (info->haveLayoutBounds ? 1 : 0);
- int pIndex = info->haveLayoutBounds ? 2 : 1;
- int bIndex = 1;
- int oIndex = 0;
-
- // Chunks ordered thusly because older platforms depend on the base 9 patch
- // data being last
- png_bytep chunkNames = info->haveLayoutBounds
- ? (png_bytep) "npOl\0npLb\0npTc\0"
- : (png_bytep) "npOl\0npTc";
-
- // base 9 patch data
- if (kDebug) {
- diag->Note(android::DiagMessage() << "adding 9-patch info..");
- }
- memcpy((char*)unknowns[pIndex].name, "npTc", 5);
- unknowns[pIndex].data = (png_byte*)info->serialize9Patch();
- unknowns[pIndex].size = info->info9Patch.serializedSize();
- // TODO: remove the check below when everything works
- checkNinePatchSerialization(&info->info9Patch, unknowns[pIndex].data);
-
- // automatically generated 9 patch outline data
- int chunkSize = sizeof(png_uint_32) * 6;
- memcpy((char*)unknowns[oIndex].name, "npOl", 5);
- unknowns[oIndex].data = (png_byte*)calloc(chunkSize, 1);
- png_byte outputData[chunkSize];
- memcpy(&outputData, &info->outlineInsetsLeft, 4 * sizeof(png_uint_32));
- ((float*)outputData)[4] = info->outlineRadius;
- ((png_uint_32*)outputData)[5] = info->outlineAlpha;
- memcpy(unknowns[oIndex].data, &outputData, chunkSize);
- unknowns[oIndex].size = chunkSize;
-
- // optional optical inset / layout bounds data
- if (info->haveLayoutBounds) {
- int chunkSize = sizeof(png_uint_32) * 4;
- memcpy((char*)unknowns[bIndex].name, "npLb", 5);
- unknowns[bIndex].data = (png_byte*)calloc(chunkSize, 1);
- memcpy(unknowns[bIndex].data, &info->layoutBoundsLeft, chunkSize);
- unknowns[bIndex].size = chunkSize;
- }
-
- for (int i = 0; i < chunkCount; i++) {
- unknowns[i].location = PNG_HAVE_PLTE;
- }
- png_set_keep_unknown_chunks(writePtr, PNG_HANDLE_CHUNK_ALWAYS, chunkNames,
- chunkCount);
- png_set_unknown_chunks(writePtr, infoPtr, unknowns, chunkCount);
-
-#if PNG_LIBPNG_VER < 10600
- // Deal with unknown chunk location bug in 1.5.x and earlier.
- png_set_unknown_chunk_location(writePtr, infoPtr, 0, PNG_HAVE_PLTE);
- if (info->haveLayoutBounds) {
- png_set_unknown_chunk_location(writePtr, infoPtr, 1, PNG_HAVE_PLTE);
- }
-#endif
- }
-
- png_write_info(writePtr, infoPtr);
-
- png_bytepp rows;
- if (colorType == PNG_COLOR_TYPE_RGB ||
- colorType == PNG_COLOR_TYPE_RGB_ALPHA) {
- if (colorType == PNG_COLOR_TYPE_RGB) {
- png_set_filler(writePtr, 0, PNG_FILLER_AFTER);
- }
- rows = info->rows.data();
- } else {
- rows = outRows;
- }
- png_write_image(writePtr, rows);
-
- if (kDebug) {
- printf("Final image data:\n");
- // dump_image(info->width, info->height, rows, colorType);
- }
-
- png_write_end(writePtr, infoPtr);
-
- for (uint32_t i = 0; i < info->height; i++) {
- free(outRows[i]);
- }
- free(outRows);
- free(unknowns[0].data);
- free(unknowns[1].data);
- free(unknowns[2].data);
-
- png_get_IHDR(writePtr, infoPtr, &width, &height, &bitDepth, &colorType,
- &interlaceType, &compressionType, nullptr);
-
- if (kDebug) {
- diag->Note(android::DiagMessage()
- << "image written: w = " << width << ", h = " << height << ", d = " << bitDepth
- << ", colors = " << colorType << ", inter = " << interlaceType
- << ", comp = " << compressionType);
- }
- return true;
-}
-
-constexpr uint32_t kColorWhite = 0xffffffffu;
-constexpr uint32_t kColorTick = 0xff000000u;
-constexpr uint32_t kColorLayoutBoundsTick = 0xff0000ffu;
-
-enum class TickType { kNone, kTick, kLayoutBounds, kBoth };
-
-static TickType tickType(png_bytep p, bool transparent, const char** outError) {
- png_uint_32 color = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
-
- if (transparent) {
- if (p[3] == 0) {
- return TickType::kNone;
- }
- if (color == kColorLayoutBoundsTick) {
- return TickType::kLayoutBounds;
- }
- if (color == kColorTick) {
- return TickType::kTick;
- }
-
- // Error cases
- if (p[3] != 0xff) {
- *outError =
- "Frame pixels must be either solid or transparent "
- "(not intermediate alphas)";
- return TickType::kNone;
- }
-
- if (p[0] != 0 || p[1] != 0 || p[2] != 0) {
- *outError = "Ticks in transparent frame must be black or red";
- }
- return TickType::kTick;
- }
-
- if (p[3] != 0xFF) {
- *outError = "White frame must be a solid color (no alpha)";
- }
- if (color == kColorWhite) {
- return TickType::kNone;
- }
- if (color == kColorTick) {
- return TickType::kTick;
- }
- if (color == kColorLayoutBoundsTick) {
- return TickType::kLayoutBounds;
- }
-
- if (p[0] != 0 || p[1] != 0 || p[2] != 0) {
- *outError = "Ticks in white frame must be black or red";
- return TickType::kNone;
- }
- return TickType::kTick;
-}
-
-enum class TickState { kStart, kInside1, kOutside1 };
-
-static bool getHorizontalTicks(png_bytep row, int width, bool transparent,
- bool required, int32_t* outLeft,
- int32_t* outRight, const char** outError,
- uint8_t* outDivs, bool multipleAllowed) {
- *outLeft = *outRight = -1;
- TickState state = TickState::kStart;
- bool found = false;
-
- for (int i = 1; i < width - 1; i++) {
- if (tickType(row + i * 4, transparent, outError) == TickType::kTick) {
- if (state == TickState::kStart ||
- (state == TickState::kOutside1 && multipleAllowed)) {
- *outLeft = i - 1;
- *outRight = width - 2;
- found = true;
- if (outDivs != NULL) {
- *outDivs += 2;
- }
- state = TickState::kInside1;
- } else if (state == TickState::kOutside1) {
- *outError = "Can't have more than one marked region along edge";
- *outLeft = i;
- return false;
- }
- } else if (!*outError) {
- if (state == TickState::kInside1) {
- // We're done with this div. Move on to the next.
- *outRight = i - 1;
- outRight += 2;
- outLeft += 2;
- state = TickState::kOutside1;
- }
- } else {
- *outLeft = i;
- return false;
- }
- }
-
- if (required && !found) {
- *outError = "No marked region found along edge";
- *outLeft = -1;
- return false;
- }
- return true;
-}
-
-static bool getVerticalTicks(png_bytepp rows, int offset, int height,
- bool transparent, bool required, int32_t* outTop,
- int32_t* outBottom, const char** outError,
- uint8_t* outDivs, bool multipleAllowed) {
- *outTop = *outBottom = -1;
- TickState state = TickState::kStart;
- bool found = false;
-
- for (int i = 1; i < height - 1; i++) {
- if (tickType(rows[i] + offset, transparent, outError) == TickType::kTick) {
- if (state == TickState::kStart ||
- (state == TickState::kOutside1 && multipleAllowed)) {
- *outTop = i - 1;
- *outBottom = height - 2;
- found = true;
- if (outDivs != NULL) {
- *outDivs += 2;
- }
- state = TickState::kInside1;
- } else if (state == TickState::kOutside1) {
- *outError = "Can't have more than one marked region along edge";
- *outTop = i;
- return false;
- }
- } else if (!*outError) {
- if (state == TickState::kInside1) {
- // We're done with this div. Move on to the next.
- *outBottom = i - 1;
- outTop += 2;
- outBottom += 2;
- state = TickState::kOutside1;
- }
- } else {
- *outTop = i;
- return false;
- }
- }
-
- if (required && !found) {
- *outError = "No marked region found along edge";
- *outTop = -1;
- return false;
- }
- return true;
-}
-
-static bool getHorizontalLayoutBoundsTicks(png_bytep row, int width,
- bool transparent,
- bool /* required */,
- int32_t* outLeft, int32_t* outRight,
- const char** outError) {
- *outLeft = *outRight = 0;
-
- // Look for left tick
- if (tickType(row + 4, transparent, outError) == TickType::kLayoutBounds) {
- // Starting with a layout padding tick
- int i = 1;
- while (i < width - 1) {
- (*outLeft)++;
- i++;
- if (tickType(row + i * 4, transparent, outError) !=
- TickType::kLayoutBounds) {
- break;
- }
- }
- }
-
- // Look for right tick
- if (tickType(row + (width - 2) * 4, transparent, outError) ==
- TickType::kLayoutBounds) {
- // Ending with a layout padding tick
- int i = width - 2;
- while (i > 1) {
- (*outRight)++;
- i--;
- if (tickType(row + i * 4, transparent, outError) !=
- TickType::kLayoutBounds) {
- break;
- }
- }
- }
- return true;
-}
-
-static bool getVerticalLayoutBoundsTicks(png_bytepp rows, int offset,
- int height, bool transparent,
- bool /* required */, int32_t* outTop,
- int32_t* outBottom,
- const char** outError) {
- *outTop = *outBottom = 0;
-
- // Look for top tick
- if (tickType(rows[1] + offset, transparent, outError) ==
- TickType::kLayoutBounds) {
- // Starting with a layout padding tick
- int i = 1;
- while (i < height - 1) {
- (*outTop)++;
- i++;
- if (tickType(rows[i] + offset, transparent, outError) !=
- TickType::kLayoutBounds) {
- break;
- }
- }
- }
-
- // Look for bottom tick
- if (tickType(rows[height - 2] + offset, transparent, outError) ==
- TickType::kLayoutBounds) {
- // Ending with a layout padding tick
- int i = height - 2;
- while (i > 1) {
- (*outBottom)++;
- i--;
- if (tickType(rows[i] + offset, transparent, outError) !=
- TickType::kLayoutBounds) {
- break;
- }
- }
- }
- return true;
-}
-
-static void findMaxOpacity(png_bytepp rows, int startX, int startY, int endX,
- int endY, int dX, int dY, int* outInset) {
- uint8_t maxOpacity = 0;
- int inset = 0;
- *outInset = 0;
- for (int x = startX, y = startY; x != endX && y != endY;
- x += dX, y += dY, inset++) {
- png_byte* color = rows[y] + x * 4;
- uint8_t opacity = color[3];
- if (opacity > maxOpacity) {
- maxOpacity = opacity;
- *outInset = inset;
- }
- if (opacity == 0xff) return;
- }
-}
-
-static uint8_t maxAlphaOverRow(png_bytep row, int startX, int endX) {
- uint8_t maxAlpha = 0;
- for (int x = startX; x < endX; x++) {
- uint8_t alpha = (row + x * 4)[3];
- if (alpha > maxAlpha) maxAlpha = alpha;
- }
- return maxAlpha;
-}
-
-static uint8_t maxAlphaOverCol(png_bytepp rows, int offsetX, int startY,
- int endY) {
- uint8_t maxAlpha = 0;
- for (int y = startY; y < endY; y++) {
- uint8_t alpha = (rows[y] + offsetX * 4)[3];
- if (alpha > maxAlpha) maxAlpha = alpha;
- }
- return maxAlpha;
-}
-
-static void getOutline(PngInfo* image) {
- int midX = image->width / 2;
- int midY = image->height / 2;
- int endX = image->width - 2;
- int endY = image->height - 2;
-
- // find left and right extent of nine patch content on center row
- if (image->width > 4) {
- findMaxOpacity(image->rows.data(), 1, midY, midX, -1, 1, 0,
- &image->outlineInsetsLeft);
- findMaxOpacity(image->rows.data(), endX, midY, midX, -1, -1, 0,
- &image->outlineInsetsRight);
- } else {
- image->outlineInsetsLeft = 0;
- image->outlineInsetsRight = 0;
- }
-
- // find top and bottom extent of nine patch content on center column
- if (image->height > 4) {
- findMaxOpacity(image->rows.data(), midX, 1, -1, midY, 0, 1,
- &image->outlineInsetsTop);
- findMaxOpacity(image->rows.data(), midX, endY, -1, midY, 0, -1,
- &image->outlineInsetsBottom);
- } else {
- image->outlineInsetsTop = 0;
- image->outlineInsetsBottom = 0;
- }
-
- int innerStartX = 1 + image->outlineInsetsLeft;
- int innerStartY = 1 + image->outlineInsetsTop;
- int innerEndX = endX - image->outlineInsetsRight;
- int innerEndY = endY - image->outlineInsetsBottom;
- int innerMidX = (innerEndX + innerStartX) / 2;
- int innerMidY = (innerEndY + innerStartY) / 2;
-
- // assuming the image is a round rect, compute the radius by marching
- // diagonally from the top left corner towards the center
- image->outlineAlpha = std::max(
- maxAlphaOverRow(image->rows[innerMidY], innerStartX, innerEndX),
- maxAlphaOverCol(image->rows.data(), innerMidX, innerStartY, innerStartY));
-
- int diagonalInset = 0;
- findMaxOpacity(image->rows.data(), innerStartX, innerStartY, innerMidX,
- innerMidY, 1, 1, &diagonalInset);
-
- /* Determine source radius based upon inset:
- * sqrt(r^2 + r^2) = sqrt(i^2 + i^2) + r
- * sqrt(2) * r = sqrt(2) * i + r
- * (sqrt(2) - 1) * r = sqrt(2) * i
- * r = sqrt(2) / (sqrt(2) - 1) * i
- */
- image->outlineRadius = 3.4142f * diagonalInset;
-
- if (kDebug) {
- printf("outline insets %d %d %d %d, rad %f, alpha %x\n",
- image->outlineInsetsLeft, image->outlineInsetsTop,
- image->outlineInsetsRight, image->outlineInsetsBottom,
- image->outlineRadius, image->outlineAlpha);
- }
-}
-
-static uint32_t getColor(png_bytepp rows, int left, int top, int right,
- int bottom) {
- png_bytep color = rows[top] + left * 4;
-
- if (left > right || top > bottom) {
- return android::Res_png_9patch::TRANSPARENT_COLOR;
- }
-
- while (top <= bottom) {
- for (int i = left; i <= right; i++) {
- png_bytep p = rows[top] + i * 4;
- if (color[3] == 0) {
- if (p[3] != 0) {
- return android::Res_png_9patch::NO_COLOR;
- }
- } else if (p[0] != color[0] || p[1] != color[1] || p[2] != color[2] ||
- p[3] != color[3]) {
- return android::Res_png_9patch::NO_COLOR;
- }
- }
- top++;
- }
-
- if (color[3] == 0) {
- return android::Res_png_9patch::TRANSPARENT_COLOR;
- }
- return (color[3] << 24) | (color[0] << 16) | (color[1] << 8) | color[2];
-}
-
-static bool do9Patch(PngInfo* image, std::string* outError) {
- image->is9Patch = true;
-
- int W = image->width;
- int H = image->height;
- int i, j;
-
- const int maxSizeXDivs = W * sizeof(int32_t);
- const int maxSizeYDivs = H * sizeof(int32_t);
- int32_t* xDivs = image->xDivs = new int32_t[W];
- int32_t* yDivs = image->yDivs = new int32_t[H];
- uint8_t numXDivs = 0;
- uint8_t numYDivs = 0;
-
- int8_t numColors;
- int numRows;
- int numCols;
- int top;
- int left;
- int right;
- int bottom;
- memset(xDivs, -1, maxSizeXDivs);
- memset(yDivs, -1, maxSizeYDivs);
- image->info9Patch.paddingLeft = image->info9Patch.paddingRight = -1;
- image->info9Patch.paddingTop = image->info9Patch.paddingBottom = -1;
- image->layoutBoundsLeft = image->layoutBoundsRight = 0;
- image->layoutBoundsTop = image->layoutBoundsBottom = 0;
-
- png_bytep p = image->rows[0];
- bool transparent = p[3] == 0;
- bool hasColor = false;
-
- const char* errorMsg = nullptr;
- int errorPixel = -1;
- const char* errorEdge = nullptr;
-
- int colorIndex = 0;
- std::vector<png_bytep> newRows;
-
- // Validate size...
- if (W < 3 || H < 3) {
- errorMsg = "Image must be at least 3x3 (1x1 without frame) pixels";
- goto getout;
- }
-
- // Validate frame...
- if (!transparent &&
- (p[0] != 0xFF || p[1] != 0xFF || p[2] != 0xFF || p[3] != 0xFF)) {
- errorMsg = "Must have one-pixel frame that is either transparent or white";
- goto getout;
- }
-
- // Find left and right of sizing areas...
- if (!getHorizontalTicks(p, W, transparent, true, &xDivs[0], &xDivs[1],
- &errorMsg, &numXDivs, true)) {
- errorPixel = xDivs[0];
- errorEdge = "top";
- goto getout;
- }
-
- // Find top and bottom of sizing areas...
- if (!getVerticalTicks(image->rows.data(), 0, H, transparent, true, &yDivs[0],
- &yDivs[1], &errorMsg, &numYDivs, true)) {
- errorPixel = yDivs[0];
- errorEdge = "left";
- goto getout;
- }
-
- // Copy patch size data into image...
- image->info9Patch.numXDivs = numXDivs;
- image->info9Patch.numYDivs = numYDivs;
-
- // Find left and right of padding area...
- if (!getHorizontalTicks(image->rows[H - 1], W, transparent, false,
- &image->info9Patch.paddingLeft,
- &image->info9Patch.paddingRight, &errorMsg, nullptr,
- false)) {
- errorPixel = image->info9Patch.paddingLeft;
- errorEdge = "bottom";
- goto getout;
- }
-
- // Find top and bottom of padding area...
- if (!getVerticalTicks(image->rows.data(), (W - 1) * 4, H, transparent, false,
- &image->info9Patch.paddingTop,
- &image->info9Patch.paddingBottom, &errorMsg, nullptr,
- false)) {
- errorPixel = image->info9Patch.paddingTop;
- errorEdge = "right";
- goto getout;
- }
-
- // Find left and right of layout padding...
- getHorizontalLayoutBoundsTicks(image->rows[H - 1], W, transparent, false,
- &image->layoutBoundsLeft,
- &image->layoutBoundsRight, &errorMsg);
-
- getVerticalLayoutBoundsTicks(image->rows.data(), (W - 1) * 4, H, transparent,
- false, &image->layoutBoundsTop,
- &image->layoutBoundsBottom, &errorMsg);
-
- image->haveLayoutBounds =
- image->layoutBoundsLeft != 0 || image->layoutBoundsRight != 0 ||
- image->layoutBoundsTop != 0 || image->layoutBoundsBottom != 0;
-
- if (image->haveLayoutBounds) {
- if (kDebug) {
- printf("layoutBounds=%d %d %d %d\n", image->layoutBoundsLeft,
- image->layoutBoundsTop, image->layoutBoundsRight,
- image->layoutBoundsBottom);
- }
- }
-
- // use opacity of pixels to estimate the round rect outline
- getOutline(image);
-
- // If padding is not yet specified, take values from size.
- if (image->info9Patch.paddingLeft < 0) {
- image->info9Patch.paddingLeft = xDivs[0];
- image->info9Patch.paddingRight = W - 2 - xDivs[1];
- } else {
- // Adjust value to be correct!
- image->info9Patch.paddingRight = W - 2 - image->info9Patch.paddingRight;
- }
- if (image->info9Patch.paddingTop < 0) {
- image->info9Patch.paddingTop = yDivs[0];
- image->info9Patch.paddingBottom = H - 2 - yDivs[1];
- } else {
- // Adjust value to be correct!
- image->info9Patch.paddingBottom = H - 2 - image->info9Patch.paddingBottom;
- }
-
- /* if (kDebug) {
- printf("Size ticks for %s: x0=%d, x1=%d, y0=%d, y1=%d\n", imageName,
- xDivs[0], xDivs[1],
- yDivs[0], yDivs[1]);
- printf("padding ticks for %s: l=%d, r=%d, t=%d, b=%d\n", imageName,
- image->info9Patch.paddingLeft, image->info9Patch.paddingRight,
- image->info9Patch.paddingTop,
- image->info9Patch.paddingBottom);
- }*/
-
- // Remove frame from image.
- newRows.resize(H - 2);
- for (i = 0; i < H - 2; i++) {
- newRows[i] = image->rows[i + 1];
- memmove(newRows[i], newRows[i] + 4, (W - 2) * 4);
- }
- image->rows.swap(newRows);
-
- image->width -= 2;
- W = image->width;
- image->height -= 2;
- H = image->height;
-
- // Figure out the number of rows and columns in the N-patch
- numCols = numXDivs + 1;
- if (xDivs[0] == 0) { // Column 1 is strechable
- numCols--;
- }
- if (xDivs[numXDivs - 1] == W) {
- numCols--;
- }
- numRows = numYDivs + 1;
- if (yDivs[0] == 0) { // Row 1 is strechable
- numRows--;
- }
- if (yDivs[numYDivs - 1] == H) {
- numRows--;
- }
-
- // Make sure the amount of rows and columns will fit in the number of
- // colors we can use in the 9-patch format.
- if (numRows * numCols > 0x7F) {
- errorMsg = "Too many rows and columns in 9-patch perimeter";
- goto getout;
- }
-
- numColors = numRows * numCols;
- image->info9Patch.numColors = numColors;
- image->colors.resize(numColors);
-
- // Fill in color information for each patch.
-
- uint32_t c;
- top = 0;
-
- // The first row always starts with the top being at y=0 and the bottom
- // being either yDivs[1] (if yDivs[0]=0) of yDivs[0]. In the former case
- // the first row is stretchable along the Y axis, otherwise it is fixed.
- // The last row always ends with the bottom being bitmap.height and the top
- // being either yDivs[numYDivs-2] (if yDivs[numYDivs-1]=bitmap.height) or
- // yDivs[numYDivs-1]. In the former case the last row is stretchable along
- // the Y axis, otherwise it is fixed.
- //
- // The first and last columns are similarly treated with respect to the X
- // axis.
- //
- // The above is to help explain some of the special casing that goes on the
- // code below.
-
- // The initial yDiv and whether the first row is considered stretchable or
- // not depends on whether yDiv[0] was zero or not.
- for (j = (yDivs[0] == 0 ? 1 : 0); j <= numYDivs && top < H; j++) {
- if (j == numYDivs) {
- bottom = H;
- } else {
- bottom = yDivs[j];
- }
- left = 0;
- // The initial xDiv and whether the first column is considered
- // stretchable or not depends on whether xDiv[0] was zero or not.
- for (i = xDivs[0] == 0 ? 1 : 0; i <= numXDivs && left < W; i++) {
- if (i == numXDivs) {
- right = W;
- } else {
- right = xDivs[i];
- }
- c = getColor(image->rows.data(), left, top, right - 1, bottom - 1);
- image->colors[colorIndex++] = c;
- if (kDebug) {
- if (c != android::Res_png_9patch::NO_COLOR) {
- hasColor = true;
- }
- }
- left = right;
- }
- top = bottom;
- }
-
- assert(colorIndex == numColors);
-
- if (kDebug && hasColor) {
- for (i = 0; i < numColors; i++) {
- if (i == 0) printf("Colors:\n");
- printf(" #%08x", image->colors[i]);
- if (i == numColors - 1) printf("\n");
- }
- }
-getout:
- if (errorMsg) {
- std::stringstream err;
- err << "9-patch malformed: " << errorMsg;
- if (errorEdge) {
- err << "." << std::endl;
- if (errorPixel >= 0) {
- err << "Found at pixel #" << errorPixel << " along " << errorEdge
- << " edge";
- } else {
- err << "Found along " << errorEdge << " edge";
- }
- }
- *outError = err.str();
- return false;
- }
- return true;
-}
-
-bool Png::process(const android::Source& source, std::istream* input, android::BigBuffer* outBuffer,
- const PngOptions& options) {
- TRACE_CALL();
- png_byte signature[kPngSignatureSize];
-
- // Read the PNG signature first.
- if (!input->read(reinterpret_cast<char*>(signature), kPngSignatureSize)) {
- mDiag->Error(android::DiagMessage() << strerror(errno));
- return false;
- }
-
- // If the PNG signature doesn't match, bail early.
- if (png_sig_cmp(signature, 0, kPngSignatureSize) != 0) {
- mDiag->Error(android::DiagMessage() << "not a valid png file");
- return false;
- }
-
- bool result = false;
- png_structp readPtr = nullptr;
- png_infop infoPtr = nullptr;
- png_structp writePtr = nullptr;
- png_infop writeInfoPtr = nullptr;
- PngInfo pngInfo = {};
-
- readPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, nullptr, nullptr);
- if (!readPtr) {
- mDiag->Error(android::DiagMessage() << "failed to allocate read ptr");
- goto bail;
- }
-
- infoPtr = png_create_info_struct(readPtr);
- if (!infoPtr) {
- mDiag->Error(android::DiagMessage() << "failed to allocate info ptr");
- goto bail;
- }
-
- png_set_error_fn(readPtr, reinterpret_cast<png_voidp>(mDiag), nullptr,
- logWarning);
-
- // Set the read function to read from std::istream.
- png_set_read_fn(readPtr, (png_voidp)input, readDataFromStream);
-
- if (!readPng(mDiag, readPtr, infoPtr, &pngInfo)) {
- goto bail;
- }
-
- if (util::EndsWith(source.path, ".9.png")) {
- std::string errorMsg;
- if (!do9Patch(&pngInfo, &errorMsg)) {
- mDiag->Error(android::DiagMessage() << errorMsg);
- goto bail;
- }
- }
-
- writePtr =
- png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, nullptr, nullptr);
- if (!writePtr) {
- mDiag->Error(android::DiagMessage() << "failed to allocate write ptr");
- goto bail;
- }
-
- writeInfoPtr = png_create_info_struct(writePtr);
- if (!writeInfoPtr) {
- mDiag->Error(android::DiagMessage() << "failed to allocate write info ptr");
- goto bail;
- }
-
- png_set_error_fn(writePtr, nullptr, nullptr, logWarning);
-
- // Set the write function to write to std::ostream.
- png_set_write_fn(writePtr, (png_voidp)outBuffer, writeDataToStream,
- flushDataToStream);
-
- if (!writePng(mDiag, writePtr, writeInfoPtr, &pngInfo,
- options.grayscale_tolerance)) {
- goto bail;
- }
-
- result = true;
-bail:
- if (readPtr) {
- png_destroy_read_struct(&readPtr, &infoPtr, nullptr);
- }
-
- if (writePtr) {
- png_destroy_write_struct(&writePtr, &writeInfoPtr);
- }
- return result;
-}
-
-} // namespace aapt
diff --git a/tools/aapt2/compile/Png.h b/tools/aapt2/compile/Png.h
deleted file mode 100644
index a8b7dd1..0000000
--- a/tools/aapt2/compile/Png.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_PNG_H
-#define AAPT_PNG_H
-
-#include <iostream>
-#include <string>
-
-#include "android-base/macros.h"
-#include "androidfw/BigBuffer.h"
-#include "androidfw/IDiagnostics.h"
-#include "androidfw/Source.h"
-#include "compile/Image.h"
-#include "io/Io.h"
-#include "process/IResourceTableConsumer.h"
-
-namespace aapt {
-
-// Size in bytes of the PNG signature.
-constexpr size_t kPngSignatureSize = 8u;
-
-struct PngOptions {
- int grayscale_tolerance = 0;
-};
-
-/**
- * Deprecated. Removing once new PNG crunching code is proved to be correct.
- */
-class Png {
- public:
- explicit Png(android::IDiagnostics* diag) : mDiag(diag) {
- }
-
- bool process(const android::Source& source, std::istream* input, android::BigBuffer* outBuffer,
- const PngOptions& options);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Png);
-
- android::IDiagnostics* mDiag;
-};
-
-/**
- * An InputStream that filters out unimportant PNG chunks.
- */
-class PngChunkFilter : public io::InputStream {
- public:
- explicit PngChunkFilter(android::StringPiece data);
- virtual ~PngChunkFilter() = default;
-
- bool Next(const void** buffer, size_t* len) override;
- void BackUp(size_t count) override;
-
- bool CanRewind() const override { return true; }
- bool Rewind() override;
- size_t ByteCount() const override { return window_start_; }
-
- bool HadError() const override {
- return !error_msg_.empty();
- }
- std::string GetError() const override {
- return error_msg_;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PngChunkFilter);
-
- bool ConsumeWindow(const void** buffer, size_t* len);
-
- android::StringPiece data_;
- size_t window_start_ = 0;
- size_t window_end_ = 0;
- std::string error_msg_;
-};
-
-/**
- * Reads a PNG from the InputStream into memory as an RGBA Image.
- */
-std::unique_ptr<Image> ReadPng(IAaptContext* context, const android::Source& source,
- io::InputStream* in);
-
-/**
- * Writes the RGBA Image, with optional 9-patch meta-data, into the OutputStream
- * as a PNG.
- */
-bool WritePng(IAaptContext* context, const Image* image,
- const NinePatch* nine_patch, io::OutputStream* out,
- const PngOptions& options);
-
-} // namespace aapt
-
-#endif // AAPT_PNG_H
diff --git a/tools/aapt2/compile/PngChunkFilter.cpp b/tools/aapt2/compile/PngChunkFilter.cpp
deleted file mode 100644
index 2e55d0c..0000000
--- a/tools/aapt2/compile/PngChunkFilter.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "compile/Png.h"
-
-#include "android-base/stringprintf.h"
-#include "androidfw/StringPiece.h"
-
-#include "io/Io.h"
-
-using ::android::StringPiece;
-using ::android::base::StringPrintf;
-
-namespace aapt {
-
-static constexpr const char* kPngSignature = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a";
-
-// Useful helper function that encodes individual bytes into a uint32
-// at compile time.
-constexpr uint32_t u32(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
- return (((uint32_t)a) << 24) | (((uint32_t)b) << 16) | (((uint32_t)c) << 8) |
- ((uint32_t)d);
-}
-
-// Allow list of PNG chunk types that we want to keep in the resulting PNG.
-enum PngChunkTypes {
- kPngChunkIHDR = u32(73, 72, 68, 82),
- kPngChunkIDAT = u32(73, 68, 65, 84),
- kPngChunkIEND = u32(73, 69, 78, 68),
- kPngChunkPLTE = u32(80, 76, 84, 69),
- kPngChunktRNS = u32(116, 82, 78, 83),
- kPngChunksRGB = u32(115, 82, 71, 66),
-};
-
-static uint32_t Peek32LE(const char* data) {
- uint32_t word = ((uint32_t)data[0]) & 0x000000ff;
- word <<= 8;
- word |= ((uint32_t)data[1]) & 0x000000ff;
- word <<= 8;
- word |= ((uint32_t)data[2]) & 0x000000ff;
- word <<= 8;
- word |= ((uint32_t)data[3]) & 0x000000ff;
- return word;
-}
-
-static bool IsPngChunkAllowed(uint32_t type) {
- switch (type) {
- case kPngChunkIHDR:
- case kPngChunkIDAT:
- case kPngChunkIEND:
- case kPngChunkPLTE:
- case kPngChunktRNS:
- case kPngChunksRGB:
- return true;
- default:
- return false;
- }
-}
-
-PngChunkFilter::PngChunkFilter(StringPiece data) : data_(data) {
- if (util::StartsWith(data_, kPngSignature)) {
- window_start_ = 0;
- window_end_ = kPngSignatureSize;
- } else {
- error_msg_ = "file does not start with PNG signature";
- }
-}
-
-bool PngChunkFilter::ConsumeWindow(const void** buffer, size_t* len) {
- if (window_start_ != window_end_) {
- // We have bytes to give from our window.
- const size_t bytes_read = window_end_ - window_start_;
- *buffer = data_.data() + window_start_;
- *len = bytes_read;
- window_start_ = window_end_;
- return true;
- }
- return false;
-}
-
-bool PngChunkFilter::Next(const void** buffer, size_t* len) {
- if (HadError()) {
- return false;
- }
-
- // In case BackUp was called, we must consume the window.
- if (ConsumeWindow(buffer, len)) {
- return true;
- }
-
- // Advance the window as far as possible (until we meet a chunk that
- // we want to strip).
- while (window_end_ < data_.size()) {
- // Chunk length (4 bytes) + type (4 bytes) + crc32 (4 bytes) = 12 bytes.
- const size_t kMinChunkHeaderSize = 3 * sizeof(uint32_t);
-
- // Is there enough room for a chunk header?
- if (data_.size() - window_end_ < kMinChunkHeaderSize) {
- error_msg_ = StringPrintf("Not enough space for a PNG chunk @ byte %zu/%zu", window_end_,
- data_.size());
- return false;
- }
-
- // Verify the chunk length.
- const uint32_t chunk_len = Peek32LE(data_.data() + window_end_);
- if ((size_t)chunk_len > data_.size() - window_end_ - kMinChunkHeaderSize) {
- // Overflow.
- const uint32_t chunk_type = Peek32LE(data_.data() + window_end_ + sizeof(uint32_t));
- error_msg_ = StringPrintf(
- "PNG chunk type %08x is too large: chunk length is %zu but chunk "
- "starts at byte %zu/%zu",
- chunk_type, (size_t)chunk_len, window_end_ + kMinChunkHeaderSize, data_.size());
- return false;
- }
-
- // Do we strip this chunk?
- const uint32_t chunk_type = Peek32LE(data_.data() + window_end_ + sizeof(uint32_t));
- if (IsPngChunkAllowed(chunk_type)) {
- // Advance the window to include this chunk.
- window_end_ += kMinChunkHeaderSize + chunk_len;
-
- // Special case the IEND chunk, which MUST appear last and libpng stops parsing once it hits
- // such a chunk (let's do the same).
- if (chunk_type == kPngChunkIEND) {
- // Truncate the data to the end of this chunk. There may be garbage trailing after
- // (b/38169876)
- data_ = data_.substr(0, window_end_);
- break;
- }
-
- } else {
- // We want to strip this chunk. If we accumulated a window,
- // we must return the window now.
- if (window_start_ != window_end_) {
- break;
- }
-
- // The window is empty, so we can advance past this chunk
- // and keep looking for the next good chunk,
- window_end_ += kMinChunkHeaderSize + chunk_len;
- window_start_ = window_end_;
- }
- }
-
- if (ConsumeWindow(buffer, len)) {
- return true;
- }
- return false;
-}
-
-void PngChunkFilter::BackUp(size_t count) {
- if (HadError()) {
- return;
- }
- window_start_ -= count;
-}
-
-bool PngChunkFilter::Rewind() {
- if (HadError()) {
- return false;
- }
- window_start_ = 0;
- window_end_ = kPngSignatureSize;
- return true;
-}
-
-} // namespace aapt
diff --git a/tools/aapt2/compile/PngCrunch.cpp b/tools/aapt2/compile/PngCrunch.cpp
deleted file mode 100644
index 4ef87ba..0000000
--- a/tools/aapt2/compile/PngCrunch.cpp
+++ /dev/null
@@ -1,750 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "compile/Png.h"
-
-#include <png.h>
-#include <zlib.h>
-
-#include <algorithm>
-#include <unordered_map>
-#include <unordered_set>
-
-#include "android-base/errors.h"
-#include "android-base/logging.h"
-#include "android-base/macros.h"
-
-#include "trace/TraceBuffer.h"
-
-namespace aapt {
-
-// Custom deleter that destroys libpng read and info structs.
-class PngReadStructDeleter {
- public:
- PngReadStructDeleter(png_structp read_ptr, png_infop info_ptr)
- : read_ptr_(read_ptr), info_ptr_(info_ptr) {}
-
- ~PngReadStructDeleter() {
- png_destroy_read_struct(&read_ptr_, &info_ptr_, nullptr);
- }
-
- private:
- png_structp read_ptr_;
- png_infop info_ptr_;
-
- DISALLOW_COPY_AND_ASSIGN(PngReadStructDeleter);
-};
-
-// Custom deleter that destroys libpng write and info structs.
-class PngWriteStructDeleter {
- public:
- PngWriteStructDeleter(png_structp write_ptr, png_infop info_ptr)
- : write_ptr_(write_ptr), info_ptr_(info_ptr) {}
-
- ~PngWriteStructDeleter() {
- png_destroy_write_struct(&write_ptr_, &info_ptr_);
- }
-
- private:
- png_structp write_ptr_;
- png_infop info_ptr_;
-
- DISALLOW_COPY_AND_ASSIGN(PngWriteStructDeleter);
-};
-
-// Custom warning logging method that uses IDiagnostics.
-static void LogWarning(png_structp png_ptr, png_const_charp warning_msg) {
- android::IDiagnostics* diag = (android::IDiagnostics*)png_get_error_ptr(png_ptr);
- diag->Warn(android::DiagMessage() << warning_msg);
-}
-
-// Custom error logging method that uses IDiagnostics.
-static void LogError(png_structp png_ptr, png_const_charp error_msg) {
- android::IDiagnostics* diag = (android::IDiagnostics*)png_get_error_ptr(png_ptr);
- diag->Error(android::DiagMessage() << error_msg);
-
- // Causes libpng to longjmp to the spot where setjmp was set. This is how libpng does
- // error handling. If this custom error handler method were to return, libpng would, by
- // default, print the error message to stdout and call the same png_longjmp method.
- png_longjmp(png_ptr, 1);
-}
-
-static void ReadDataFromStream(png_structp png_ptr, png_bytep buffer, png_size_t len) {
- io::InputStream* in = (io::InputStream*)png_get_io_ptr(png_ptr);
-
- const void* in_buffer;
- size_t in_len;
- if (!in->Next(&in_buffer, &in_len)) {
- if (in->HadError()) {
- std::stringstream error_msg_builder;
- error_msg_builder << "failed reading from input";
- if (!in->GetError().empty()) {
- error_msg_builder << ": " << in->GetError();
- }
- std::string err = error_msg_builder.str();
- png_error(png_ptr, err.c_str());
- }
- return;
- }
-
- const size_t bytes_read = std::min(in_len, len);
- memcpy(buffer, in_buffer, bytes_read);
- if (bytes_read != in_len) {
- in->BackUp(in_len - bytes_read);
- }
-}
-
-static void WriteDataToStream(png_structp png_ptr, png_bytep buffer, png_size_t len) {
- io::OutputStream* out = (io::OutputStream*)png_get_io_ptr(png_ptr);
-
- void* out_buffer;
- size_t out_len;
- while (len > 0) {
- if (!out->Next(&out_buffer, &out_len)) {
- if (out->HadError()) {
- std::stringstream err_msg_builder;
- err_msg_builder << "failed writing to output";
- if (!out->GetError().empty()) {
- err_msg_builder << ": " << out->GetError();
- }
- std::string err = out->GetError();
- png_error(png_ptr, err.c_str());
- }
- return;
- }
-
- const size_t bytes_written = std::min(out_len, len);
- memcpy(out_buffer, buffer, bytes_written);
-
- // Advance the input buffer.
- buffer += bytes_written;
- len -= bytes_written;
-
- // Advance the output buffer.
- out_len -= bytes_written;
- }
-
- // If the entire output buffer wasn't used, backup.
- if (out_len > 0) {
- out->BackUp(out_len);
- }
-}
-
-std::unique_ptr<Image> ReadPng(IAaptContext* context, const android::Source& source,
- io::InputStream* in) {
- TRACE_CALL();
- // Create a diagnostics that has the source information encoded.
- android::SourcePathDiagnostics source_diag(source, context->GetDiagnostics());
-
- // Read the first 8 bytes of the file looking for the PNG signature.
- // Bail early if it does not match.
- const png_byte* signature;
- size_t buffer_size;
- if (!in->Next((const void**)&signature, &buffer_size)) {
- if (in->HadError()) {
- source_diag.Error(android::DiagMessage()
- << "failed to read PNG signature: " << in->GetError());
- } else {
- source_diag.Error(android::DiagMessage() << "not enough data for PNG signature");
- }
- return {};
- }
-
- if (buffer_size < kPngSignatureSize || png_sig_cmp(signature, 0, kPngSignatureSize) != 0) {
- source_diag.Error(android::DiagMessage() << "file signature does not match PNG signature");
- return {};
- }
-
- // Start at the beginning of the first chunk.
- in->BackUp(buffer_size - kPngSignatureSize);
-
- // Create and initialize the png_struct with the default error and warning handlers.
- // The header version is also passed in to ensure that this was built against the same
- // version of libpng.
- png_structp read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
- if (read_ptr == nullptr) {
- source_diag.Error(android::DiagMessage() << "failed to create libpng read png_struct");
- return {};
- }
-
- // Create and initialize the memory for image header and data.
- png_infop info_ptr = png_create_info_struct(read_ptr);
- if (info_ptr == nullptr) {
- source_diag.Error(android::DiagMessage() << "failed to create libpng read png_info");
- png_destroy_read_struct(&read_ptr, nullptr, nullptr);
- return {};
- }
-
- // Automatically release PNG resources at end of scope.
- PngReadStructDeleter png_read_deleter(read_ptr, info_ptr);
-
- // libpng uses longjmp to jump to an error handling routine.
- // setjmp will only return true if it was jumped to, aka there was
- // an error.
- if (setjmp(png_jmpbuf(read_ptr))) {
- return {};
- }
-
- // Handle warnings ourselves via IDiagnostics.
- png_set_error_fn(read_ptr, (png_voidp)&source_diag, LogError, LogWarning);
-
- // Set up the read functions which read from our custom data sources.
- png_set_read_fn(read_ptr, (png_voidp)in, ReadDataFromStream);
-
- // Skip the signature that we already read.
- png_set_sig_bytes(read_ptr, kPngSignatureSize);
-
- // Read the chunk headers.
- png_read_info(read_ptr, info_ptr);
-
- // Extract image meta-data from the various chunk headers.
- uint32_t width, height;
- int bit_depth, color_type, interlace_method, compression_method, filter_method;
- png_get_IHDR(read_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
- &interlace_method, &compression_method, &filter_method);
-
- // When the image is read, expand it so that it is in RGBA 8888 format
- // so that image handling is uniform.
-
- if (color_type == PNG_COLOR_TYPE_PALETTE) {
- png_set_palette_to_rgb(read_ptr);
- }
-
- if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
- png_set_expand_gray_1_2_4_to_8(read_ptr);
- }
-
- if (png_get_valid(read_ptr, info_ptr, PNG_INFO_tRNS)) {
- png_set_tRNS_to_alpha(read_ptr);
- }
-
- if (bit_depth == 16) {
- png_set_strip_16(read_ptr);
- }
-
- if (!(color_type & PNG_COLOR_MASK_ALPHA)) {
- png_set_add_alpha(read_ptr, 0xFF, PNG_FILLER_AFTER);
- }
-
- if (color_type == PNG_COLOR_TYPE_GRAY ||
- color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
- png_set_gray_to_rgb(read_ptr);
- }
-
- if (interlace_method != PNG_INTERLACE_NONE) {
- png_set_interlace_handling(read_ptr);
- }
-
- // Once all the options for reading have been set, we need to flush
- // them to libpng.
- png_read_update_info(read_ptr, info_ptr);
-
- // 9-patch uses int32_t to index images, so we cap the image dimensions to
- // something
- // that can always be represented by 9-patch.
- if (width > std::numeric_limits<int32_t>::max() || height > std::numeric_limits<int32_t>::max()) {
- source_diag.Error(android::DiagMessage()
- << "PNG image dimensions are too large: " << width << "x" << height);
- return {};
- }
-
- std::unique_ptr<Image> output_image = util::make_unique<Image>();
- output_image->width = static_cast<int32_t>(width);
- output_image->height = static_cast<int32_t>(height);
-
- const size_t row_bytes = png_get_rowbytes(read_ptr, info_ptr);
- CHECK(row_bytes == 4 * width); // RGBA
-
- // Allocate one large block to hold the image.
- output_image->data = std::unique_ptr<uint8_t[]>(new uint8_t[height * row_bytes]);
-
- // Create an array of rows that index into the data block.
- output_image->rows = std::unique_ptr<uint8_t* []>(new uint8_t*[height]);
- for (uint32_t h = 0; h < height; h++) {
- output_image->rows[h] = output_image->data.get() + (h * row_bytes);
- }
-
- // Actually read the image pixels.
- png_read_image(read_ptr, output_image->rows.get());
-
- // Finish reading. This will read any other chunks after the image data.
- png_read_end(read_ptr, info_ptr);
-
- return output_image;
-}
-
-// Experimentally chosen constant to be added to the overhead of using color type
-// PNG_COLOR_TYPE_PALETTE to account for the uncompressability of the palette chunk.
-// Without this, many small PNGs encoded with palettes are larger after compression than
-// the same PNGs encoded as RGBA.
-constexpr static const size_t kPaletteOverheadConstant = 1024u * 10u;
-
-// Pick a color type by which to encode the image, based on which color type will take
-// the least amount of disk space.
-//
-// 9-patch images traditionally have not been encoded with palettes.
-// The original rationale was to avoid dithering until after scaling,
-// but I don't think this would be an issue with palettes. Either way,
-// our naive size estimation tends to be wrong for small images like 9-patches
-// and using palettes balloons the size of the resulting 9-patch.
-// In order to not regress in size, restrict 9-patch to not use palettes.
-
-// The options are:
-//
-// - RGB
-// - RGBA
-// - RGB + cheap alpha
-// - Color palette
-// - Color palette + cheap alpha
-// - Color palette + alpha palette
-// - Grayscale
-// - Grayscale + cheap alpha
-// - Grayscale + alpha
-//
-static int PickColorType(int32_t width, int32_t height, bool grayscale,
- bool convertible_to_grayscale, bool has_nine_patch,
- size_t color_palette_size, size_t alpha_palette_size) {
- const size_t palette_chunk_size = 16 + color_palette_size * 3;
- const size_t alpha_chunk_size = 16 + alpha_palette_size;
- const size_t color_alpha_data_chunk_size = 16 + 4 * width * height;
- const size_t color_data_chunk_size = 16 + 3 * width * height;
- const size_t grayscale_alpha_data_chunk_size = 16 + 2 * width * height;
- const size_t palette_data_chunk_size = 16 + width * height;
-
- if (grayscale) {
- if (alpha_palette_size == 0) {
- // This is the smallest the data can be.
- return PNG_COLOR_TYPE_GRAY;
- } else if (color_palette_size <= 256 && !has_nine_patch) {
- // This grayscale has alpha and can fit within a palette.
- // See if it is worth fitting into a palette.
- const size_t palette_threshold = palette_chunk_size + alpha_chunk_size +
- palette_data_chunk_size +
- kPaletteOverheadConstant;
- if (grayscale_alpha_data_chunk_size > palette_threshold) {
- return PNG_COLOR_TYPE_PALETTE;
- }
- }
- return PNG_COLOR_TYPE_GRAY_ALPHA;
- }
-
- if (color_palette_size <= 256 && !has_nine_patch) {
- // This image can fit inside a palette. Let's see if it is worth it.
- size_t total_size_with_palette =
- palette_data_chunk_size + palette_chunk_size;
- size_t total_size_without_palette = color_data_chunk_size;
- if (alpha_palette_size > 0) {
- total_size_with_palette += alpha_palette_size;
- total_size_without_palette = color_alpha_data_chunk_size;
- }
-
- if (total_size_without_palette >
- total_size_with_palette + kPaletteOverheadConstant) {
- return PNG_COLOR_TYPE_PALETTE;
- }
- }
-
- if (convertible_to_grayscale) {
- if (alpha_palette_size == 0) {
- return PNG_COLOR_TYPE_GRAY;
- } else {
- return PNG_COLOR_TYPE_GRAY_ALPHA;
- }
- }
-
- if (alpha_palette_size == 0) {
- return PNG_COLOR_TYPE_RGB;
- }
- return PNG_COLOR_TYPE_RGBA;
-}
-
-// Assigns indices to the color and alpha palettes, encodes them, and then invokes
-// png_set_PLTE/png_set_tRNS.
-// This must be done before writing image data.
-// Image data must be transformed to use the indices assigned within the palette.
-static void WritePalette(png_structp write_ptr, png_infop write_info_ptr,
- std::unordered_map<uint32_t, int>* color_palette,
- std::unordered_set<uint32_t>* alpha_palette) {
- CHECK(color_palette->size() <= 256);
- CHECK(alpha_palette->size() <= 256);
-
- // Populate the PNG palette struct and assign indices to the color palette.
-
- // Colors in the alpha palette should have smaller indices.
- // This will ensure that we can truncate the alpha palette if it is
- // smaller than the color palette.
- int index = 0;
- for (uint32_t color : *alpha_palette) {
- (*color_palette)[color] = index++;
- }
-
- // Assign the rest of the entries.
- for (auto& entry : *color_palette) {
- if (entry.second == -1) {
- entry.second = index++;
- }
- }
-
- // Create the PNG color palette struct.
- auto color_palette_bytes = std::unique_ptr<png_color[]>(new png_color[color_palette->size()]);
-
- std::unique_ptr<png_byte[]> alpha_palette_bytes;
- if (!alpha_palette->empty()) {
- alpha_palette_bytes = std::unique_ptr<png_byte[]>(new png_byte[alpha_palette->size()]);
- }
-
- for (const auto& entry : *color_palette) {
- const uint32_t color = entry.first;
- const int index = entry.second;
- CHECK(index >= 0);
- CHECK(static_cast<size_t>(index) < color_palette->size());
-
- png_colorp slot = color_palette_bytes.get() + index;
- slot->red = color >> 24;
- slot->green = color >> 16;
- slot->blue = color >> 8;
-
- const png_byte alpha = color & 0x000000ff;
- if (alpha != 0xff && alpha_palette_bytes) {
- CHECK(static_cast<size_t>(index) < alpha_palette->size());
- alpha_palette_bytes[index] = alpha;
- }
- }
-
- // The bytes get copied here, so it is safe to release color_palette_bytes at
- // the end of function
- // scope.
- png_set_PLTE(write_ptr, write_info_ptr, color_palette_bytes.get(), color_palette->size());
-
- if (alpha_palette_bytes) {
- png_set_tRNS(write_ptr, write_info_ptr, alpha_palette_bytes.get(), alpha_palette->size(),
- nullptr);
- }
-}
-
-// Write the 9-patch custom PNG chunks to write_info_ptr. This must be done
-// before writing image data.
-static void WriteNinePatch(png_structp write_ptr, png_infop write_info_ptr,
- const NinePatch* nine_patch) {
- // The order of the chunks is important.
- // 9-patch code in older platforms expects the 9-patch chunk to be last.
-
- png_unknown_chunk unknown_chunks[3];
- memset(unknown_chunks, 0, sizeof(unknown_chunks));
-
- size_t index = 0;
- size_t chunk_len = 0;
-
- std::unique_ptr<uint8_t[]> serialized_outline =
- nine_patch->SerializeRoundedRectOutline(&chunk_len);
- strcpy((char*)unknown_chunks[index].name, "npOl");
- unknown_chunks[index].size = chunk_len;
- unknown_chunks[index].data = (png_bytep)serialized_outline.get();
- unknown_chunks[index].location = PNG_HAVE_PLTE;
- index++;
-
- std::unique_ptr<uint8_t[]> serialized_layout_bounds;
- if (nine_patch->layout_bounds.nonZero()) {
- serialized_layout_bounds = nine_patch->SerializeLayoutBounds(&chunk_len);
- strcpy((char*)unknown_chunks[index].name, "npLb");
- unknown_chunks[index].size = chunk_len;
- unknown_chunks[index].data = (png_bytep)serialized_layout_bounds.get();
- unknown_chunks[index].location = PNG_HAVE_PLTE;
- index++;
- }
-
- std::unique_ptr<uint8_t[]> serialized_nine_patch = nine_patch->SerializeBase(&chunk_len);
- strcpy((char*)unknown_chunks[index].name, "npTc");
- unknown_chunks[index].size = chunk_len;
- unknown_chunks[index].data = (png_bytep)serialized_nine_patch.get();
- unknown_chunks[index].location = PNG_HAVE_PLTE;
- index++;
-
- // Handle all unknown chunks. We are manually setting the chunks here,
- // so we will only ever handle our custom chunks.
- png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS, nullptr, 0);
-
- // Set the actual chunks here. The data gets copied, so our buffers can
- // safely go out of scope.
- png_set_unknown_chunks(write_ptr, write_info_ptr, unknown_chunks, index);
-}
-
-bool WritePng(IAaptContext* context, const Image* image,
- const NinePatch* nine_patch, io::OutputStream* out,
- const PngOptions& options) {
- TRACE_CALL();
- // Create and initialize the write png_struct with the default error and
- // warning handlers.
- // The header version is also passed in to ensure that this was built against the same
- // version of libpng.
- png_structp write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
- if (write_ptr == nullptr) {
- context->GetDiagnostics()->Error(android::DiagMessage()
- << "failed to create libpng write png_struct");
- return false;
- }
-
- // Allocate memory to store image header data.
- png_infop write_info_ptr = png_create_info_struct(write_ptr);
- if (write_info_ptr == nullptr) {
- context->GetDiagnostics()->Error(android::DiagMessage()
- << "failed to create libpng write png_info");
- png_destroy_write_struct(&write_ptr, nullptr);
- return false;
- }
-
- // Automatically release PNG resources at end of scope.
- PngWriteStructDeleter png_write_deleter(write_ptr, write_info_ptr);
-
- // libpng uses longjmp to jump to error handling routines.
- // setjmp will return true only if it was jumped to, aka, there was an error.
- if (setjmp(png_jmpbuf(write_ptr))) {
- return false;
- }
-
- // Handle warnings with our IDiagnostics.
- png_set_error_fn(write_ptr, (png_voidp)context->GetDiagnostics(), LogError, LogWarning);
-
- // Set up the write functions which write to our custom data sources.
- png_set_write_fn(write_ptr, (png_voidp)out, WriteDataToStream, nullptr);
-
- // We want small files and can take the performance hit to achieve this goal.
- png_set_compression_level(write_ptr, Z_BEST_COMPRESSION);
-
- // Begin analysis of the image data.
- // Scan the entire image and determine if:
- // 1. Every pixel has R == G == B (grayscale)
- // 2. Every pixel has A == 255 (opaque)
- // 3. There are no more than 256 distinct RGBA colors (palette).
- std::unordered_map<uint32_t, int> color_palette;
- std::unordered_set<uint32_t> alpha_palette;
- bool needs_to_zero_rgb_channels_of_transparent_pixels = false;
- bool grayscale = true;
- int max_gray_deviation = 0;
-
- for (int32_t y = 0; y < image->height; y++) {
- const uint8_t* row = image->rows[y];
- for (int32_t x = 0; x < image->width; x++) {
- int red = *row++;
- int green = *row++;
- int blue = *row++;
- int alpha = *row++;
-
- if (alpha == 0) {
- // The color is completely transparent.
- // For purposes of palettes and grayscale optimization,
- // treat all channels as 0x00.
- needs_to_zero_rgb_channels_of_transparent_pixels =
- needs_to_zero_rgb_channels_of_transparent_pixels ||
- (red != 0 || green != 0 || blue != 0);
- red = green = blue = 0;
- }
-
- // Insert the color into the color palette.
- const uint32_t color = red << 24 | green << 16 | blue << 8 | alpha;
- color_palette[color] = -1;
-
- // If the pixel has non-opaque alpha, insert it into the
- // alpha palette.
- if (alpha != 0xff) {
- alpha_palette.insert(color);
- }
-
- // Check if the image is indeed grayscale.
- if (grayscale) {
- if (red != green || red != blue) {
- grayscale = false;
- }
- }
-
- // Calculate the gray scale deviation so that it can be compared
- // with the threshold.
- max_gray_deviation = std::max(std::abs(red - green), max_gray_deviation);
- max_gray_deviation = std::max(std::abs(green - blue), max_gray_deviation);
- max_gray_deviation = std::max(std::abs(blue - red), max_gray_deviation);
- }
- }
-
- if (context->IsVerbose()) {
- android::DiagMessage msg;
- msg << " paletteSize=" << color_palette.size()
- << " alphaPaletteSize=" << alpha_palette.size()
- << " maxGrayDeviation=" << max_gray_deviation
- << " grayScale=" << (grayscale ? "true" : "false");
- context->GetDiagnostics()->Note(msg);
- }
-
- const bool convertible_to_grayscale = max_gray_deviation <= options.grayscale_tolerance;
-
- const int new_color_type = PickColorType(
- image->width, image->height, grayscale, convertible_to_grayscale,
- nine_patch != nullptr, color_palette.size(), alpha_palette.size());
-
- if (context->IsVerbose()) {
- android::DiagMessage msg;
- msg << "encoding PNG ";
- if (nine_patch) {
- msg << "(with 9-patch) as ";
- }
- switch (new_color_type) {
- case PNG_COLOR_TYPE_GRAY:
- msg << "GRAY";
- break;
- case PNG_COLOR_TYPE_GRAY_ALPHA:
- msg << "GRAY + ALPHA";
- break;
- case PNG_COLOR_TYPE_RGB:
- msg << "RGB";
- break;
- case PNG_COLOR_TYPE_RGB_ALPHA:
- msg << "RGBA";
- break;
- case PNG_COLOR_TYPE_PALETTE:
- msg << "PALETTE";
- break;
- default:
- msg << "unknown type " << new_color_type;
- break;
- }
- context->GetDiagnostics()->Note(msg);
- }
-
- png_set_IHDR(write_ptr, write_info_ptr, image->width, image->height, 8,
- new_color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
- PNG_FILTER_TYPE_DEFAULT);
-
- if (new_color_type & PNG_COLOR_MASK_PALETTE) {
- // Assigns indices to the palette, and writes the encoded palette to the
- // libpng writePtr.
- WritePalette(write_ptr, write_info_ptr, &color_palette, &alpha_palette);
- png_set_filter(write_ptr, 0, PNG_NO_FILTERS);
- } else {
- png_set_filter(write_ptr, 0, PNG_ALL_FILTERS);
- }
-
- if (nine_patch) {
- WriteNinePatch(write_ptr, write_info_ptr, nine_patch);
- }
-
- // Flush our updates to the header.
- png_write_info(write_ptr, write_info_ptr);
-
- // Write out each row of image data according to its encoding.
- if (new_color_type == PNG_COLOR_TYPE_PALETTE) {
- // 1 byte/pixel.
- auto out_row = std::unique_ptr<png_byte[]>(new png_byte[image->width]);
-
- for (int32_t y = 0; y < image->height; y++) {
- png_const_bytep in_row = image->rows[y];
- for (int32_t x = 0; x < image->width; x++) {
- int rr = *in_row++;
- int gg = *in_row++;
- int bb = *in_row++;
- int aa = *in_row++;
- if (aa == 0) {
- // Zero out color channels when transparent.
- rr = gg = bb = 0;
- }
-
- const uint32_t color = rr << 24 | gg << 16 | bb << 8 | aa;
- const int idx = color_palette[color];
- CHECK(idx != -1);
- out_row[x] = static_cast<png_byte>(idx);
- }
- png_write_row(write_ptr, out_row.get());
- }
- } else if (new_color_type == PNG_COLOR_TYPE_GRAY ||
- new_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
- const size_t bpp = new_color_type == PNG_COLOR_TYPE_GRAY ? 1 : 2;
- auto out_row =
- std::unique_ptr<png_byte[]>(new png_byte[image->width * bpp]);
-
- for (int32_t y = 0; y < image->height; y++) {
- png_const_bytep in_row = image->rows[y];
- for (int32_t x = 0; x < image->width; x++) {
- int rr = in_row[x * 4];
- int gg = in_row[x * 4 + 1];
- int bb = in_row[x * 4 + 2];
- int aa = in_row[x * 4 + 3];
- if (aa == 0) {
- // Zero out the gray channel when transparent.
- rr = gg = bb = 0;
- }
-
- if (grayscale) {
- // The image was already grayscale, red == green == blue.
- out_row[x * bpp] = in_row[x * 4];
- } else {
- // The image is convertible to grayscale, use linear-luminance of
- // sRGB colorspace:
- // https://en.wikipedia.org/wiki/Grayscale#Colorimetric_.28luminance-preserving.29_conversion_to_grayscale
- out_row[x * bpp] =
- (png_byte)(rr * 0.2126f + gg * 0.7152f + bb * 0.0722f);
- }
-
- if (bpp == 2) {
- // Write out alpha if we have it.
- out_row[x * bpp + 1] = aa;
- }
- }
- png_write_row(write_ptr, out_row.get());
- }
- } else if (new_color_type == PNG_COLOR_TYPE_RGB || new_color_type == PNG_COLOR_TYPE_RGBA) {
- const size_t bpp = new_color_type == PNG_COLOR_TYPE_RGB ? 3 : 4;
- if (needs_to_zero_rgb_channels_of_transparent_pixels) {
- // The source RGBA data can't be used as-is, because we need to zero out
- // the RGB values of transparent pixels.
- auto out_row = std::unique_ptr<png_byte[]>(new png_byte[image->width * bpp]);
-
- for (int32_t y = 0; y < image->height; y++) {
- png_const_bytep in_row = image->rows[y];
- for (int32_t x = 0; x < image->width; x++) {
- int rr = *in_row++;
- int gg = *in_row++;
- int bb = *in_row++;
- int aa = *in_row++;
- if (aa == 0) {
- // Zero out the RGB channels when transparent.
- rr = gg = bb = 0;
- }
- out_row[x * bpp] = rr;
- out_row[x * bpp + 1] = gg;
- out_row[x * bpp + 2] = bb;
- if (bpp == 4) {
- out_row[x * bpp + 3] = aa;
- }
- }
- png_write_row(write_ptr, out_row.get());
- }
- } else {
- // The source image can be used as-is, just tell libpng whether or not to
- // ignore the alpha channel.
- if (new_color_type == PNG_COLOR_TYPE_RGB) {
- // Delete the extraneous alpha values that we appended to our buffer
- // when reading the original values.
- png_set_filler(write_ptr, 0, PNG_FILLER_AFTER);
- }
- png_write_image(write_ptr, image->rows.get());
- }
- } else {
- LOG(FATAL) << "unreachable";
- }
-
- png_write_end(write_ptr, write_info_ptr);
- return true;
-}
-
-} // namespace aapt
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index a2b4818..a596229 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -29,8 +29,8 @@
#include "SdkConstants.h"
#include "ValueVisitor.h"
#include "androidfw/ConfigDescription.h"
+#include "androidfw/FileStream.h"
#include "io/File.h"
-#include "io/FileStream.h"
#include "process/IResourceTableConsumer.h"
#include "xml/XmlDom.h"
diff --git a/tools/aapt2/format/Archive.cpp b/tools/aapt2/format/Archive.cpp
index e9a93d8..91768a0 100644
--- a/tools/aapt2/format/Archive.cpp
+++ b/tools/aapt2/format/Archive.cpp
@@ -91,7 +91,7 @@
return true;
}
- bool WriteFile(StringPiece path, uint32_t flags, io::InputStream* in) override {
+ bool WriteFile(StringPiece path, uint32_t flags, android::InputStream* in) override {
if (!StartEntry(path, flags)) {
return false;
}
@@ -182,7 +182,7 @@
return true;
}
- bool WriteFile(StringPiece path, uint32_t flags, io::InputStream* in) override {
+ bool WriteFile(StringPiece path, uint32_t flags, android::InputStream* in) override {
while (true) {
if (!StartEntry(path, flags)) {
return false;
diff --git a/tools/aapt2/format/Archive.h b/tools/aapt2/format/Archive.h
index 6cde753..3c3d0ab 100644
--- a/tools/aapt2/format/Archive.h
+++ b/tools/aapt2/format/Archive.h
@@ -24,9 +24,9 @@
#include "androidfw/BigBuffer.h"
#include "androidfw/IDiagnostics.h"
+#include "androidfw/Streams.h"
#include "androidfw/StringPiece.h"
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
-#include "io/Io.h"
#include "util/Files.h"
namespace aapt {
@@ -46,7 +46,7 @@
public:
virtual ~IArchiveWriter() = default;
- virtual bool WriteFile(android::StringPiece path, uint32_t flags, io::InputStream* in) = 0;
+ virtual bool WriteFile(android::StringPiece path, uint32_t flags, android::InputStream* in) = 0;
// Starts a new entry and allows caller to write bytes to it sequentially.
// Only use StartEntry if code you do not control needs to write to a CopyingOutputStream.
diff --git a/tools/aapt2/format/Archive_test.cpp b/tools/aapt2/format/Archive_test.cpp
index fd50af9..df105f8 100644
--- a/tools/aapt2/format/Archive_test.cpp
+++ b/tools/aapt2/format/Archive_test.cpp
@@ -95,7 +95,7 @@
void VerifyZipFile(const std::string& output_path, const std::string& file, const uint8_t array[]) {
std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(output_path, nullptr);
- std::unique_ptr<io::InputStream> stream = zip->FindFile(file)->OpenInputStream();
+ std::unique_ptr<android::InputStream> stream = zip->FindFile(file)->OpenInputStream();
std::vector<uint8_t> buffer;
const void* data;
diff --git a/tools/aapt2/format/Container.cpp b/tools/aapt2/format/Container.cpp
index 1ff6c49..cb4a225 100644
--- a/tools/aapt2/format/Container.cpp
+++ b/tools/aapt2/format/Container.cpp
@@ -94,7 +94,7 @@
}
bool ContainerWriter::AddResFileEntry(const pb::internal::CompiledFile& file,
- io::KnownSizeInputStream* in) {
+ android::KnownSizeInputStream* in) {
if (current_entry_count_ >= total_entry_count_) {
error_ = "too many entries being serialized";
return false;
@@ -264,7 +264,7 @@
return reader_->GetError();
}
-ContainerReader::ContainerReader(io::InputStream* in)
+ContainerReader::ContainerReader(android::InputStream* in)
: in_(in),
adaptor_(in),
coded_in_(&adaptor_),
diff --git a/tools/aapt2/format/Container.h b/tools/aapt2/format/Container.h
index 121c592..c5d5676 100644
--- a/tools/aapt2/format/Container.h
+++ b/tools/aapt2/format/Container.h
@@ -22,9 +22,9 @@
#include "Resources.pb.h"
#include "ResourcesInternal.pb.h"
#include "androidfw/BigBuffer.h"
+#include "androidfw/Streams.h"
#include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/io/zero_copy_stream.h"
-#include "io/Io.h"
#include "io/Util.h"
namespace aapt {
@@ -39,7 +39,7 @@
explicit ContainerWriter(::google::protobuf::io::ZeroCopyOutputStream* out, size_t entry_count);
bool AddResTableEntry(const pb::ResourceTable& table);
- bool AddResFileEntry(const pb::internal::CompiledFile& file, io::KnownSizeInputStream* in);
+ bool AddResFileEntry(const pb::internal::CompiledFile& file, android::KnownSizeInputStream* in);
bool HadError() const;
std::string GetError() const;
@@ -79,7 +79,7 @@
class ContainerReader {
public:
- explicit ContainerReader(io::InputStream* in);
+ explicit ContainerReader(android::InputStream* in);
ContainerReaderEntry* Next();
@@ -91,7 +91,7 @@
friend class ContainerReaderEntry;
- io::InputStream* in_;
+ android::InputStream* in_;
io::ZeroCopyInputAdaptor adaptor_;
::google::protobuf::io::CodedInputStream coded_in_;
size_t total_entry_count_;
diff --git a/tools/aapt2/io/BigBufferStream.cpp b/tools/aapt2/io/BigBufferStream.cpp
deleted file mode 100644
index 9704caa..0000000
--- a/tools/aapt2/io/BigBufferStream.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "io/BigBufferStream.h"
-
-namespace aapt {
-namespace io {
-
-//
-// BigBufferInputStream
-//
-
-bool BigBufferInputStream::Next(const void** data, size_t* size) {
- if (iter_ == buffer_->end()) {
- return false;
- }
-
- if (offset_ == iter_->size) {
- ++iter_;
- if (iter_ == buffer_->end()) {
- return false;
- }
- offset_ = 0;
- }
-
- *data = iter_->buffer.get() + offset_;
- *size = iter_->size - offset_;
- bytes_read_ += iter_->size - offset_;
- offset_ = iter_->size;
- return true;
-}
-
-void BigBufferInputStream::BackUp(size_t count) {
- if (count > offset_) {
- bytes_read_ -= offset_;
- offset_ = 0;
- } else {
- offset_ -= count;
- bytes_read_ -= count;
- }
-}
-
-bool BigBufferInputStream::CanRewind() const {
- return true;
-}
-
-bool BigBufferInputStream::Rewind() {
- iter_ = buffer_->begin();
- offset_ = 0;
- bytes_read_ = 0;
- return true;
-}
-
-size_t BigBufferInputStream::ByteCount() const {
- return bytes_read_;
-}
-
-bool BigBufferInputStream::HadError() const {
- return false;
-}
-
-size_t BigBufferInputStream::TotalSize() const {
- return buffer_->size();
-}
-
-//
-// BigBufferOutputStream
-//
-
-bool BigBufferOutputStream::Next(void** data, size_t* size) {
- *data = buffer_->NextBlock(size);
- return true;
-}
-
-void BigBufferOutputStream::BackUp(size_t count) {
- buffer_->BackUp(count);
-}
-
-size_t BigBufferOutputStream::ByteCount() const {
- return buffer_->size();
-}
-
-bool BigBufferOutputStream::HadError() const {
- return false;
-}
-
-} // namespace io
-} // namespace aapt
diff --git a/tools/aapt2/io/BigBufferStream.h b/tools/aapt2/io/BigBufferStream.h
deleted file mode 100644
index 63a5e57..0000000
--- a/tools/aapt2/io/BigBufferStream.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_IO_BIGBUFFERSTREAM_H
-#define AAPT_IO_BIGBUFFERSTREAM_H
-
-#include "androidfw/BigBuffer.h"
-#include "io/Io.h"
-
-namespace aapt {
-namespace io {
-
-class BigBufferInputStream : public KnownSizeInputStream {
- public:
- inline explicit BigBufferInputStream(const android::BigBuffer* buffer)
- : buffer_(buffer), iter_(buffer->begin()) {
- }
- virtual ~BigBufferInputStream() = default;
-
- bool Next(const void** data, size_t* size) override;
-
- void BackUp(size_t count) override;
-
- bool CanRewind() const override;
-
- bool Rewind() override;
-
- size_t ByteCount() const override;
-
- bool HadError() const override;
-
- size_t TotalSize() const override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(BigBufferInputStream);
-
- const android::BigBuffer* buffer_;
- android::BigBuffer::const_iterator iter_;
- size_t offset_ = 0;
- size_t bytes_read_ = 0;
-};
-
-class BigBufferOutputStream : public OutputStream {
- public:
- inline explicit BigBufferOutputStream(android::BigBuffer* buffer) : buffer_(buffer) {
- }
- virtual ~BigBufferOutputStream() = default;
-
- bool Next(void** data, size_t* size) override;
-
- void BackUp(size_t count) override;
-
- size_t ByteCount() const override;
-
- bool HadError() const override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(BigBufferOutputStream);
-
- android::BigBuffer* buffer_;
-};
-
-} // namespace io
-} // namespace aapt
-
-#endif // AAPT_IO_BIGBUFFERSTREAM_H
diff --git a/tools/aapt2/io/Data.h b/tools/aapt2/io/Data.h
index db91a77..29f523a 100644
--- a/tools/aapt2/io/Data.h
+++ b/tools/aapt2/io/Data.h
@@ -20,15 +20,14 @@
#include <memory>
#include "android-base/macros.h"
+#include "androidfw/Streams.h"
#include "utils/FileMap.h"
-#include "io/Io.h"
-
namespace aapt {
namespace io {
// Interface for a block of contiguous memory. An instance of this interface owns the data.
-class IData : public KnownSizeInputStream {
+class IData : public android::KnownSizeInputStream {
public:
virtual ~IData() = default;
diff --git a/tools/aapt2/io/File.cpp b/tools/aapt2/io/File.cpp
index b4f1ff3..4dfdb5b 100644
--- a/tools/aapt2/io/File.cpp
+++ b/tools/aapt2/io/File.cpp
@@ -39,7 +39,7 @@
return {};
}
-std::unique_ptr<io::InputStream> FileSegment::OpenInputStream() {
+std::unique_ptr<android::InputStream> FileSegment::OpenInputStream() {
return OpenAsData();
}
diff --git a/tools/aapt2/io/File.h b/tools/aapt2/io/File.h
index 673d1b7..248756b 100644
--- a/tools/aapt2/io/File.h
+++ b/tools/aapt2/io/File.h
@@ -43,7 +43,7 @@
// Returns nullptr on failure.
virtual std::unique_ptr<IData> OpenAsData() = 0;
- virtual std::unique_ptr<io::InputStream> OpenInputStream() = 0;
+ virtual std::unique_ptr<android::InputStream> OpenInputStream() = 0;
// Returns the source of this file. This is for presentation to the user and
// may not be a valid file system path (for example, it may contain a '@' sign to separate
@@ -78,7 +78,7 @@
: file_(file), offset_(offset), len_(len) {}
std::unique_ptr<IData> OpenAsData() override;
- std::unique_ptr<io::InputStream> OpenInputStream() override;
+ std::unique_ptr<android::InputStream> OpenInputStream() override;
const android::Source& GetSource() const override {
return file_->GetSource();
diff --git a/tools/aapt2/io/FileStream.cpp b/tools/aapt2/io/FileStream.cpp
deleted file mode 100644
index 27529bc..0000000
--- a/tools/aapt2/io/FileStream.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "io/FileStream.h"
-
-#include <errno.h> // for errno
-#include <fcntl.h> // for O_RDONLY
-#include <unistd.h> // for read
-
-#include "android-base/errors.h"
-#include "android-base/file.h" // for O_BINARY
-#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;
-
-namespace aapt {
-namespace io {
-
-FileInputStream::FileInputStream(const std::string& path, size_t 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) {
- if (fd_ < 0) {
- error_ = "Bad File Descriptor";
- } else {
- buffer_.reset(new uint8_t[buffer_capacity_]);
- }
-}
-
-bool FileInputStream::Next(const void** data, size_t* size) {
- if (HadError()) {
- return false;
- }
-
- // Deal with any remaining bytes after BackUp was called.
- if (buffer_offset_ != buffer_size_) {
- *data = buffer_.get() + buffer_offset_;
- *size = buffer_size_ - buffer_offset_;
- total_byte_count_ += buffer_size_ - buffer_offset_;
- buffer_offset_ = buffer_size_;
- return true;
- }
-
- ssize_t n = TEMP_FAILURE_RETRY(read(fd_, buffer_.get(), buffer_capacity_));
- if (n < 0) {
- error_ = SystemErrorCodeToString(errno);
- fd_.reset();
- buffer_.reset();
- return false;
- }
-
- buffer_size_ = static_cast<size_t>(n);
- buffer_offset_ = buffer_size_;
- total_byte_count_ += buffer_size_;
-
- *data = buffer_.get();
- *size = buffer_size_;
- return buffer_size_ != 0u;
-}
-
-void FileInputStream::BackUp(size_t count) {
- if (count > buffer_offset_) {
- count = buffer_offset_;
- }
- buffer_offset_ -= count;
- total_byte_count_ -= count;
-}
-
-size_t FileInputStream::ByteCount() const {
- return total_byte_count_;
-}
-
-bool FileInputStream::HadError() const {
- return fd_ == -1;
-}
-
-std::string FileInputStream::GetError() const {
- return error_;
-}
-
-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)
- : FileOutputStream(fd.get(), buffer_capacity) {
- owned_fd_ = std::move(fd);
-}
-
-FileOutputStream::FileOutputStream(int fd, size_t buffer_capacity)
- : fd_(fd), buffer_capacity_(buffer_capacity) {
- if (fd_ < 0) {
- error_ = "Bad File Descriptor";
- } else {
- buffer_.reset(new uint8_t[buffer_capacity_]);
- }
-}
-
-FileOutputStream::~FileOutputStream() {
- // Flush the buffer.
- Flush();
-}
-
-bool FileOutputStream::Next(void** data, size_t* size) {
- if (HadError()) {
- return false;
- }
-
- if (buffer_offset_ == buffer_capacity_) {
- if (!FlushImpl()) {
- return false;
- }
- }
-
- const size_t buffer_size = buffer_capacity_ - buffer_offset_;
- *data = buffer_.get() + buffer_offset_;
- *size = buffer_size;
- total_byte_count_ += buffer_size;
- buffer_offset_ = buffer_capacity_;
- return true;
-}
-
-void FileOutputStream::BackUp(size_t count) {
- if (count > buffer_offset_) {
- count = buffer_offset_;
- }
- buffer_offset_ -= count;
- total_byte_count_ -= count;
-}
-
-size_t FileOutputStream::ByteCount() const {
- return total_byte_count_;
-}
-
-bool FileOutputStream::Flush() {
- if (!HadError()) {
- return FlushImpl();
- }
- return false;
-}
-
-bool FileOutputStream::FlushImpl() {
- ssize_t n = TEMP_FAILURE_RETRY(write(fd_, buffer_.get(), buffer_offset_));
- if (n < 0) {
- error_ = SystemErrorCodeToString(errno);
- owned_fd_.reset();
- fd_ = -1;
- buffer_.reset();
- return false;
- }
-
- buffer_offset_ = 0u;
- return true;
-}
-
-bool FileOutputStream::HadError() const {
- return fd_ == -1;
-}
-
-std::string FileOutputStream::GetError() const {
- return error_;
-}
-
-} // namespace io
-} // namespace aapt
diff --git a/tools/aapt2/io/FileStream.h b/tools/aapt2/io/FileStream.h
deleted file mode 100644
index 62d910f..0000000
--- a/tools/aapt2/io/FileStream.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_IO_FILESTREAM_H
-#define AAPT_IO_FILESTREAM_H
-
-#include "io/Io.h"
-
-#include <memory>
-#include <string>
-
-#include "android-base/macros.h"
-#include "android-base/unique_fd.h"
-
-namespace aapt {
-namespace io {
-
-constexpr size_t kDefaultBufferCapacity = 4096u;
-
-class FileInputStream : public InputStream {
- public:
- explicit FileInputStream(const std::string& path,
- size_t buffer_capacity = kDefaultBufferCapacity);
-
- // Take ownership of `fd`.
- explicit FileInputStream(int fd, size_t buffer_capacity = kDefaultBufferCapacity);
-
- bool Next(const void** data, size_t* size) override;
-
- void BackUp(size_t count) override;
-
- size_t ByteCount() const override;
-
- bool HadError() const override;
-
- std::string GetError() const override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FileInputStream);
-
- android::base::unique_fd fd_;
- std::string error_;
- std::unique_ptr<uint8_t[]> buffer_;
- 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,
- size_t buffer_capacity = kDefaultBufferCapacity);
-
- // Does not take ownership of `fd`.
- explicit FileOutputStream(int fd, size_t buffer_capacity = kDefaultBufferCapacity);
-
- // Takes ownership of `fd`.
- explicit FileOutputStream(android::base::unique_fd fd,
- size_t buffer_capacity = kDefaultBufferCapacity);
-
- ~FileOutputStream();
-
- bool Next(void** data, size_t* size) override;
-
- // Immediately flushes out the contents of the buffer to disk.
- bool Flush();
-
- void BackUp(size_t count) override;
-
- size_t ByteCount() const override;
-
- bool HadError() const override;
-
- std::string GetError() const override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FileOutputStream);
-
- bool FlushImpl();
-
- android::base::unique_fd owned_fd_;
- int fd_;
- std::string error_;
- std::unique_ptr<uint8_t[]> buffer_;
- size_t buffer_capacity_ = 0u;
- size_t buffer_offset_ = 0u;
- size_t total_byte_count_ = 0u;
-};
-
-} // namespace io
-} // namespace aapt
-
-#endif // AAPT_IO_FILESTREAM_H
diff --git a/tools/aapt2/io/FileStream_test.cpp b/tools/aapt2/io/FileStream_test.cpp
deleted file mode 100644
index cc9cd28..0000000
--- a/tools/aapt2/io/FileStream_test.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "io/FileStream.h"
-
-#include "android-base/file.h"
-#include "android-base/macros.h"
-
-#include "test/Test.h"
-
-using ::android::StringPiece;
-using ::testing::Eq;
-using ::testing::NotNull;
-using ::testing::StrEq;
-
-namespace aapt {
-namespace io {
-
-TEST(FileInputStreamTest, NextAndBackup) {
- std::string input = "this is a cool string";
- TemporaryFile file;
- ASSERT_THAT(TEMP_FAILURE_RETRY(write(file.fd, input.c_str(), input.size())), Eq(21));
- lseek64(file.fd, 0, SEEK_SET);
-
- // Use a small buffer size so that we can call Next() a few times.
- FileInputStream in(file.release(), 10u);
- ASSERT_FALSE(in.HadError());
- EXPECT_THAT(in.ByteCount(), Eq(0u));
-
- const void* buffer;
- size_t size;
- ASSERT_TRUE(in.Next(&buffer, &size)) << in.GetError();
- ASSERT_THAT(size, Eq(10u));
- ASSERT_THAT(buffer, NotNull());
- EXPECT_THAT(in.ByteCount(), Eq(10u));
- EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("this is a "));
-
- ASSERT_TRUE(in.Next(&buffer, &size));
- ASSERT_THAT(size, Eq(10u));
- ASSERT_THAT(buffer, NotNull());
- EXPECT_THAT(in.ByteCount(), Eq(20u));
- EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("cool strin"));
-
- in.BackUp(5u);
- EXPECT_THAT(in.ByteCount(), Eq(15u));
-
- ASSERT_TRUE(in.Next(&buffer, &size));
- ASSERT_THAT(size, Eq(5u));
- ASSERT_THAT(buffer, NotNull());
- ASSERT_THAT(in.ByteCount(), Eq(20u));
- EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("strin"));
-
- // Backup 1 more than possible. Should clamp.
- in.BackUp(11u);
- EXPECT_THAT(in.ByteCount(), Eq(10u));
-
- ASSERT_TRUE(in.Next(&buffer, &size));
- ASSERT_THAT(size, Eq(10u));
- ASSERT_THAT(buffer, NotNull());
- ASSERT_THAT(in.ByteCount(), Eq(20u));
- EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("cool strin"));
-
- ASSERT_TRUE(in.Next(&buffer, &size));
- ASSERT_THAT(size, Eq(1u));
- ASSERT_THAT(buffer, NotNull());
- ASSERT_THAT(in.ByteCount(), Eq(21u));
- EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("g"));
-
- EXPECT_FALSE(in.Next(&buffer, &size));
- EXPECT_FALSE(in.HadError());
-}
-
-TEST(FileOutputStreamTest, NextAndBackup) {
- const std::string input = "this is a cool string";
-
- TemporaryFile file;
-
- FileOutputStream out(file.fd, 10u);
- ASSERT_FALSE(out.HadError());
- EXPECT_THAT(out.ByteCount(), Eq(0u));
-
- void* buffer;
- size_t size;
- ASSERT_TRUE(out.Next(&buffer, &size));
- ASSERT_THAT(size, Eq(10u));
- ASSERT_THAT(buffer, NotNull());
- EXPECT_THAT(out.ByteCount(), Eq(10u));
- memcpy(reinterpret_cast<char*>(buffer), input.c_str(), size);
-
- ASSERT_TRUE(out.Next(&buffer, &size));
- ASSERT_THAT(size, Eq(10u));
- ASSERT_THAT(buffer, NotNull());
- EXPECT_THAT(out.ByteCount(), Eq(20u));
- memcpy(reinterpret_cast<char*>(buffer), input.c_str() + 10u, size);
-
- ASSERT_TRUE(out.Next(&buffer, &size));
- ASSERT_THAT(size, Eq(10u));
- ASSERT_THAT(buffer, NotNull());
- EXPECT_THAT(out.ByteCount(), Eq(30u));
- reinterpret_cast<char*>(buffer)[0] = input[20u];
- out.BackUp(size - 1);
- EXPECT_THAT(out.ByteCount(), Eq(21u));
-
- ASSERT_TRUE(out.Flush());
-
- lseek64(file.fd, 0, SEEK_SET);
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(file.fd, &actual));
- EXPECT_THAT(actual, StrEq(input));
-}
-
-} // namespace io
-} // namespace aapt
diff --git a/tools/aapt2/io/FileSystem.cpp b/tools/aapt2/io/FileSystem.cpp
index 6a692e4..03fabcc 100644
--- a/tools/aapt2/io/FileSystem.cpp
+++ b/tools/aapt2/io/FileSystem.cpp
@@ -22,9 +22,9 @@
#include <sys/stat.h>
#include "android-base/errors.h"
+#include "androidfw/FileStream.h"
#include "androidfw/Source.h"
#include "androidfw/StringPiece.h"
-#include "io/FileStream.h"
#include "util/Files.h"
#include "util/Util.h"
#include "utils/FileMap.h"
@@ -49,8 +49,8 @@
return {};
}
-std::unique_ptr<io::InputStream> RegularFile::OpenInputStream() {
- return util::make_unique<FileInputStream>(source_.path);
+std::unique_ptr<android::InputStream> RegularFile::OpenInputStream() {
+ return util::make_unique<android::FileInputStream>(source_.path);
}
const android::Source& RegularFile::GetSource() const {
diff --git a/tools/aapt2/io/FileSystem.h b/tools/aapt2/io/FileSystem.h
index f975196..d6ecfeb 100644
--- a/tools/aapt2/io/FileSystem.h
+++ b/tools/aapt2/io/FileSystem.h
@@ -30,7 +30,7 @@
explicit RegularFile(const android::Source& source);
std::unique_ptr<IData> OpenAsData() override;
- std::unique_ptr<io::InputStream> OpenInputStream() override;
+ std::unique_ptr<android::InputStream> OpenInputStream() override;
const android::Source& GetSource() const override;
bool GetModificationTime(struct tm* buf) const override;
diff --git a/tools/aapt2/io/Io.h b/tools/aapt2/io/Io.h
deleted file mode 100644
index e1df23a6..0000000
--- a/tools/aapt2/io/Io.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_IO_IO_H
-#define AAPT_IO_IO_H
-
-#include <string>
-
-namespace aapt {
-namespace io {
-
-// InputStream interface that mimics protobuf's ZeroCopyInputStream,
-// with added error handling methods to better report issues.
-class InputStream {
- public:
- virtual ~InputStream() = default;
-
- // Returns a chunk of data for reading. data and size must not be nullptr.
- // Returns true so long as there is more data to read, returns false if an error occurred
- // or no data remains. If an error occurred, check HadError().
- // The stream owns the buffer returned from this method and the buffer is invalidated
- // anytime another mutable method is called.
- virtual bool Next(const void** data, size_t* size) = 0;
-
- // Backup count bytes, where count is smaller or equal to the size of the last buffer returned
- // from Next().
- // Useful when the last block returned from Next() wasn't fully read.
- virtual void BackUp(size_t count) = 0;
-
- // Returns true if this InputStream can rewind. If so, Rewind() can be called.
- virtual bool CanRewind() const { return false; };
-
- // Rewinds the stream to the beginning so it can be read again.
- // Returns true if the rewind succeeded.
- // This does nothing if CanRewind() returns false.
- virtual bool Rewind() { return false; }
-
- // Returns the number of bytes that have been read from the stream.
- virtual size_t ByteCount() const = 0;
-
- // Returns an error message if HadError() returned true.
- virtual std::string GetError() const { return {}; }
-
- // Returns true if an error occurred. Errors are permanent.
- virtual bool HadError() const = 0;
-};
-
-// A sub-InputStream interface that knows the total size of its stream.
-class KnownSizeInputStream : public InputStream {
- public:
- virtual size_t TotalSize() const = 0;
-};
-
-// OutputStream interface that mimics protobuf's ZeroCopyOutputStream,
-// with added error handling methods to better report issues.
-class OutputStream {
- public:
- virtual ~OutputStream() = default;
-
- // Returns a buffer to which data can be written to. The data written to this buffer will
- // eventually be written to the stream. Call BackUp() if the data written doesn't occupy the
- // entire buffer.
- // Return false if there was an error.
- // The stream owns the buffer returned from this method and the buffer is invalidated
- // anytime another mutable method is called.
- virtual bool Next(void** data, size_t* size) = 0;
-
- // Backup count bytes, where count is smaller or equal to the size of the last buffer returned
- // from Next().
- // Useful for when the last block returned from Next() wasn't fully written to.
- virtual void BackUp(size_t count) = 0;
-
- // Returns the number of bytes that have been written to the stream.
- virtual size_t ByteCount() const = 0;
-
- // Returns an error message if HadError() returned true.
- virtual std::string GetError() const { return {}; }
-
- // Returns true if an error occurred. Errors are permanent.
- virtual bool HadError() const = 0;
-};
-
-} // namespace io
-} // namespace aapt
-
-#endif /* AAPT_IO_IO_H */
diff --git a/tools/aapt2/io/StringStream.cpp b/tools/aapt2/io/StringStream.cpp
index 9c49788..bb3911b 100644
--- a/tools/aapt2/io/StringStream.cpp
+++ b/tools/aapt2/io/StringStream.cpp
@@ -51,6 +51,23 @@
return str_.size();
}
+bool StringInputStream::ReadFullyAtOffset(void* data, size_t byte_count, off64_t offset) {
+ if (byte_count == 0) {
+ return true;
+ }
+ if (offset < 0) {
+ return false;
+ }
+ if (offset > std::numeric_limits<off64_t>::max() - byte_count) {
+ return false;
+ }
+ if (offset + byte_count > str_.size()) {
+ return false;
+ }
+ memcpy(data, str_.data() + offset, byte_count);
+ return true;
+}
+
StringOutputStream::StringOutputStream(std::string* str, size_t buffer_capacity)
: str_(str),
buffer_capacity_(buffer_capacity),
diff --git a/tools/aapt2/io/StringStream.h b/tools/aapt2/io/StringStream.h
index f7bdecca..7e1abe5 100644
--- a/tools/aapt2/io/StringStream.h
+++ b/tools/aapt2/io/StringStream.h
@@ -17,17 +17,16 @@
#ifndef AAPT_IO_STRINGSTREAM_H
#define AAPT_IO_STRINGSTREAM_H
-#include "io/Io.h"
-
#include <memory>
#include "android-base/macros.h"
+#include "androidfw/Streams.h"
#include "androidfw/StringPiece.h"
namespace aapt {
namespace io {
-class StringInputStream : public KnownSizeInputStream {
+class StringInputStream : public android::KnownSizeInputStream {
public:
explicit StringInputStream(android::StringPiece str);
@@ -47,6 +46,8 @@
size_t TotalSize() const override;
+ bool ReadFullyAtOffset(void* data, size_t byte_count, off64_t offset) override;
+
private:
DISALLOW_COPY_AND_ASSIGN(StringInputStream);
@@ -54,7 +55,7 @@
size_t offset_;
};
-class StringOutputStream : public OutputStream {
+class StringOutputStream : public android::OutputStream {
public:
explicit StringOutputStream(std::string* str, size_t buffer_capacity = 4096u);
diff --git a/tools/aapt2/io/Util.cpp b/tools/aapt2/io/Util.cpp
index 79d8d52..9616e47 100644
--- a/tools/aapt2/io/Util.cpp
+++ b/tools/aapt2/io/Util.cpp
@@ -26,8 +26,9 @@
namespace aapt {
namespace io {
-bool CopyInputStreamToArchive(IAaptContext* context, InputStream* in, std::string_view out_path,
- uint32_t compression_flags, IArchiveWriter* writer) {
+bool CopyInputStreamToArchive(IAaptContext* context, android::InputStream* in,
+ std::string_view out_path, uint32_t compression_flags,
+ IArchiveWriter* writer) {
TRACE_CALL();
if (context->IsVerbose()) {
context->GetDiagnostics()->Note(android::DiagMessage()
@@ -91,7 +92,7 @@
return false;
}
-bool Copy(OutputStream* out, InputStream* in) {
+bool Copy(android::OutputStream* out, android::InputStream* in) {
TRACE_CALL();
const void* in_buffer;
size_t in_len;
@@ -110,7 +111,7 @@
return !in->HadError();
}
-bool Copy(OutputStream* out, StringPiece in) {
+bool Copy(android::OutputStream* out, StringPiece in) {
const char* in_buffer = in.data();
size_t in_len = in.size();
while (in_len != 0) {
@@ -129,7 +130,7 @@
return true;
}
-bool Copy(ZeroCopyOutputStream* out, InputStream* in) {
+bool Copy(ZeroCopyOutputStream* out, android::InputStream* in) {
OutputStreamAdaptor adaptor(out);
return Copy(&adaptor, in);
}
diff --git a/tools/aapt2/io/Util.h b/tools/aapt2/io/Util.h
index 685f522..25aa8f8 100644
--- a/tools/aapt2/io/Util.h
+++ b/tools/aapt2/io/Util.h
@@ -19,18 +19,19 @@
#include <string_view>
+#include "androidfw/Streams.h"
#include "format/Archive.h"
#include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/message.h"
#include "io/File.h"
-#include "io/Io.h"
#include "process/IResourceTableConsumer.h"
namespace aapt {
namespace io {
-bool CopyInputStreamToArchive(IAaptContext* context, InputStream* in, std::string_view out_path,
- uint32_t compression_flags, IArchiveWriter* writer);
+bool CopyInputStreamToArchive(IAaptContext* context, android::InputStream* in,
+ std::string_view out_path, uint32_t compression_flags,
+ IArchiveWriter* writer);
bool CopyFileToArchive(IAaptContext* context, IFile* file, std::string_view out_path,
uint32_t compression_flags, IArchiveWriter* writer);
@@ -44,11 +45,11 @@
// Copies the data from in to out. Returns false if there was an error.
// If there was an error, check the individual streams' HadError/GetError methods.
-bool Copy(OutputStream* out, InputStream* in);
-bool Copy(OutputStream* out, android::StringPiece in);
-bool Copy(::google::protobuf::io::ZeroCopyOutputStream* out, InputStream* in);
+bool Copy(android::OutputStream* out, android::InputStream* in);
+bool Copy(android::OutputStream* out, android::StringPiece in);
+bool Copy(::google::protobuf::io::ZeroCopyOutputStream* out, android::InputStream* in);
-class OutputStreamAdaptor : public io::OutputStream {
+class OutputStreamAdaptor : public android::OutputStream {
public:
explicit OutputStreamAdaptor(::google::protobuf::io::ZeroCopyOutputStream* out) : out_(out) {
}
@@ -84,7 +85,7 @@
class ZeroCopyInputAdaptor : public ::google::protobuf::io::ZeroCopyInputStream {
public:
- explicit ZeroCopyInputAdaptor(io::InputStream* in) : in_(in) {
+ explicit ZeroCopyInputAdaptor(android::InputStream* in) : in_(in) {
}
bool Next(const void** data, int* size) override {
@@ -119,12 +120,13 @@
private:
DISALLOW_COPY_AND_ASSIGN(ZeroCopyInputAdaptor);
- io::InputStream* in_;
+ android::InputStream* in_;
};
class ProtoInputStreamReader {
public:
- explicit ProtoInputStreamReader(io::InputStream* in) : in_(in) { }
+ explicit ProtoInputStreamReader(android::InputStream* in) : in_(in) {
+ }
/** Deserializes a Message proto from the current position in the input stream.*/
template <typename T> bool ReadMessage(T *message) {
@@ -135,7 +137,7 @@
}
private:
- io::InputStream* in_;
+ android::InputStream* in_;
};
} // namespace io
diff --git a/tools/aapt2/io/ZipArchive.cpp b/tools/aapt2/io/ZipArchive.cpp
index cb5bbe9..e44d61e 100644
--- a/tools/aapt2/io/ZipArchive.cpp
+++ b/tools/aapt2/io/ZipArchive.cpp
@@ -63,7 +63,7 @@
}
}
-std::unique_ptr<io::InputStream> ZipFile::OpenInputStream() {
+std::unique_ptr<android::InputStream> ZipFile::OpenInputStream() {
return OpenAsData();
}
diff --git a/tools/aapt2/io/ZipArchive.h b/tools/aapt2/io/ZipArchive.h
index ac125d0..a53c4a2 100644
--- a/tools/aapt2/io/ZipArchive.h
+++ b/tools/aapt2/io/ZipArchive.h
@@ -35,7 +35,7 @@
ZipFile(::ZipArchiveHandle handle, const ::ZipEntry& entry, const android::Source& source);
std::unique_ptr<IData> OpenAsData() override;
- std::unique_ptr<io::InputStream> OpenInputStream() override;
+ std::unique_ptr<android::InputStream> OpenInputStream() override;
const android::Source& GetSource() const override;
bool WasCompressed() override;
bool GetModificationTime(struct tm* buf) const override;
diff --git a/tools/aapt2/java/ClassDefinition.cpp b/tools/aapt2/java/ClassDefinition.cpp
index 98f3bd2..db7aa35 100644
--- a/tools/aapt2/java/ClassDefinition.cpp
+++ b/tools/aapt2/java/ClassDefinition.cpp
@@ -111,7 +111,7 @@
" */\n\n";
void ClassDefinition::WriteJavaFile(const ClassDefinition* def, StringPiece package, bool final,
- bool strip_api_annotations, io::OutputStream* out) {
+ bool strip_api_annotations, android::OutputStream* out) {
Printer printer(out);
printer.Print(sWarningHeader).Print("package ").Print(package).Println(";");
printer.Println();
diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h
index 63c9982..84e3f33 100644
--- a/tools/aapt2/java/ClassDefinition.h
+++ b/tools/aapt2/java/ClassDefinition.h
@@ -241,7 +241,7 @@
class ClassDefinition : public ClassMember {
public:
static void WriteJavaFile(const ClassDefinition* def, android::StringPiece package, bool final,
- bool strip_api_annotations, io::OutputStream* out);
+ bool strip_api_annotations, android::OutputStream* out);
ClassDefinition(android::StringPiece name, ClassQualifier qualifier, bool createIfEmpty)
: name_(name), qualifier_(qualifier), create_if_empty_(createIfEmpty) {
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 7665d0e..58f6564 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -37,8 +37,8 @@
#include "java/ClassDefinition.h"
#include "process/SymbolTable.h"
-using ::aapt::io::OutputStream;
using ::aapt::text::Printer;
+using ::android::OutputStream;
using ::android::StringPiece;
using ::android::base::StringPrintf;
diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h
index 234df04..9909eec 100644
--- a/tools/aapt2/java/JavaClassGenerator.h
+++ b/tools/aapt2/java/JavaClassGenerator.h
@@ -19,11 +19,10 @@
#include <string>
-#include "androidfw/StringPiece.h"
-
#include "ResourceTable.h"
#include "ResourceValues.h"
-#include "io/Io.h"
+#include "androidfw/Streams.h"
+#include "androidfw/StringPiece.h"
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
#include "text/Printer.h"
@@ -70,12 +69,12 @@
// 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(android::StringPiece package_name_to_generate, io::OutputStream* out,
- io::OutputStream* out_r_txt = nullptr);
+ bool Generate(android::StringPiece package_name_to_generate, android::OutputStream* out,
+ android::OutputStream* out_r_txt = nullptr);
bool Generate(android::StringPiece package_name_to_generate,
- android::StringPiece output_package_name, io::OutputStream* out,
- io::OutputStream* out_r_txt = nullptr);
+ android::StringPiece output_package_name, android::OutputStream* out,
+ android::OutputStream* out_r_txt = nullptr);
const std::string& GetError() const;
diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp
index 80a46d5..aef48fc 100644
--- a/tools/aapt2/java/ProguardRules.cpp
+++ b/tools/aapt2/java/ProguardRules.cpp
@@ -29,8 +29,8 @@
#include "util/Util.h"
#include "xml/XmlDom.h"
-using ::aapt::io::OutputStream;
using ::aapt::text::Printer;
+using ::android::OutputStream;
namespace aapt {
namespace proguard {
diff --git a/tools/aapt2/java/ProguardRules.h b/tools/aapt2/java/ProguardRules.h
index 267f7ed..876ef48 100644
--- a/tools/aapt2/java/ProguardRules.h
+++ b/tools/aapt2/java/ProguardRules.h
@@ -26,8 +26,8 @@
#include "ResourceTable.h"
#include "ValueVisitor.h"
#include "androidfw/Source.h"
+#include "androidfw/Streams.h"
#include "androidfw/StringPiece.h"
-#include "io/Io.h"
#include "process/IResourceTableConsumer.h"
#include "xml/XmlDom.h"
@@ -69,7 +69,7 @@
}
private:
- friend void WriteKeepSet(const KeepSet& keep_set, io::OutputStream* out, bool minimal_keep,
+ friend void WriteKeepSet(const KeepSet& keep_set, android::OutputStream* out, bool minimal_keep,
bool no_location_reference);
friend bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set,
@@ -89,7 +89,7 @@
bool CollectResourceReferences(IAaptContext* context, ResourceTable* table, KeepSet* keep_set);
-void WriteKeepSet(const KeepSet& keep_set, io::OutputStream* out, bool minimal_keep,
+void WriteKeepSet(const KeepSet& keep_set, android::OutputStream* out, bool minimal_keep,
bool no_location_reference);
bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set,
diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h
index e48668c..0437980 100644
--- a/tools/aapt2/test/Common.h
+++ b/tools/aapt2/test/Common.h
@@ -90,7 +90,7 @@
return {};
}
- std::unique_ptr<io::InputStream> OpenInputStream() override {
+ std::unique_ptr<android::InputStream> OpenInputStream() override {
return OpenAsData();
}
diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp
index 428372f..b91abe5 100644
--- a/tools/aapt2/test/Fixture.cpp
+++ b/tools/aapt2/test/Fixture.cpp
@@ -20,6 +20,7 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/utf8.h>
+#include <androidfw/FileStream.h>
#include <androidfw/StringPiece.h>
#include <dirent.h>
#include <gmock/gmock.h>
@@ -28,7 +29,6 @@
#include "Diagnostics.h"
#include "cmd/Compile.h"
#include "cmd/Link.h"
-#include "io/FileStream.h"
#include "util/Files.h"
using testing::Eq;
diff --git a/tools/aapt2/text/Printer.cpp b/tools/aapt2/text/Printer.cpp
index 8e491ac..c2fa8cc 100644
--- a/tools/aapt2/text/Printer.cpp
+++ b/tools/aapt2/text/Printer.cpp
@@ -20,7 +20,7 @@
#include "io/Util.h"
-using ::aapt::io::OutputStream;
+using ::android::OutputStream;
using ::android::StringPiece;
namespace aapt {
diff --git a/tools/aapt2/text/Printer.h b/tools/aapt2/text/Printer.h
index f7ad98b..44f0fc5 100644
--- a/tools/aapt2/text/Printer.h
+++ b/tools/aapt2/text/Printer.h
@@ -18,17 +18,16 @@
#define AAPT_TEXT_PRINTER_H
#include "android-base/macros.h"
+#include "androidfw/Streams.h"
#include "androidfw/StringPiece.h"
-#include "io/Io.h"
-
namespace aapt {
namespace text {
// An indenting Printer that helps write formatted text to the OutputStream.
class Printer {
public:
- explicit Printer(::aapt::io::OutputStream* out) : out_(out) {
+ explicit Printer(android::OutputStream* out) : out_(out) {
}
Printer& Print(android::StringPiece str);
@@ -41,7 +40,7 @@
private:
DISALLOW_COPY_AND_ASSIGN(Printer);
- ::aapt::io::OutputStream* out_;
+ android::OutputStream* out_;
int indent_level_ = 0;
bool needs_indent_ = false;
bool error_ = false;
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index 8dea8ea..49807db 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -30,7 +30,7 @@
#include "XmlPullParser.h"
#include "util/Util.h"
-using ::aapt::io::InputStream;
+using ::android::InputStream;
using ::android::StringPiece;
using ::android::StringPiece16;
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index c253b0a..9668b6a6 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -24,8 +24,8 @@
#include "Resource.h"
#include "ResourceValues.h"
#include "androidfw/IDiagnostics.h"
+#include "androidfw/Streams.h"
#include "androidfw/StringPiece.h"
-#include "io/Io.h"
#include "util/Util.h"
#include "xml/XmlUtil.h"
@@ -152,7 +152,7 @@
};
// Inflates an XML DOM from an InputStream, logging errors to the logger.
-std::unique_ptr<XmlResource> Inflate(io::InputStream* in, android::IDiagnostics* diag,
+std::unique_ptr<XmlResource> Inflate(android::InputStream* in, android::IDiagnostics* diag,
const android::Source& source);
// Inflates an XML DOM from a binary ResXMLTree.
diff --git a/tools/aapt2/xml/XmlPullParser.cpp b/tools/aapt2/xml/XmlPullParser.cpp
index d79446b..203832d 100644
--- a/tools/aapt2/xml/XmlPullParser.cpp
+++ b/tools/aapt2/xml/XmlPullParser.cpp
@@ -21,7 +21,7 @@
#include "xml/XmlPullParser.h"
#include "xml/XmlUtil.h"
-using ::aapt::io::InputStream;
+using ::android::InputStream;
using ::android::StringPiece;
namespace aapt {
diff --git a/tools/aapt2/xml/XmlPullParser.h b/tools/aapt2/xml/XmlPullParser.h
index fe4cd01..655e6dc 100644
--- a/tools/aapt2/xml/XmlPullParser.h
+++ b/tools/aapt2/xml/XmlPullParser.h
@@ -27,11 +27,10 @@
#include <string>
#include <vector>
-#include "android-base/macros.h"
-#include "androidfw/StringPiece.h"
-
#include "Resource.h"
-#include "io/Io.h"
+#include "android-base/macros.h"
+#include "androidfw/Streams.h"
+#include "androidfw/StringPiece.h"
#include "process/IResourceTableConsumer.h"
#include "xml/XmlUtil.h"
@@ -66,7 +65,7 @@
static bool SkipCurrentElement(XmlPullParser* parser);
static bool IsGoodEvent(Event event);
- explicit XmlPullParser(io::InputStream* in);
+ explicit XmlPullParser(android::InputStream* in);
~XmlPullParser();
/**
@@ -179,7 +178,7 @@
std::vector<Attribute> attributes;
};
- io::InputStream* in_;
+ android::InputStream* in_;
XML_Parser parser_;
std::queue<EventData> event_queue_;
std::string error_;