Merge "androidfw: Add tests for compact entries/short offsets"
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <androidfw/ResourceTypes.h>
|
||||
#include <androidfw/TypeWrappers.h>
|
||||
#include <utils/String8.h>
|
||||
@@ -22,88 +23,123 @@
|
||||
|
||||
namespace android {
|
||||
|
||||
void* createTypeData() {
|
||||
ResTable_type t;
|
||||
memset(&t, 0, sizeof(t));
|
||||
// create a ResTable_type in memory with a vector of Res_value*
|
||||
static ResTable_type* createTypeTable(std::vector<Res_value*>& values,
|
||||
bool compact_entry = false,
|
||||
bool short_offsets = false)
|
||||
{
|
||||
ResTable_type t{};
|
||||
t.header.type = RES_TABLE_TYPE_TYPE;
|
||||
t.header.headerSize = sizeof(t);
|
||||
t.header.size = sizeof(t);
|
||||
t.id = 1;
|
||||
t.entryCount = 3;
|
||||
t.flags = short_offsets ? ResTable_type::FLAG_OFFSET16 : 0;
|
||||
|
||||
uint32_t offsets[3];
|
||||
t.entriesStart = t.header.headerSize + sizeof(offsets);
|
||||
t.header.size = t.entriesStart;
|
||||
t.header.size += values.size() * (short_offsets ? sizeof(uint16_t) : sizeof(uint32_t));
|
||||
t.entriesStart = t.header.size;
|
||||
t.entryCount = values.size();
|
||||
|
||||
offsets[0] = 0;
|
||||
ResTable_entry e1;
|
||||
memset(&e1, 0, sizeof(e1));
|
||||
e1.full.size = sizeof(e1);
|
||||
e1.full.key.index = 0;
|
||||
t.header.size += sizeof(e1);
|
||||
size_t entry_size = compact_entry ? sizeof(ResTable_entry)
|
||||
: sizeof(ResTable_entry) + sizeof(Res_value);
|
||||
for (auto const v : values) {
|
||||
t.header.size += v ? entry_size : 0;
|
||||
}
|
||||
|
||||
Res_value v1;
|
||||
memset(&v1, 0, sizeof(v1));
|
||||
t.header.size += sizeof(v1);
|
||||
uint8_t* data = (uint8_t *)malloc(t.header.size);
|
||||
uint8_t* p_header = data;
|
||||
uint8_t* p_offsets = data + t.header.headerSize;
|
||||
uint8_t* p_entries = data + t.entriesStart;
|
||||
|
||||
offsets[1] = ResTable_type::NO_ENTRY;
|
||||
memcpy(p_header, &t, sizeof(t));
|
||||
|
||||
offsets[2] = sizeof(e1) + sizeof(v1);
|
||||
ResTable_entry e2;
|
||||
memset(&e2, 0, sizeof(e2));
|
||||
e2.full.size = sizeof(e2);
|
||||
e2.full.key.index = 1;
|
||||
t.header.size += sizeof(e2);
|
||||
size_t i = 0, entry_offset = 0;
|
||||
uint32_t k = 0;
|
||||
for (auto const& v : values) {
|
||||
if (short_offsets) {
|
||||
uint16_t *p = reinterpret_cast<uint16_t *>(p_offsets) + i;
|
||||
*p = v ? (entry_offset >> 2) & 0xffffu : 0xffffu;
|
||||
} else {
|
||||
uint32_t *p = reinterpret_cast<uint32_t *>(p_offsets) + i;
|
||||
*p = v ? entry_offset : ResTable_type::NO_ENTRY;
|
||||
}
|
||||
|
||||
Res_value v2;
|
||||
memset(&v2, 0, sizeof(v2));
|
||||
t.header.size += sizeof(v2);
|
||||
|
||||
uint8_t* data = (uint8_t*)malloc(t.header.size);
|
||||
uint8_t* p = data;
|
||||
memcpy(p, &t, sizeof(t));
|
||||
p += sizeof(t);
|
||||
memcpy(p, offsets, sizeof(offsets));
|
||||
p += sizeof(offsets);
|
||||
memcpy(p, &e1, sizeof(e1));
|
||||
p += sizeof(e1);
|
||||
memcpy(p, &v1, sizeof(v1));
|
||||
p += sizeof(v1);
|
||||
memcpy(p, &e2, sizeof(e2));
|
||||
p += sizeof(e2);
|
||||
memcpy(p, &v2, sizeof(v2));
|
||||
p += sizeof(v2);
|
||||
return data;
|
||||
if (v) {
|
||||
ResTable_entry entry{};
|
||||
if (compact_entry) {
|
||||
entry.compact.key = i;
|
||||
entry.compact.flags = ResTable_entry::FLAG_COMPACT | (v->dataType << 8);
|
||||
entry.compact.data = v->data;
|
||||
memcpy(p_entries, &entry, sizeof(entry)); p_entries += sizeof(entry);
|
||||
entry_offset += sizeof(entry);
|
||||
} else {
|
||||
Res_value value{};
|
||||
entry.full.size = sizeof(entry);
|
||||
entry.full.key.index = i;
|
||||
value = *v;
|
||||
memcpy(p_entries, &entry, sizeof(entry)); p_entries += sizeof(entry);
|
||||
memcpy(p_entries, &value, sizeof(value)); p_entries += sizeof(value);
|
||||
entry_offset += sizeof(entry) + sizeof(value);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return reinterpret_cast<ResTable_type*>(data);
|
||||
}
|
||||
|
||||
TEST(TypeVariantIteratorTest, shouldIterateOverTypeWithoutErrors) {
|
||||
ResTable_type* data = (ResTable_type*) createTypeData();
|
||||
std::vector<Res_value *> values;
|
||||
|
||||
TypeVariant v(data);
|
||||
Res_value *v1 = new Res_value{};
|
||||
values.push_back(v1);
|
||||
|
||||
TypeVariant::iterator iter = v.beginEntries();
|
||||
ASSERT_EQ(uint32_t(0), iter.index());
|
||||
ASSERT_TRUE(NULL != *iter);
|
||||
ASSERT_EQ(uint32_t(0), iter->full.key.index);
|
||||
ASSERT_NE(v.endEntries(), iter);
|
||||
values.push_back(nullptr);
|
||||
|
||||
iter++;
|
||||
Res_value *v2 = new Res_value{};
|
||||
values.push_back(v2);
|
||||
|
||||
ASSERT_EQ(uint32_t(1), iter.index());
|
||||
ASSERT_TRUE(NULL == *iter);
|
||||
ASSERT_NE(v.endEntries(), iter);
|
||||
Res_value *v3 = new Res_value{ sizeof(Res_value), 0, Res_value::TYPE_STRING, 0x12345678};
|
||||
values.push_back(v3);
|
||||
|
||||
iter++;
|
||||
// test for combinations of compact_entry and short_offsets
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
bool compact_entry = i & 0x1, short_offsets = i & 0x2;
|
||||
ResTable_type* data = createTypeTable(values, compact_entry, short_offsets);
|
||||
TypeVariant v(data);
|
||||
|
||||
ASSERT_EQ(uint32_t(2), iter.index());
|
||||
ASSERT_TRUE(NULL != *iter);
|
||||
ASSERT_EQ(uint32_t(1), iter->full.key.index);
|
||||
ASSERT_NE(v.endEntries(), iter);
|
||||
TypeVariant::iterator iter = v.beginEntries();
|
||||
ASSERT_EQ(uint32_t(0), iter.index());
|
||||
ASSERT_TRUE(NULL != *iter);
|
||||
ASSERT_EQ(uint32_t(0), iter->key());
|
||||
ASSERT_NE(v.endEntries(), iter);
|
||||
|
||||
iter++;
|
||||
iter++;
|
||||
|
||||
ASSERT_EQ(v.endEntries(), iter);
|
||||
ASSERT_EQ(uint32_t(1), iter.index());
|
||||
ASSERT_TRUE(NULL == *iter);
|
||||
ASSERT_NE(v.endEntries(), iter);
|
||||
|
||||
free(data);
|
||||
iter++;
|
||||
|
||||
ASSERT_EQ(uint32_t(2), iter.index());
|
||||
ASSERT_TRUE(NULL != *iter);
|
||||
ASSERT_EQ(uint32_t(2), iter->key());
|
||||
ASSERT_NE(v.endEntries(), iter);
|
||||
|
||||
iter++;
|
||||
|
||||
ASSERT_EQ(uint32_t(3), iter.index());
|
||||
ASSERT_TRUE(NULL != *iter);
|
||||
ASSERT_EQ(iter->is_compact(), compact_entry);
|
||||
ASSERT_EQ(uint32_t(3), iter->key());
|
||||
ASSERT_EQ(uint32_t(0x12345678), iter->value().data);
|
||||
ASSERT_EQ(Res_value::TYPE_STRING, iter->value().dataType);
|
||||
|
||||
iter++;
|
||||
|
||||
ASSERT_EQ(v.endEntries(), iter);
|
||||
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
||||
Reference in New Issue
Block a user