AAPT2: Add Inline Complex XML support

See: https://developer.android.com/guide/topics/resources/complex-xml-resources.html

Change-Id: I8274c85e25cabf90423141c228697e873167d136
diff --git a/tools/aapt2/proto/TableProtoSerializer.cpp b/tools/aapt2/proto/TableProtoSerializer.cpp
index 425fca6..a5c2cbc 100644
--- a/tools/aapt2/proto/TableProtoSerializer.cpp
+++ b/tools/aapt2/proto/TableProtoSerializer.cpp
@@ -22,6 +22,10 @@
 #include "proto/ProtoSerialize.h"
 #include "util/BigBuffer.h"
 
+using google::protobuf::io::CodedOutputStream;
+using google::protobuf::io::CodedInputStream;
+using google::protobuf::io::ZeroCopyOutputStream;
+
 namespace aapt {
 
 namespace {
@@ -210,7 +214,7 @@
     });
     table->stringPool.prune();
 
-    std::unique_ptr<pb::ResourceTable> pbTable = util::make_unique<pb::ResourceTable>();
+    auto pbTable = util::make_unique<pb::ResourceTable>();
     serializeStringPoolToPb(table->stringPool, pbTable->mutable_string_pool());
 
     StringPool sourcePool, symbolPool;
@@ -274,7 +278,7 @@
 }
 
 std::unique_ptr<pb::CompiledFile> serializeCompiledFileToPb(const ResourceFile& file) {
-    std::unique_ptr<pb::CompiledFile> pbFile = util::make_unique<pb::CompiledFile>();
+    auto pbFile = util::make_unique<pb::CompiledFile>();
     pbFile->set_resource_name(file.name.toString());
     pbFile->set_source_path(file.source.path);
     serializeConfig(file.config, pbFile->mutable_config());
@@ -287,36 +291,112 @@
     return pbFile;
 }
 
-CompiledFileOutputStream::CompiledFileOutputStream(google::protobuf::io::ZeroCopyOutputStream* out,
-                                                   pb::CompiledFile* pbFile) :
-        mOut(out), mPbFile(pbFile) {
+CompiledFileOutputStream::CompiledFileOutputStream(ZeroCopyOutputStream* out) : mOut(out) {
 }
 
-bool CompiledFileOutputStream::ensureFileWritten() {
-    if (mPbFile) {
-        const uint64_t pbSize = mPbFile->ByteSize();
-        mOut.WriteLittleEndian64(pbSize);
-        mPbFile->SerializeWithCachedSizes(&mOut);
-        const size_t padding = 4 - (pbSize & 0x03);
-        if (padding > 0) {
-            uint32_t zero = 0u;
-            mOut.WriteRaw(&zero, padding);
-        }
-        mPbFile = nullptr;
+void CompiledFileOutputStream::ensureAlignedWrite() {
+    const int padding = mOut.ByteCount() % 4;
+    if (padding > 0) {
+        uint32_t zero = 0u;
+        mOut.WriteRaw(&zero, padding);
     }
-    return !mOut.HadError();
 }
 
-bool CompiledFileOutputStream::Write(const void* data, int size) {
-    if (!ensureFileWritten()) {
+void CompiledFileOutputStream::WriteLittleEndian32(uint32_t val) {
+    ensureAlignedWrite();
+    mOut.WriteLittleEndian32(val);
+}
+
+void CompiledFileOutputStream::WriteCompiledFile(const pb::CompiledFile* compiledFile) {
+    ensureAlignedWrite();
+    mOut.WriteLittleEndian64(static_cast<uint64_t>(compiledFile->ByteSize()));
+    compiledFile->SerializeWithCachedSizes(&mOut);
+}
+
+void CompiledFileOutputStream::WriteData(const BigBuffer* buffer) {
+    ensureAlignedWrite();
+    mOut.WriteLittleEndian64(static_cast<uint64_t>(buffer->size()));
+    for (const BigBuffer::Block& block : *buffer) {
+        mOut.WriteRaw(block.buffer.get(), block.size);
+    }
+}
+
+void CompiledFileOutputStream::WriteData(const void* data, size_t len) {
+    ensureAlignedWrite();
+    mOut.WriteLittleEndian64(static_cast<uint64_t>(len));
+    mOut.WriteRaw(data, len);
+}
+
+bool CompiledFileOutputStream::HadError() {
+    return mOut.HadError();
+}
+
+CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size) :
+        mIn(static_cast<const uint8_t*>(data), size) {
+}
+
+void CompiledFileInputStream::ensureAlignedRead() {
+    const int padding = mIn.CurrentPosition() % 4;
+    if (padding > 0) {
+        // Reads are always 4 byte aligned.
+        mIn.Skip(padding);
+    }
+}
+
+bool CompiledFileInputStream::ReadLittleEndian32(uint32_t* outVal) {
+    ensureAlignedRead();
+    return mIn.ReadLittleEndian32(outVal);
+}
+
+bool CompiledFileInputStream::ReadCompiledFile(pb::CompiledFile* outVal) {
+    ensureAlignedRead();
+
+    uint64_t pbSize = 0u;
+    if (!mIn.ReadLittleEndian64(&pbSize)) {
         return false;
     }
-    mOut.WriteRaw(data, size);
-    return !mOut.HadError();
+
+    CodedInputStream::Limit l = mIn.PushLimit(static_cast<int>(pbSize));
+
+    // Check that we haven't tried to read past the end.
+    if (static_cast<uint64_t>(mIn.BytesUntilLimit()) != pbSize) {
+        mIn.PopLimit(l);
+        mIn.PushLimit(0);
+        return false;
+    }
+
+    if (!outVal->ParsePartialFromCodedStream(&mIn)) {
+        mIn.PopLimit(l);
+        mIn.PushLimit(0);
+        return false;
+    }
+
+    mIn.PopLimit(l);
+    return true;
 }
 
-bool CompiledFileOutputStream::Finish() {
-    return ensureFileWritten();
+bool CompiledFileInputStream::ReadDataMetaData(uint64_t* outOffset, uint64_t* outLen) {
+    ensureAlignedRead();
+
+    uint64_t pbSize = 0u;
+    if (!mIn.ReadLittleEndian64(&pbSize)) {
+        return false;
+    }
+
+    // Check that we aren't trying to read past the end.
+    if (pbSize > static_cast<uint64_t>(mIn.BytesUntilLimit())) {
+        mIn.PushLimit(0);
+        return false;
+    }
+
+    uint64_t offset = static_cast<uint64_t>(mIn.CurrentPosition());
+    if (!mIn.Skip(pbSize)) {
+        return false;
+    }
+
+    *outOffset = offset;
+    *outLen = pbSize;
+    return true;
 }
 
 } // namespace aapt