diff --git a/tools/aapt2/format/Container.cpp b/tools/aapt2/format/Container.cpp index f1890488276c..9cef7b3d2ce3 100644 --- a/tools/aapt2/format/Container.cpp +++ b/tools/aapt2/format/Container.cpp @@ -30,6 +30,7 @@ namespace aapt { constexpr const static uint32_t kContainerFormatMagic = 0x54504141u; constexpr const static uint32_t kContainerFormatVersion = 1u; +constexpr const static size_t kPaddingAlignment = 4u; ContainerWriter::ContainerWriter(ZeroCopyOutputStream* out, size_t entry_count) : out_(out), total_entry_count_(entry_count), current_entry_count_(0u) { @@ -49,11 +50,17 @@ ContainerWriter::ContainerWriter(ZeroCopyOutputStream* out, size_t entry_count) } } -inline static void WritePadding(int padding, CodedOutputStream* out) { - if (padding < 4) { - const uint32_t zero = 0u; - out->WriteRaw(&zero, padding); - } +inline static size_t CalculatePaddingForAlignment(size_t size) { + size_t overage = size % kPaddingAlignment; + return overage == 0 ? 0 : kPaddingAlignment - overage; +} + +inline static void WritePadding(size_t padding, CodedOutputStream* out) { + CHECK(padding < kPaddingAlignment); + const uint32_t zero = 0u; + static_assert(sizeof(zero) >= kPaddingAlignment, "Not enough source bytes for padding"); + + out->WriteRaw(&zero, padding); } bool ContainerWriter::AddResTableEntry(const pb::ResourceTable& table) { @@ -70,7 +77,7 @@ bool ContainerWriter::AddResTableEntry(const pb::ResourceTable& table) { // Write the aligned size. const ::google::protobuf::uint64 size = table.ByteSize(); - const int padding = 4 - (size % 4); + const int padding = CalculatePaddingForAlignment(size); coded_out.WriteLittleEndian64(size); // Write the table. @@ -103,9 +110,9 @@ bool ContainerWriter::AddResFileEntry(const pb::internal::CompiledFile& file, // Write the aligned size. const ::google::protobuf::uint32 header_size = file.ByteSize(); - const int header_padding = 4 - (header_size % 4); + const int header_padding = CalculatePaddingForAlignment(header_size); const ::google::protobuf::uint64 data_size = in->TotalSize(); - const int data_padding = 4 - (data_size % 4); + const int data_padding = CalculatePaddingForAlignment(data_size); coded_out.WriteLittleEndian64(kResFileEntryHeaderSize + header_size + header_padding + data_size + data_padding); diff --git a/tools/aapt2/formats.md b/tools/aapt2/formats.md index bb31a005ef42..25a0e798dea2 100644 --- a/tools/aapt2/formats.md +++ b/tools/aapt2/formats.md @@ -23,7 +23,7 @@ boundary, so if a previous entry ends unaligned, padding must be inserted. | Size (in bytes) | Field | Description | |:----------------|:---------------|:----------------------------------------------------------------------------------------------------------| | `4` | `entry_type` | The type of the entry. This can be one of two types: `RES_TABLE (0x00000000)` or `RES_FILE (0x00000001)`. | -| `8` | `entry_length` | The length of the data that follows. | +| `8` | `entry_length` | The length of the data that follows. Do not use if `entry_type` is `RES_FILE`; this value may be wrong. | | `entry_length` | `data` | The payload. The contents of this varies based on the `entry_type`. | If the `entry_type` is equal to `RES_TABLE (0x00000000)`, the `data` field contains a serialized @@ -32,13 +32,14 @@ If the `entry_type` is equal to `RES_TABLE (0x00000000)`, the `data` field conta If the `entry_type` is equal to `RES_FILE (0x00000001)`, the `data` field contains the following: -| Size (in bytes) | Field | Description | -|:----------------|:---------------|:----------------------------------------------------------------------------------------------------------| -| `4` | `header_size` | The size of the `header` field. | -| `8` | `data_size` | The size of the `data` field. | -| `header_size` | `header` | The serialized Protobuf message [aapt.pb.internal.CompiledFile](ResourcesInternal.proto). | -| `x` | `padding` | Up to 4 bytes of zeros, if padding is necessary to align the `data` field on a 32-bit boundary. | -| `data_size` | `data` | The payload, which is determined by the `type` field in the `aapt.pb.internal.CompiledFile`. This can be a PNG file, binary XML, or [aapt.pb.XmlNode](Resources.proto). | +| Size (in bytes) | Field | Description | +|:----------------|:-----------------|:----------------------------------------------------------------------------------------------------------| +| `4` | `header_size` | The size of the `header` field. | +| `8` | `data_size` | The size of the `data` field. | +| `header_size` | `header` | The serialized Protobuf message [aapt.pb.internal.CompiledFile](ResourcesInternal.proto). | +| `x` | `header_padding` | Up to 3 bytes of zeros, if padding is necessary to align the `data` field on a 32-bit boundary. | +| `data_size` | `data` | The payload, which is determined by the `type` field in the `aapt.pb.internal.CompiledFile`. This can be a PNG file, binary XML, or [aapt.pb.XmlNode](Resources.proto). | +| `y` | `data_padding` | Up to 3 bytes of zeros, if `data_size` is not a multiple of 4. | ## AAPT2 Static Library Format (extension `.sapk`)