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