Search in sources :

Example 1 with ResChunk_header

use of org.robolectric.res.android.ResourceTypes.ResChunk_header in project robolectric by robolectric.

the class ResTable method addInternal.

// status_t addInternal(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
// bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset=false);
int addInternal(byte[] data, int dataSize, final Object idmapData, int idmapDataSize, boolean appAsLib, final int cookie, boolean copyData, boolean isSystemAsset) {
    if (!isTruthy(data)) {
        return NO_ERROR;
    }
    if (dataSize < ResTable_header.SIZEOF) {
        ALOGE("Invalid data. Size(%d) is smaller than a ResTable_header(%d).", (int) dataSize, (int) ResTable_header.SIZEOF);
        return UNKNOWN_ERROR;
    }
    Header header = new Header(this);
    header.index = mHeaders.size();
    header.cookie = cookie;
    if (idmapData != NULL) {
        header.resourceIDMap = new int[idmapDataSize / 4];
        if (header.resourceIDMap == NULL) {
            // delete header;
            return (mError = NO_MEMORY);
        }
    // memcpy(header.resourceIDMap, idmapData, idmapDataSize);
    // header.resourceIDMapSize = idmapDataSize;
    }
    mHeaders.add(header);
    final boolean notDeviceEndian = htods((short) 0xf0) != 0xf0;
    if (kDebugLoadTableNoisy) {
        ALOGV("Adding resources to ResTable: data=%s, size=0x%x, cookie=%d, copy=%d " + "idmap=%s\n", data, dataSize, cookie, copyData, idmapData);
    }
    if (copyData || notDeviceEndian) {
        // malloc(dataSize);
        header.ownedData = data;
        if (header.ownedData == NULL) {
            return (mError = NO_MEMORY);
        }
        // memcpy(header.ownedData, data, dataSize);
        data = header.ownedData;
    }
    ByteBuffer buf = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
    // header->header = (const ResTable_header*)data;
    header.header = new ResTable_header(buf, 0);
    header.size = dtohl(header.header.header.size);
    if (kDebugLoadTableSuperNoisy) {
        ALOGI("Got size 0x%x, again size 0x%x, raw size 0x%x\n", header.size, dtohl(header.header.header.size), header.header.header.size);
    }
    if (kDebugLoadTableNoisy) {
        ALOGV("Loading ResTable @%s:\n", header.header);
    }
    if (dtohs(header.header.header.headerSize) > header.size || header.size > dataSize) {
        ALOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n", (int) dtohs(header.header.header.headerSize), (int) header.size, (int) dataSize);
        return (mError = BAD_TYPE);
    }
    if (((dtohs(header.header.header.headerSize) | header.size) & 0x3) != 0) {
        ALOGW("Bad resource table: header size 0x%x or total size 0x%x is not on an integer boundary\n", (int) dtohs(header.header.header.headerSize), (int) header.size);
        return (mError = BAD_TYPE);
    }
    // header->dataEnd = ((const uint8_t*)header->header) + header->size;
    header.dataEnd = header.size;
    // Iterate through all chunks.
    int curPackage = 0;
    // const ResChunk_header* chunk =
    // (const ResChunk_header*)(((const uint8_t*)header->header)
    // + dtohs(header->header->header.headerSize));
    ResChunk_header chunk = new ResChunk_header(buf, dtohs(header.header.header.headerSize));
    while (chunk != null && (chunk.myOffset()) <= (header.dataEnd - ResChunk_header.SIZEOF) && (chunk.myOffset()) <= (header.dataEnd - dtohl(chunk.size))) {
        int err = validate_chunk(chunk, ResChunk_header.SIZEOF, header.dataEnd, "ResTable");
        if (err != NO_ERROR) {
            return (mError = err);
        }
        if (kDebugTableNoisy) {
            ALOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%s\n", dtohs(chunk.type), dtohs(chunk.headerSize), dtohl(chunk.size), (Object) ((chunk.myOffset()) - (header.header.myOffset())));
        }
        final int csize = dtohl(chunk.size);
        final int ctype = dtohs(chunk.type);
        if (ctype == RES_STRING_POOL_TYPE) {
            if (header.values.getError() != NO_ERROR) {
                // Only use the first string chunk; ignore any others that
                // may appear.
                err = header.values.setTo(chunk.myBuf(), chunk.myOffset(), csize, false);
                if (err != NO_ERROR) {
                    return (mError = err);
                }
            } else {
                ALOGW("Multiple string chunks found in resource table.");
            }
        } else if (ctype == RES_TABLE_PACKAGE_TYPE) {
            if (curPackage >= dtohl(header.header.packageCount)) {
                ALOGW("More package chunks were found than the %d declared in the header.", dtohl(header.header.packageCount));
                return (mError = BAD_TYPE);
            }
            if (parsePackage(new ResTable_package(chunk.myBuf(), chunk.myOffset()), header, appAsLib, isSystemAsset) != NO_ERROR) {
                return mError;
            }
            curPackage++;
        } else {
            ALOGW("Unknown chunk type 0x%x in table at 0x%x.\n", ctype, (chunk.myOffset()) - (header.header.myOffset()));
        }
        chunk = chunk.myOffset() + csize < header.dataEnd ? new ResChunk_header(chunk.myBuf(), chunk.myOffset() + csize) : null;
    }
    if (curPackage < dtohl(header.header.packageCount)) {
        ALOGW("Fewer package chunks (%d) were found than the %d declared in the header.", (int) curPackage, dtohl(header.header.packageCount));
        return (mError = BAD_TYPE);
    }
    mError = header.values.getError();
    if (mError != NO_ERROR) {
        ALOGW("No string values found in resource table!");
    }
    if (kDebugTableNoisy) {
        ALOGV("Returning from add with mError=%d\n", mError);
    }
    return mError;
}
Also used : ResTable_header(org.robolectric.res.android.ResourceTypes.ResTable_header) ResTable_package(org.robolectric.res.android.ResourceTypes.ResTable_package) ResChunk_header(org.robolectric.res.android.ResourceTypes.ResChunk_header) ByteBuffer(java.nio.ByteBuffer)

Example 2 with ResChunk_header

use of org.robolectric.res.android.ResourceTypes.ResChunk_header in project robolectric by robolectric.

the class ResStringPool method setTo.

// status_t setTo(const void* data, size_t size, bool copyData=false);
public int setTo(ByteBuffer buf, int offset, int size, boolean copyData) {
    if (!isTruthy(buf) || !isTruthy(size)) {
        return (mError = BAD_TYPE);
    }
    uninit();
    // The chunk must be at least the size of the string pool header.
    if (size < ResStringPool_header.SIZEOF) {
        ALOGW("Bad string block: data size %zu is too small to be a string block", size);
        return (mError = BAD_TYPE);
    }
    // `data + size` is safe because the source of `size` comes from the kernel/filesystem.
    if (validate_chunk(new ResChunk_header(buf, offset), ResStringPool_header.SIZEOF, size, "ResStringPool_header") != NO_ERROR) {
        ALOGW("Bad string block: malformed block dimensions");
        return (mError = BAD_TYPE);
    }
    // final boolean notDeviceEndian = htods((short) 0xf0) != 0xf0;
    // 
    // if (copyData || notDeviceEndian) {
    // mOwnedData = data;
    // if (mOwnedData == null) {
    // return (mError=NO_MEMORY);
    // }
    // //      memcpy(mOwnedData, data, size);
    // data = mOwnedData;
    // }
    // The size has been checked, so it is safe to read the data in the ResStringPool_header
    // data structure.
    mHeader = new ResStringPool_header(buf, offset);
    if (mHeader.header.headerSize > mHeader.header.size || mHeader.header.size > size) {
        ALOGW("Bad string block: header size %d or total size %d is larger than data size %d\n", (int) mHeader.header.headerSize, (int) mHeader.header.size, (int) size);
        return (mError = BAD_TYPE);
    }
    mSize = mHeader.header.size;
    mEntries = new IntArray(mHeader.myBuf(), mHeader.myOffset() + mHeader.header.headerSize);
    if (mHeader.stringCount > 0) {
        if (// uint32 overflow?
        (mHeader.stringCount * 4 < /*sizeof(uint32_t)*/
        mHeader.stringCount) || (mHeader.header.headerSize + (mHeader.stringCount * 4)) > size) {
            ALOGW("Bad string block: entry of %d items extends past data size %d\n", (int) (mHeader.header.headerSize + (mHeader.stringCount * 4)), (int) size);
            return (mError = BAD_TYPE);
        }
        int charSize;
        if (isTruthy(mHeader.flags & ResStringPool_header.UTF8_FLAG)) {
            charSize = 1;
        } else {
            charSize = 2;
        }
        // (2 bytes length, null terminator).
        if (mHeader.stringsStart >= (mSize - 2)) {
            ALOGW("Bad string block: string pool starts at %d, after total size %d\n", (int) mHeader.stringsStart, (int) mHeader.header.size);
            return (mError = BAD_TYPE);
        }
        mStrings = mHeader.stringsStart;
        if (mHeader.styleCount == 0) {
            mStringPoolSize = (mSize - mHeader.stringsStart) / charSize;
        } else {
            // check invariant: styles starts before end of data
            if (mHeader.stylesStart >= (mSize - 2)) {
                ALOGW("Bad style block: style block starts at %d past data size of %d\n", (int) mHeader.stylesStart, (int) mHeader.header.size);
                return (mError = BAD_TYPE);
            }
            // check invariant: styles follow the strings
            if (mHeader.stylesStart <= mHeader.stringsStart) {
                ALOGW("Bad style block: style block starts at %d, before strings at %d\n", (int) mHeader.stylesStart, (int) mHeader.stringsStart);
                return (mError = BAD_TYPE);
            }
            mStringPoolSize = (mHeader.stylesStart - mHeader.stringsStart) / charSize;
        }
        // check invariant: stringCount > 0 requires a string pool to exist
        if (mStringPoolSize == 0) {
            ALOGW("Bad string block: stringCount is %d but pool size is 0\n", (int) mHeader.stringCount);
            return (mError = BAD_TYPE);
        }
        if ((isTruthy(mHeader.flags & ResStringPool_header.UTF8_FLAG) && (mHeader.getByte(mStrings + mStringPoolSize - 1) != 0)) || (!isTruthy(mHeader.flags & ResStringPool_header.UTF8_FLAG) && (mHeader.getShort(mStrings + mStringPoolSize * 2 - 2) != 0))) {
            ALOGW("Bad string block: last string is not 0-terminated\n");
            return (mError = BAD_TYPE);
        }
    } else {
        mStrings = -1;
        mStringPoolSize = 0;
    }
    if (mHeader.styleCount > 0) {
        mEntryStyles = new IntArray(mEntries.myBuf(), mEntries.myOffset() + mHeader.stringCount * SIZEOF_INT);
        // invariant: integer overflow in calculating mEntryStyles
        if (mEntryStyles.myOffset() < mEntries.myOffset()) {
            ALOGW("Bad string block: integer overflow finding styles\n");
            return (mError = BAD_TYPE);
        }
        // if (((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader) > (int)size) {
        if ((mEntryStyles.myOffset() - mHeader.myOffset()) > (int) size) {
            ALOGW("Bad string block: entry of %d styles extends past data size %d\n", (int) (mEntryStyles.myOffset()), (int) size);
            return (mError = BAD_TYPE);
        }
        mStyles = mHeader.stylesStart;
        if (mHeader.stylesStart >= mHeader.header.size) {
            ALOGW("Bad string block: style pool starts %d, after total size %d\n", (int) mHeader.stylesStart, (int) mHeader.header.size);
            return (mError = BAD_TYPE);
        }
        mStylePoolSize = (mHeader.header.size - mHeader.stylesStart);
        // if (notDeviceEndian) {
        // size_t i;
        // uint32_t* e = final_cast<uint32_t*>(mEntryStyles);
        // for (i=0; i<mHeader.styleCount; i++) {
        // e[i] = dtohl(mEntryStyles[i]);
        // }
        // uint32_t* s = final_cast<uint32_t*>(mStyles);
        // for (i=0; i<mStylePoolSize; i++) {
        // s[i] = dtohl(mStyles[i]);
        // }
        // }
        // final ResStringPool_span endSpan = {
        // { htodl(ResStringPool_span.END) },
        // htodl(ResStringPool_span.END), htodl(ResStringPool_span.END)
        // };
        // if (memcmp(&mStyles[mStylePoolSize-(sizeof(endSpan)/sizeof(uint32_t))],
        // &endSpan, sizeof(endSpan)) != 0) {
        ResStringPool_span endSpan = new ResStringPool_span(buf, mHeader.myOffset() + mStyles + (mStylePoolSize - ResStringPool_span.SIZEOF));
        if (!endSpan.isEnd()) {
            ALOGW("Bad string block: last style is not 0xFFFFFFFF-terminated\n");
            return (mError = BAD_TYPE);
        }
    } else {
        mEntryStyles = null;
        mStyles = 0;
        mStylePoolSize = 0;
    }
    return (mError = NO_ERROR);
}
Also used : ResStringPool_span(org.robolectric.res.android.ResourceTypes.ResStringPool_span) ResChunk_header(org.robolectric.res.android.ResourceTypes.ResChunk_header) ResStringPool_header(org.robolectric.res.android.ResourceTypes.ResStringPool_header)

Example 3 with ResChunk_header

use of org.robolectric.res.android.ResourceTypes.ResChunk_header in project robolectric by robolectric.

the class ResTable method parsePackage.

int parsePackage(ResTable_package pkg, Header header, boolean appAsLib, boolean isSystemAsset) {
    int base = pkg.myOffset();
    int err = validate_chunk(pkg.header, ResTable_package.SIZEOF - 4, /*sizeof(pkg.typeIdOffset)*/
    header.dataEnd, "ResTable_package");
    if (err != NO_ERROR) {
        return (mError = err);
    }
    final int pkgSize = dtohl(pkg.header.size);
    if (dtohl(pkg.typeStrings) >= pkgSize) {
        ALOGW("ResTable_package type strings at 0x%x are past chunk size 0x%x.", dtohl(pkg.typeStrings), pkgSize);
        return (mError = BAD_TYPE);
    }
    if ((dtohl(pkg.typeStrings) & 0x3) != 0) {
        ALOGW("ResTable_package type strings at 0x%x is not on an integer boundary.", dtohl(pkg.typeStrings));
        return (mError = BAD_TYPE);
    }
    if (dtohl(pkg.keyStrings) >= pkgSize) {
        ALOGW("ResTable_package key strings at 0x%x are past chunk size 0x%x.", dtohl(pkg.keyStrings), pkgSize);
        return (mError = BAD_TYPE);
    }
    if ((dtohl(pkg.keyStrings) & 0x3) != 0) {
        ALOGW("ResTable_package key strings at 0x%x is not on an integer boundary.", dtohl(pkg.keyStrings));
        return (mError = BAD_TYPE);
    }
    int id = dtohl(pkg.id);
    final Map<Byte, IdmapEntries> idmapEntries = new HashMap<>();
    if (header.resourceIDMap != NULL) {
    // byte targetPackageId = 0;
    // int err = parseIdmap(header.resourceIDMap, header.resourceIDMapSize, &targetPackageId, &idmapEntries);
    // if (err != NO_ERROR) {
    // ALOGW("Overlay is broken");
    // return (mError=err);
    // }
    // id = targetPackageId;
    }
    boolean isDynamic = false;
    if (id >= 256) {
        // LOG_ALWAYS_FATAL("Package id out of range");
        throw new IllegalStateException("Package id out of range");
    // return NO_ERROR;
    } else if (id == 0 || (id == 0x7f && appAsLib) || isSystemAsset) {
        // This is a library or a system asset, so assign an ID
        id = mNextPackageId++;
        isDynamic = true;
    }
    PackageGroup group = null;
    Package _package = new Package(this, header, pkg);
    if (_package == NULL) {
        return (mError = NO_MEMORY);
    }
    // err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
    // header->dataEnd-(base+dtohl(pkg->typeStrings)));
    err = _package.typeStrings.setTo(pkg.myBuf(), base + dtohl(pkg.typeStrings), header.dataEnd - (base + dtohl(pkg.typeStrings)), false);
    if (err != NO_ERROR) {
        // delete _package;
        return (mError = err);
    }
    // err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
    // header->dataEnd-(base+dtohl(pkg->keyStrings)));
    err = _package.keyStrings.setTo(pkg.myBuf(), base + dtohl(pkg.keyStrings), header.dataEnd - (base + dtohl(pkg.keyStrings)), false);
    if (err != NO_ERROR) {
        // delete _package;
        return (mError = err);
    }
    int idx = mPackageMap[id];
    if (idx == 0) {
        idx = mPackageGroups.size() + 1;
        // char[] tmpName = new char[pkg.name.length /*sizeof(pkg.name)/sizeof(pkg.name[0])*/];
        // strcpy16_dtoh(tmpName, pkg.name, sizeof(pkg.name)/sizeof(pkg.name[0]));
        group = new PackageGroup(this, new String(pkg.name), id, appAsLib, isSystemAsset, isDynamic);
        if (group == NULL) {
            // delete _package;
            return (mError = NO_MEMORY);
        }
        mPackageGroups.put(group.id, group);
        // if (err < NO_ERROR) {
        // return (mError=err);
        // }
        mPackageMap[id] = (byte) idx;
        // for (int i = 0; i < N; i++) {
        for (PackageGroup packageGroup : mPackageGroups.values()) {
            packageGroup.dynamicRefTable.addMapping(group.name, (byte) group.id);
        }
    } else {
        group = mPackageGroups.get(idx - 1);
        if (group == NULL) {
            return (mError = UNKNOWN_ERROR);
        }
    }
    group.packages.add(_package);
    // if (err < NO_ERROR) {
    // return (mError=err);
    // }
    // Iterate through all chunks.
    ResChunk_header chunk = new ResChunk_header(pkg.myBuf(), pkg.myOffset() + dtohs(pkg.header.headerSize));
    // const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size);
    final int endPos = (pkg.myOffset()) + pkg.header.size;
    // ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) {
    while (chunk != null && (chunk.myOffset()) <= (endPos - ResChunk_header.SIZEOF) && (chunk.myOffset()) <= (endPos - dtohl(chunk.size))) {
        if (kDebugTableNoisy) {
            ALOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%s\n", dtohs(chunk.type), dtohs(chunk.headerSize), dtohl(chunk.size), ((chunk.myOffset()) - (header.header.myOffset())));
        }
        final int csize = dtohl(chunk.size);
        final short ctype = dtohs(chunk.type);
        if (ctype == RES_TABLE_TYPE_SPEC_TYPE) {
            final ResTable_typeSpec typeSpec = new ResTable_typeSpec(chunk.myBuf(), chunk.myOffset());
            err = validate_chunk(typeSpec.header, ResTable_typeSpec.SIZEOF, endPos, "ResTable_typeSpec");
            if (err != NO_ERROR) {
                return (mError = err);
            }
            final int typeSpecSize = dtohl(typeSpec.header.size);
            final int newEntryCount = dtohl(typeSpec.entryCount);
            if (kDebugLoadTableNoisy) {
                ALOGI("TypeSpec off %s: type=0x%x, headerSize=0x%x, size=%s\n", (base - chunk.myOffset()), dtohs(typeSpec.header.type), dtohs(typeSpec.header.headerSize), typeSpecSize);
            }
            // look for block overrun or int overflow when multiplying by 4
            if ((dtohl(typeSpec.entryCount) > (Integer.MAX_VALUE / 4) || dtohs(typeSpec.header.headerSize) + (4 * /*sizeof(int)*/
            newEntryCount) > typeSpecSize)) {
                ALOGW("ResTable_typeSpec entry index to %s extends beyond chunk end %s.", (dtohs(typeSpec.header.headerSize) + (4 * /*sizeof(int)*/
                newEntryCount)), typeSpecSize);
                return (mError = BAD_TYPE);
            }
            if (typeSpec.id == 0) {
                ALOGW("ResTable_type has an id of 0.");
                return (mError = BAD_TYPE);
            }
            if (newEntryCount > 0) {
                boolean addToType = true;
                byte typeIndex = (byte) (typeSpec.id - 1);
                IdmapEntries idmapEntry = idmapEntries.get(typeSpec.id);
                if (idmapEntry != null) {
                    typeIndex = (byte) (idmapEntry.targetTypeId() - 1);
                } else if (header.resourceIDMap != NULL) {
                    // This is an overlay, but the types in this overlay are not
                    // overlaying anything according to the idmap. We can skip these
                    // as they will otherwise conflict with the other resources in the package
                    // without a mapping.
                    addToType = false;
                }
                if (addToType) {
                    List<Type> typeList = computeIfAbsent(group.types, (int) typeIndex, k -> new ArrayList<>());
                    if (!typeList.isEmpty()) {
                        final Type existingType = typeList.get(0);
                        if (existingType.entryCount != newEntryCount && idmapEntry == null) {
                            ALOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d", (int) newEntryCount, (int) existingType.entryCount);
                        // We should normally abort here, but some legacy apps declare
                        // resources in the 'android' package (old bug in AAPT).
                        }
                    }
                    Type t = new Type(header, _package, newEntryCount);
                    t.typeSpec = typeSpec;
                    t.typeSpecFlags = typeSpec.getSpecFlags();
                    if (idmapEntry != null) {
                        t.idmapEntries = idmapEntry;
                    }
                    typeList.add(t);
                    group.largestTypeId = max(group.largestTypeId, typeSpec.id);
                }
            } else {
                ALOGV("Skipping empty ResTable_typeSpec for type %d", typeSpec.id);
            }
        } else if (ctype == RES_TABLE_TYPE_TYPE) {
            ResTable_type type = new ResTable_type(chunk.myBuf(), chunk.myOffset());
            err = validate_chunk(type.header, ResTable_type.SIZEOF_WITHOUT_CONFIG + /*-sizeof(ResTable_config)*/
            4, endPos, "ResTable_type");
            if (err != NO_ERROR) {
                return (mError = err);
            }
            final int typeSize = dtohl(type.header.size);
            final int newEntryCount = dtohl(type.entryCount);
            if (kDebugLoadTableNoisy) {
                System.out.println(String.format("Type off 0x%x: type=0x%x, headerSize=0x%x, size=%d\n", base - chunk.myOffset(), dtohs(type.header.type), dtohs(type.header.headerSize), typeSize));
            }
            if (dtohs(type.header.headerSize) + (4 * /*sizeof(int)*/
            newEntryCount) > typeSize) {
                ALOGW("ResTable_type entry index to %s extends beyond chunk end 0x%x.", (dtohs(type.header.headerSize) + (4 * /*sizeof(int)*/
                newEntryCount)), typeSize);
                return (mError = BAD_TYPE);
            }
            if (newEntryCount != 0 && dtohl(type.entriesStart) > (typeSize - ResTable_entry.SIZEOF)) {
                ALOGW("ResTable_type entriesStart at 0x%x extends beyond chunk end 0x%x.", dtohl(type.entriesStart), typeSize);
                return (mError = BAD_TYPE);
            }
            if (type.id == 0) {
                ALOGW("ResTable_type has an id of 0.");
                return (mError = BAD_TYPE);
            }
            if (newEntryCount > 0) {
                boolean addToType = true;
                byte typeIndex = (byte) (type.id - 1);
                IdmapEntries idmapEntry = idmapEntries.get(type.id);
                if (idmapEntry != null) {
                    typeIndex = (byte) (idmapEntry.targetTypeId() - 1);
                } else if (header.resourceIDMap != NULL) {
                    // This is an overlay, but the types in this overlay are not
                    // overlaying anything according to the idmap. We can skip these
                    // as they will otherwise conflict with the other resources in the package
                    // without a mapping.
                    addToType = false;
                }
                if (addToType) {
                    List<Type> typeList = getOrDefault(group.types, (int) typeIndex, Collections.emptyList());
                    if (typeList.isEmpty()) {
                        ALOGE("No TypeSpec for type %d", type.id);
                        return (mError = BAD_TYPE);
                    }
                    Type t = typeList.get(typeList.size() - 1);
                    if (newEntryCount != t.entryCount) {
                        ALOGE("ResTable_type entry count inconsistent: given %d, previously %d", (int) newEntryCount, (int) t.entryCount);
                        return (mError = BAD_TYPE);
                    }
                    if (t._package_ != _package) {
                        ALOGE("No TypeSpec for type %d", type.id);
                        return (mError = BAD_TYPE);
                    }
                    t.configs.add(type);
                    if (kDebugTableGetEntry) {
                        ResTable_config thisConfig = ResTable_config.fromDtoH(type.config);
                        ALOGI("Adding config to type %d: %s\n", type.id, thisConfig.toString());
                    }
                }
            } else {
                ALOGV("Skipping empty ResTable_type for type %d", type.id);
            }
        } else if (ctype == RES_TABLE_LIBRARY_TYPE) {
            if (group.dynamicRefTable.entries().isEmpty()) {
                throw new UnsupportedOperationException("libraries not supported yet");
            // const ResTable_lib_header* lib = (const ResTable_lib_header*) chunk;
            // status_t err = validate_chunk(&lib->header, sizeof(*lib),
            // endPos, "ResTable_lib_header");
            // if (err != NO_ERROR) {
            // return (mError=err);
            // }
            // 
            // err = group->dynamicRefTable.load(lib);
            // if (err != NO_ERROR) {
            // return (mError=err);
            // }
            // 
            // // Fill in the reference table with the entries we already know about.
            // size_t N = mPackageGroups.size();
            // for (size_t i = 0; i < N; i++) {
            // group.dynamicRefTable.addMapping(mPackageGroups[i].name, mPackageGroups[i].id);
            // }
            } else {
                ALOGW("Found multiple library tables, ignoring...");
            }
        } else {
            err = validate_chunk(chunk, ResChunk_header.SIZEOF, endPos, "ResTable_package:unknown");
            if (err != NO_ERROR) {
                return (mError = err);
            }
        }
        chunk = chunk.myOffset() + csize < endPos ? new ResChunk_header(chunk.myBuf(), chunk.myOffset() + csize) : null;
    }
    return NO_ERROR;
}
Also used : HashMap(java.util.HashMap) ResChunk_header(org.robolectric.res.android.ResourceTypes.ResChunk_header) ArrayList(java.util.ArrayList) List(java.util.List) ResTable_typeSpec(org.robolectric.res.android.ResourceTypes.ResTable_typeSpec) ResTable_type(org.robolectric.res.android.ResourceTypes.ResTable_type)

Example 4 with ResChunk_header

use of org.robolectric.res.android.ResourceTypes.ResChunk_header in project robolectric by robolectric.

the class ResXMLTree method setTo.

public int setTo(byte[] data, int size, boolean copyData) {
    uninit();
    mParser.mEventCode = START_DOCUMENT;
    if (!isTruthy(data) || !isTruthy(size)) {
        return (mError = BAD_TYPE);
    }
    if (copyData) {
        mOwnedData = new byte[size];
        // if (mOwnedData == null) {
        // return (mError=NO_MEMORY);
        // }
        // memcpy(mOwnedData, data, size);
        System.arraycopy(data, 0, mOwnedData, 0, size);
        data = mOwnedData;
    }
    mBuffer = new XmlBuffer(data);
    mHeader = new ResXMLTree_header(mBuffer.buf, 0);
    mSize = dtohl(mHeader.header.size);
    if (dtohs(mHeader.header.headerSize) > mSize || mSize > size) {
        ALOGW("Bad XML block: header size %d or total size %d is larger than data size %d\n", (int) dtohs(mHeader.header.headerSize), (int) dtohl(mHeader.header.size), (int) size);
        mError = BAD_TYPE;
        mParser.restart();
        return mError;
    }
    // mDataEnd = ((final uint8_t*)mHeader) + mSize;
    mDataLen = mSize;
    mStrings.uninit();
    mRootNode = null;
    mResIds = null;
    mNumResIds = 0;
    // First look for a couple interesting chunks: the string block
    // and first XML node.
    ResChunk_header chunk = // (final ResChunk_header*)(((final uint8_t*)mHeader) + dtohs(mHeader.header.headerSize));
    new ResChunk_header(mBuffer.buf, mHeader.header.headerSize);
    ResChunk_header lastChunk = chunk;
    while (chunk.myOffset() < /*((final uint8_t*)chunk)*/
    (mDataLen - ResChunk_header.SIZEOF) && chunk.myOffset() < /*((final uint8_t*)chunk)*/
    (mDataLen - dtohl(chunk.size))) {
        int err = validate_chunk(chunk, ResChunk_header.SIZEOF, /*sizeof(ResChunk_header)*/
        mDataLen, "XML");
        if (err != NO_ERROR) {
            mError = err;
            // goto done;
            mParser.restart();
            return mError;
        }
        final short type = dtohs(chunk.type);
        final int size1 = dtohl(chunk.size);
        if (kDebugXMLNoisy) {
        // System.out.println(String.format("Scanning @ %s: type=0x%x, size=0x%zx\n",
        // (void*)(((uintptr_t)chunk)-((uintptr_t)mHeader)), type, size1);
        }
        if (type == RES_STRING_POOL_TYPE) {
            mStrings.setTo(mBuffer.buf, chunk.myOffset(), size, false);
        } else if (type == RES_XML_RESOURCE_MAP_TYPE) {
            // mResIds = (final int*)
            // (((final uint8_t*)chunk)+dtohs(chunk.headerSize()));
            mNumResIds = (dtohl(chunk.size) - dtohs(chunk.headerSize)) / SIZEOF_INT;
            mResIds = new int[mNumResIds];
            for (int i = 0; i < mNumResIds; i++) {
                mResIds[i] = mBuffer.buf.getInt(chunk.myOffset() + chunk.headerSize + i * SIZEOF_INT);
            }
        } else if (type >= RES_XML_FIRST_CHUNK_TYPE && type <= RES_XML_LAST_CHUNK_TYPE) {
            if (validateNode(new ResXMLTree_node(mBuffer.buf, chunk)) != NO_ERROR) {
                mError = BAD_TYPE;
                // goto done;
                mParser.restart();
                return mError;
            }
            mParser.mCurNode = new ResXMLTree_node(mBuffer.buf, lastChunk.myOffset());
            if (mParser.nextNode() == BAD_DOCUMENT) {
                mError = BAD_TYPE;
                // goto done;
                mParser.restart();
                return mError;
            }
            mRootNode = mParser.mCurNode;
            mRootExt = mParser.mCurExt;
            mRootCode = mParser.mEventCode;
            break;
        } else {
            if (kDebugXMLNoisy) {
                System.out.println("Skipping unknown chunk!\n");
            }
        }
        lastChunk = chunk;
        // chunk = (final ResChunk_header*)
        // (((final uint8_t*)chunk) + size1);
        chunk = new ResChunk_header(mBuffer.buf, chunk.myOffset() + size1);
    }
    if (mRootNode == null) {
        ALOGW("Bad XML block: no root element node found\n");
        mError = BAD_TYPE;
        // goto done;
        mParser.restart();
        return mError;
    }
    mError = mStrings.getError();
    done: mParser.restart();
    return mError;
}
Also used : ResXMLTree_header(org.robolectric.res.android.ResourceTypes.ResXMLTree_header) ResXMLTree_node(org.robolectric.res.android.ResourceTypes.ResXMLTree_node) ResChunk_header(org.robolectric.res.android.ResourceTypes.ResChunk_header)

Aggregations

ResChunk_header (org.robolectric.res.android.ResourceTypes.ResChunk_header)4 ByteBuffer (java.nio.ByteBuffer)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 List (java.util.List)1 ResStringPool_header (org.robolectric.res.android.ResourceTypes.ResStringPool_header)1 ResStringPool_span (org.robolectric.res.android.ResourceTypes.ResStringPool_span)1 ResTable_header (org.robolectric.res.android.ResourceTypes.ResTable_header)1 ResTable_package (org.robolectric.res.android.ResourceTypes.ResTable_package)1 ResTable_type (org.robolectric.res.android.ResourceTypes.ResTable_type)1 ResTable_typeSpec (org.robolectric.res.android.ResourceTypes.ResTable_typeSpec)1 ResXMLTree_header (org.robolectric.res.android.ResourceTypes.ResXMLTree_header)1 ResXMLTree_node (org.robolectric.res.android.ResourceTypes.ResXMLTree_node)1