Home | History | Annotate | Download | only in androidfw
      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 #include <algorithm>
     20 
     21 namespace android {
     22 
     23 TypeVariant::TypeVariant(const ResTable_type* data) : data(data), mLength(dtohl(data->entryCount)) {
     24     if (data->flags & ResTable_type::FLAG_SPARSE) {
     25         const uint32_t entryCount = dtohl(data->entryCount);
     26         const uintptr_t containerEnd = reinterpret_cast<uintptr_t>(data) + dtohl(data->header.size);
     27         const uint32_t* const entryIndices = reinterpret_cast<const uint32_t*>(
     28                 reinterpret_cast<uintptr_t>(data) + dtohs(data->header.headerSize));
     29         if (reinterpret_cast<uintptr_t>(entryIndices) + (sizeof(uint32_t) * entryCount)
     30                 > containerEnd) {
     31             ALOGE("Type's entry indices extend beyond its boundaries");
     32             mLength = 0;
     33         } else {
     34           mLength = ResTable_sparseTypeEntry{entryIndices[entryCount - 1]}.idx + 1;
     35         }
     36     }
     37 }
     38 
     39 TypeVariant::iterator& TypeVariant::iterator::operator++() {
     40     mIndex++;
     41     if (mIndex > mTypeVariant->mLength) {
     42         mIndex = mTypeVariant->mLength;
     43     }
     44     return *this;
     45 }
     46 
     47 static bool keyCompare(uint32_t entry, uint16_t index) {
     48   return dtohs(ResTable_sparseTypeEntry{entry}.idx) < index;
     49 }
     50 
     51 const ResTable_entry* TypeVariant::iterator::operator*() const {
     52     const ResTable_type* type = mTypeVariant->data;
     53     if (mIndex >= mTypeVariant->mLength) {
     54         return NULL;
     55     }
     56 
     57     const uint32_t entryCount = dtohl(mTypeVariant->data->entryCount);
     58     const uintptr_t containerEnd = reinterpret_cast<uintptr_t>(type)
     59             + dtohl(type->header.size);
     60     const uint32_t* const entryIndices = reinterpret_cast<const uint32_t*>(
     61             reinterpret_cast<uintptr_t>(type) + dtohs(type->header.headerSize));
     62     if (reinterpret_cast<uintptr_t>(entryIndices) + (sizeof(uint32_t) * entryCount) > containerEnd) {
     63         ALOGE("Type's entry indices extend beyond its boundaries");
     64         return NULL;
     65     }
     66 
     67     uint32_t entryOffset;
     68     if (type->flags & ResTable_type::FLAG_SPARSE) {
     69       auto iter = std::lower_bound(entryIndices, entryIndices + entryCount, mIndex, keyCompare);
     70       if (iter == entryIndices + entryCount
     71               || dtohs(ResTable_sparseTypeEntry{*iter}.idx) != mIndex) {
     72         return NULL;
     73       }
     74 
     75       entryOffset = static_cast<uint32_t>(dtohs(ResTable_sparseTypeEntry{*iter}.offset)) * 4u;
     76     } else {
     77       entryOffset = dtohl(entryIndices[mIndex]);
     78     }
     79 
     80     if (entryOffset == ResTable_type::NO_ENTRY) {
     81         return NULL;
     82     }
     83 
     84     if ((entryOffset & 0x3) != 0) {
     85         ALOGE("Index %u points to entry with unaligned offset 0x%08x", mIndex, entryOffset);
     86         return NULL;
     87     }
     88 
     89     const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(
     90             reinterpret_cast<uintptr_t>(type) + dtohl(type->entriesStart) + entryOffset);
     91     if (reinterpret_cast<uintptr_t>(entry) > containerEnd - sizeof(*entry)) {
     92         ALOGE("Entry offset at index %u points outside the Type's boundaries", mIndex);
     93         return NULL;
     94     } else if (reinterpret_cast<uintptr_t>(entry) + dtohs(entry->size) > containerEnd) {
     95         ALOGE("Entry at index %u extends beyond Type's boundaries", mIndex);
     96         return NULL;
     97     } else if (dtohs(entry->size) < sizeof(*entry)) {
     98         ALOGE("Entry at index %u is too small (%u)", mIndex, dtohs(entry->size));
     99         return NULL;
    100     }
    101     return entry;
    102 }
    103 
    104 } // namespace android
    105