1f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski/*
2f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski * Copyright (C) 2014 The Android Open Source Project
3f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski *
4f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
5f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski * you may not use this file except in compliance with the License.
6f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski * You may obtain a copy of the License at
7f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski *
8f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
9f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski *
10f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski * Unless required by applicable law or agreed to in writing, software
11f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
12f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski * See the License for the specific language governing permissions and
14f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski * limitations under the License.
15f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski */
16f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
17f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski#include <androidfw/TypeWrappers.h>
18f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
19c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski#include <algorithm>
20c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski
21f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinskinamespace android {
22f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
23c8f71aa67ea599cb80205496cb67e9e7a121299cAdam LesinskiTypeVariant::TypeVariant(const ResTable_type* data) : data(data), mLength(dtohl(data->entryCount)) {
24c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    if (data->flags & ResTable_type::FLAG_SPARSE) {
25c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        const uint32_t entryCount = dtohl(data->entryCount);
26c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        const uintptr_t containerEnd = reinterpret_cast<uintptr_t>(data) + dtohl(data->header.size);
27c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        const uint32_t* const entryIndices = reinterpret_cast<const uint32_t*>(
28c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski                reinterpret_cast<uintptr_t>(data) + dtohs(data->header.headerSize));
29c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        if (reinterpret_cast<uintptr_t>(entryIndices) + (sizeof(uint32_t) * entryCount)
30c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski                > containerEnd) {
31c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski            ALOGE("Type's entry indices extend beyond its boundaries");
32c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski            mLength = 0;
33c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        } else {
34c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski          mLength = ResTable_sparseTypeEntry{entryIndices[entryCount - 1]}.idx + 1;
35c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        }
36c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    }
37c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski}
38c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski
39f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam LesinskiTypeVariant::iterator& TypeVariant::iterator::operator++() {
40f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    mIndex++;
41c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    if (mIndex > mTypeVariant->mLength) {
42c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        mIndex = mTypeVariant->mLength;
43f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    }
44f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    return *this;
45f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski}
46f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
47c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinskistatic bool keyCompare(uint32_t entry, uint16_t index) {
48c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski  return dtohs(ResTable_sparseTypeEntry{entry}.idx) < index;
49c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski}
50c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski
51f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinskiconst ResTable_entry* TypeVariant::iterator::operator*() const {
52f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    const ResTable_type* type = mTypeVariant->data;
53c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    if (mIndex >= mTypeVariant->mLength) {
54f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        return NULL;
55f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    }
56f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
57c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    const uint32_t entryCount = dtohl(mTypeVariant->data->entryCount);
58f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    const uintptr_t containerEnd = reinterpret_cast<uintptr_t>(type)
59f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            + dtohl(type->header.size);
60f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    const uint32_t* const entryIndices = reinterpret_cast<const uint32_t*>(
61f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            reinterpret_cast<uintptr_t>(type) + dtohs(type->header.headerSize));
62f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    if (reinterpret_cast<uintptr_t>(entryIndices) + (sizeof(uint32_t) * entryCount) > containerEnd) {
63f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        ALOGE("Type's entry indices extend beyond its boundaries");
64f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        return NULL;
65f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    }
66f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
67c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    uint32_t entryOffset;
68c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    if (type->flags & ResTable_type::FLAG_SPARSE) {
69c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      auto iter = std::lower_bound(entryIndices, entryIndices + entryCount, mIndex, keyCompare);
70c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      if (iter == entryIndices + entryCount
71c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski              || dtohs(ResTable_sparseTypeEntry{*iter}.idx) != mIndex) {
72c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        return NULL;
73c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      }
74c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski
75c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      entryOffset = static_cast<uint32_t>(dtohs(ResTable_sparseTypeEntry{*iter}.offset)) * 4u;
76c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    } else {
77c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      entryOffset = dtohl(entryIndices[mIndex]);
78c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    }
79c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski
80f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    if (entryOffset == ResTable_type::NO_ENTRY) {
81f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        return NULL;
82f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    }
83f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
84f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    if ((entryOffset & 0x3) != 0) {
85fb600d60c06192f1a5b1c09bc86f92a80894a6c1Adam Lesinski        ALOGE("Index %u points to entry with unaligned offset 0x%08x", mIndex, entryOffset);
86f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        return NULL;
87f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    }
88f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
89f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(
90f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            reinterpret_cast<uintptr_t>(type) + dtohl(type->entriesStart) + entryOffset);
91f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    if (reinterpret_cast<uintptr_t>(entry) > containerEnd - sizeof(*entry)) {
92f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        ALOGE("Entry offset at index %u points outside the Type's boundaries", mIndex);
93f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        return NULL;
94f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    } else if (reinterpret_cast<uintptr_t>(entry) + dtohs(entry->size) > containerEnd) {
95f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        ALOGE("Entry at index %u extends beyond Type's boundaries", mIndex);
96f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        return NULL;
97f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    } else if (dtohs(entry->size) < sizeof(*entry)) {
98f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        ALOGE("Entry at index %u is too small (%u)", mIndex, dtohs(entry->size));
99f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        return NULL;
100f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    }
101f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    return entry;
102f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski}
103f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
104f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski} // namespace android
105