• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <androidfw/TypeWrappers.h>
18 
19 namespace android {
20 
TypeVariant(const ResTable_type * data)21 TypeVariant::TypeVariant(const ResTable_type* data)
22     : data(data)
23     , mLength(dtohl(data->entryCount))
24     , mSparse(data->flags & ResTable_type::FLAG_SPARSE) {
25     if (mSparse) {
26         const uint32_t entryCount = dtohl(data->entryCount);
27         const uintptr_t containerEnd = reinterpret_cast<uintptr_t>(data) + dtohl(data->header.size);
28         const uint32_t* const entryIndices = reinterpret_cast<const uint32_t*>(
29                 reinterpret_cast<uintptr_t>(data) + dtohs(data->header.headerSize));
30         if (reinterpret_cast<uintptr_t>(entryIndices) + (sizeof(uint32_t) * entryCount)
31                 > containerEnd) {
32             ALOGE("Type's entry indices extend beyond its boundaries");
33             mLength = 0;
34         } else {
35           mLength = dtohs(ResTable_sparseTypeEntry{entryIndices[entryCount - 1]}.idx) + 1;
36         }
37     }
38 }
39 
operator ++()40 TypeVariant::iterator& TypeVariant::iterator::operator++() {
41     ++mIndex;
42     if (mIndex > mTypeVariant->mLength) {
43         mIndex = mTypeVariant->mLength;
44     }
45 
46     if (!mTypeVariant->mSparse) {
47       return *this;
48     }
49 
50     // Need to adjust |mSparseIndex| as well if we've passed its current element.
51     const ResTable_type* type = mTypeVariant->data;
52     const uint32_t entryCount = dtohl(type->entryCount);
53     if (mSparseIndex >= entryCount) {
54       return *this; // done
55     }
56     const auto entryIndices = reinterpret_cast<const uint32_t*>(
57         reinterpret_cast<uintptr_t>(type) + dtohs(type->header.headerSize));
58     const auto element = (const ResTable_sparseTypeEntry*)(entryIndices + mSparseIndex);
59     if (mIndex > dtohs(element->idx)) {
60       ++mSparseIndex;
61     }
62 
63     return *this;
64 }
65 
operator *() const66 const ResTable_entry* TypeVariant::iterator::operator*() const {
67     if (mIndex >= mTypeVariant->mLength) {
68         return nullptr;
69     }
70 
71     const ResTable_type* type = mTypeVariant->data;
72     const uint32_t entryCount = dtohl(type->entryCount);
73     const uintptr_t containerEnd = reinterpret_cast<uintptr_t>(type)
74             + dtohl(type->header.size);
75     const uint32_t* const entryIndices = reinterpret_cast<const uint32_t*>(
76             reinterpret_cast<uintptr_t>(type) + dtohs(type->header.headerSize));
77     const size_t indexSize = type->flags & ResTable_type::FLAG_OFFSET16 ?
78                                     sizeof(uint16_t) : sizeof(uint32_t);
79     if (reinterpret_cast<uintptr_t>(entryIndices) + (indexSize * entryCount) > containerEnd) {
80         ALOGE("Type's entry indices extend beyond its boundaries");
81         return nullptr;
82     }
83 
84     uint32_t entryOffset;
85     if (mTypeVariant->mSparse) {
86       if (mSparseIndex >= entryCount) {
87         return nullptr;
88       }
89       const auto element = (const ResTable_sparseTypeEntry*)(entryIndices + mSparseIndex);
90       if (dtohs(element->idx) != mIndex) {
91         return nullptr;
92       }
93       entryOffset = static_cast<uint32_t>(dtohs(element->offset)) * 4u;
94     } else if (type->flags & ResTable_type::FLAG_OFFSET16) {
95       auto entryIndices16 = reinterpret_cast<const uint16_t*>(entryIndices);
96       entryOffset = offset_from16(entryIndices16[mIndex]);
97     } else {
98       entryOffset = dtohl(entryIndices[mIndex]);
99     }
100 
101     if (entryOffset == ResTable_type::NO_ENTRY) {
102         return nullptr;
103     }
104 
105     if ((entryOffset & 0x3) != 0) {
106         ALOGE("Index %u points to entry with unaligned offset 0x%08x", mIndex, entryOffset);
107         return nullptr;
108     }
109 
110     const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(
111             reinterpret_cast<uintptr_t>(type) + dtohl(type->entriesStart) + entryOffset);
112     if (reinterpret_cast<uintptr_t>(entry) > containerEnd - sizeof(*entry)) {
113         ALOGE("Entry offset at index %u points outside the Type's boundaries", mIndex);
114         return nullptr;
115     } else if (reinterpret_cast<uintptr_t>(entry) + entry->size() > containerEnd) {
116         ALOGE("Entry at index %u extends beyond Type's boundaries", mIndex);
117         return nullptr;
118     } else if (entry->size() < sizeof(*entry)) {
119         ALOGE("Entry at index %u is too small (%zu)", mIndex, entry->size());
120         return nullptr;
121     }
122     return entry;
123 }
124 
125 } // namespace android
126