1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <algorithm>
18 #include <androidfw/ResourceTypes.h>
19 #include <androidfw/TypeWrappers.h>
20 #include <utils/String8.h>
21
22 #include <gtest/gtest.h>
23
24 namespace android {
25
26 // create a ResTable_type in memory with a vector of Res_value*
createTypeTable(std::vector<Res_value * > & values,bool compact_entry=false,bool short_offsets=false)27 static ResTable_type* createTypeTable(std::vector<Res_value*>& values,
28 bool compact_entry = false,
29 bool short_offsets = false)
30 {
31 ResTable_type t{};
32 t.header.type = RES_TABLE_TYPE_TYPE;
33 t.header.headerSize = sizeof(t);
34 t.header.size = sizeof(t);
35 t.id = 1;
36 t.flags = short_offsets ? ResTable_type::FLAG_OFFSET16 : 0;
37
38 t.header.size += values.size() * (short_offsets ? sizeof(uint16_t) : sizeof(uint32_t));
39 t.entriesStart = t.header.size;
40 t.entryCount = values.size();
41
42 size_t entry_size = compact_entry ? sizeof(ResTable_entry)
43 : sizeof(ResTable_entry) + sizeof(Res_value);
44 for (auto const v : values) {
45 t.header.size += v ? entry_size : 0;
46 }
47
48 uint8_t* data = (uint8_t *)malloc(t.header.size);
49 uint8_t* p_header = data;
50 uint8_t* p_offsets = data + t.header.headerSize;
51 uint8_t* p_entries = data + t.entriesStart;
52
53 memcpy(p_header, &t, sizeof(t));
54
55 size_t i = 0, entry_offset = 0;
56 uint32_t k = 0;
57 for (auto const& v : values) {
58 if (short_offsets) {
59 uint16_t *p = reinterpret_cast<uint16_t *>(p_offsets) + i;
60 *p = v ? (entry_offset >> 2) & 0xffffu : 0xffffu;
61 } else {
62 uint32_t *p = reinterpret_cast<uint32_t *>(p_offsets) + i;
63 *p = v ? entry_offset : ResTable_type::NO_ENTRY;
64 }
65
66 if (v) {
67 ResTable_entry entry{};
68 if (compact_entry) {
69 entry.compact.key = i;
70 entry.compact.flags = ResTable_entry::FLAG_COMPACT | (v->dataType << 8);
71 entry.compact.data = v->data;
72 memcpy(p_entries, &entry, sizeof(entry)); p_entries += sizeof(entry);
73 entry_offset += sizeof(entry);
74 } else {
75 Res_value value{};
76 entry.full.size = sizeof(entry);
77 entry.full.key.index = i;
78 value = *v;
79 memcpy(p_entries, &entry, sizeof(entry)); p_entries += sizeof(entry);
80 memcpy(p_entries, &value, sizeof(value)); p_entries += sizeof(value);
81 entry_offset += sizeof(entry) + sizeof(value);
82 }
83 }
84 i++;
85 }
86 return reinterpret_cast<ResTable_type*>(data);
87 }
88
TEST(TypeVariantIteratorTest,shouldIterateOverTypeWithoutErrors)89 TEST(TypeVariantIteratorTest, shouldIterateOverTypeWithoutErrors) {
90 std::vector<Res_value *> values;
91
92 Res_value *v1 = new Res_value{};
93 values.push_back(v1);
94
95 values.push_back(nullptr);
96
97 Res_value *v2 = new Res_value{};
98 values.push_back(v2);
99
100 Res_value *v3 = new Res_value{ sizeof(Res_value), 0, Res_value::TYPE_STRING, 0x12345678};
101 values.push_back(v3);
102
103 // test for combinations of compact_entry and short_offsets
104 for (size_t i = 0; i < 4; i++) {
105 bool compact_entry = i & 0x1, short_offsets = i & 0x2;
106 ResTable_type* data = createTypeTable(values, compact_entry, short_offsets);
107 TypeVariant v(data);
108
109 TypeVariant::iterator iter = v.beginEntries();
110 ASSERT_EQ(uint32_t(0), iter.index());
111 ASSERT_TRUE(NULL != *iter);
112 ASSERT_EQ(uint32_t(0), iter->key());
113 ASSERT_NE(v.endEntries(), iter);
114
115 iter++;
116
117 ASSERT_EQ(uint32_t(1), iter.index());
118 ASSERT_TRUE(NULL == *iter);
119 ASSERT_NE(v.endEntries(), iter);
120
121 iter++;
122
123 ASSERT_EQ(uint32_t(2), iter.index());
124 ASSERT_TRUE(NULL != *iter);
125 ASSERT_EQ(uint32_t(2), iter->key());
126 ASSERT_NE(v.endEntries(), iter);
127
128 iter++;
129
130 ASSERT_EQ(uint32_t(3), iter.index());
131 ASSERT_TRUE(NULL != *iter);
132 ASSERT_EQ(iter->is_compact(), compact_entry);
133 ASSERT_EQ(uint32_t(3), iter->key());
134 ASSERT_EQ(uint32_t(0x12345678), iter->value().data);
135 ASSERT_EQ(Res_value::TYPE_STRING, iter->value().dataType);
136
137 iter++;
138
139 ASSERT_EQ(v.endEntries(), iter);
140
141 free(data);
142 }
143 }
144
145 } // namespace android
146