19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "ResourceType"
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//#define LOG_NDEBUG 0
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski#include <androidfw/ByteBucketArray.h>
21b13b9bdad2baf6ad1ec2e56b6b7598fa20f55fc4Mathias Agopian#include <androidfw/ResourceTypes.h>
22f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski#include <androidfw/TypeWrappers.h>
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Atomic.h>
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/ByteOrder.h>
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Debug.h>
26b13b9bdad2baf6ad1ec2e56b6b7598fa20f55fc4Mathias Agopian#include <utils/Log.h>
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/String16.h>
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/String8.h>
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdlib.h>
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <string.h>
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <memory.h>
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <ctype.h>
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdint.h>
35f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski#include <stddef.h>
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#ifndef INT32_MAX
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define INT32_MAX ((int32_t)(2147483647))
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
41d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn#define STRING_POOL_NOISY(x) //x
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define XML_NOISY(x) //x
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define TABLE_NOISY(x) //x
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define TABLE_GETENTRY(x) //x
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define TABLE_SUPER_NOISY(x) //x
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOAD_TABLE_NOISY(x) //x
47b8d81679553ee33f6ae5281310abf2effca4ffcdDianne Hackborn#define TABLE_THEME(x) //x
48f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski#define LIB_NOISY(x) //x
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android {
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#ifdef HAVE_WINSOCK
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#undef  nhtol
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#undef  htonl
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#ifdef HAVE_LITTLE_ENDIAN
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define ntohl(x)    ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define htonl(x)    ntohl(x)
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define ntohs(x)    ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define htons(x)    ntohs(x)
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#else
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define ntohl(x)    (x)
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define htonl(x)    (x)
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define ntohs(x)    (x)
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define htons(x)    (x)
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
69f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski#define IDMAP_MAGIC             0x504D4449
70f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski#define IDMAP_CURRENT_VERSION   0x00000001
7157f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad
72de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski#define APP_PACKAGE_ID      0x7f
73de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski#define SYS_PACKAGE_ID      0x01
74de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Standard C isspace() is only required to look at the low byte of its input, so
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// produces incorrect results for UTF-16 characters.  For safety's sake, assume that
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// any high-byte UTF-16 code point is not whitespace.
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectinline int isspace16(char16_t c) {
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return (c < 0x0080 && isspace(c));
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
82f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinskitemplate<typename T>
83f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinskiinline static T max(T a, T b) {
84f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    return a > b ? a : b;
85f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski}
86f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// range checked; guaranteed to NUL-terminate within the stated number of available slots
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// NOTE: if this truncates the dst string due to running out of space, no attempt is
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// made to avoid splitting surrogate pairs.
904bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinskistatic void strcpy16_dtoh(char16_t* dst, const uint16_t* src, size_t avail)
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
924bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski    char16_t* last = dst + avail - 1;
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while (*src && (dst < last)) {
944bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski        char16_t s = dtohs(static_cast<char16_t>(*src));
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        *dst++ = s;
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        src++;
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    *dst = 0;
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic status_t validate_chunk(const ResChunk_header* chunk,
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                               size_t minSize,
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                               const uint8_t* dataEnd,
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                               const char* name)
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const uint16_t headerSize = dtohs(chunk->headerSize);
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const uint32_t size = dtohl(chunk->size);
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (headerSize >= minSize) {
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (headerSize <= size) {
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (((headerSize|size)&0x3) == 0) {
1127322ea7b73000ef50be18d72750624bb1832dec4Adam Lesinski                if ((size_t)size <= (size_t)(dataEnd-((const uint8_t*)chunk))) {
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return NO_ERROR;
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
115443dd9313f06ec61abc9fee908f6e693d1091590Patrik Bannura                ALOGW("%s data size 0x%x extends beyond resource end %p.",
116443dd9313f06ec61abc9fee908f6e693d1091590Patrik Bannura                     name, size, (void*)(dataEnd-((const uint8_t*)chunk)));
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return BAD_TYPE;
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1198564c8da817a845353d213acd8636b76f567b234Steve Block            ALOGW("%s size 0x%x or headerSize 0x%x is not on an integer boundary.",
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 name, (int)size, (int)headerSize);
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return BAD_TYPE;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
123443dd9313f06ec61abc9fee908f6e693d1091590Patrik Bannura        ALOGW("%s size 0x%x is smaller than header size 0x%x.",
124443dd9313f06ec61abc9fee908f6e693d1091590Patrik Bannura             name, size, headerSize);
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return BAD_TYPE;
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
127de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    ALOGW("%s header size 0x%04x is too small.",
128443dd9313f06ec61abc9fee908f6e693d1091590Patrik Bannura         name, headerSize);
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return BAD_TYPE;
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1326381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamathstatic void fill9patchOffsets(Res_png_9patch* patch) {
1336381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    patch->xDivsOffset = sizeof(Res_png_9patch);
1346381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    patch->yDivsOffset = patch->xDivsOffset + (patch->numXDivs * sizeof(int32_t));
1356381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    patch->colorsOffset = patch->yDivsOffset + (patch->numYDivs * sizeof(int32_t));
1366381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath}
1376381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectinline void Res_value::copyFrom_dtoh(const Res_value& src)
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size = dtohs(src.size);
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    res0 = src.res0;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    dataType = src.dataType;
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    data = dtohl(src.data);
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid Res_png_9patch::deviceToFile()
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1486381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    int32_t* xDivs = getXDivs();
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (int i = 0; i < numXDivs; i++) {
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        xDivs[i] = htonl(xDivs[i]);
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1526381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    int32_t* yDivs = getYDivs();
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (int i = 0; i < numYDivs; i++) {
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        yDivs[i] = htonl(yDivs[i]);
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    paddingLeft = htonl(paddingLeft);
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    paddingRight = htonl(paddingRight);
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    paddingTop = htonl(paddingTop);
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    paddingBottom = htonl(paddingBottom);
1606381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    uint32_t* colors = getColors();
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (int i=0; i<numColors; i++) {
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        colors[i] = htonl(colors[i]);
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid Res_png_9patch::fileToDevice()
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1686381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    int32_t* xDivs = getXDivs();
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (int i = 0; i < numXDivs; i++) {
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        xDivs[i] = ntohl(xDivs[i]);
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1726381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    int32_t* yDivs = getYDivs();
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (int i = 0; i < numYDivs; i++) {
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        yDivs[i] = ntohl(yDivs[i]);
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    paddingLeft = ntohl(paddingLeft);
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    paddingRight = ntohl(paddingRight);
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    paddingTop = ntohl(paddingTop);
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    paddingBottom = ntohl(paddingBottom);
1806381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    uint32_t* colors = getColors();
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (int i=0; i<numColors; i++) {
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        colors[i] = ntohl(colors[i]);
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1866381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamathsize_t Res_png_9patch::serializedSize() const
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // The size of this struct is 32 bytes on the 32-bit target system
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // 4 * int8_t
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // 4 * int32_t
1916381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    // 3 * uint32_t
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return 32
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            + numXDivs * sizeof(int32_t)
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            + numYDivs * sizeof(int32_t)
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            + numColors * sizeof(uint32_t);
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1986381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamathvoid* Res_png_9patch::serialize(const Res_png_9patch& patch, const int32_t* xDivs,
1996381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath                                const int32_t* yDivs, const uint32_t* colors)
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
2014df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    // Use calloc since we're going to leave a few holes in the data
2024df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    // and want this to run cleanly under valgrind
2036381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    void* newData = calloc(1, patch.serializedSize());
2046381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    serialize(patch, xDivs, yDivs, colors, newData);
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return newData;
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2086381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamathvoid Res_png_9patch::serialize(const Res_png_9patch& patch, const int32_t* xDivs,
2096381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath                               const int32_t* yDivs, const uint32_t* colors, void* outData)
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
2116381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    uint8_t* data = (uint8_t*) outData;
2126381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    memcpy(data, &patch.wasDeserialized, 4);     // copy  wasDeserialized, numXDivs, numYDivs, numColors
2136381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    memcpy(data + 12, &patch.paddingLeft, 16);   // copy paddingXXXX
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    data += 32;
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2166381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    memcpy(data, xDivs, patch.numXDivs * sizeof(int32_t));
2176381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    data +=  patch.numXDivs * sizeof(int32_t);
2186381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    memcpy(data, yDivs, patch.numYDivs * sizeof(int32_t));
2196381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    data +=  patch.numYDivs * sizeof(int32_t);
2206381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    memcpy(data, colors, patch.numColors * sizeof(uint32_t));
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2226381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    fill9patchOffsets(reinterpret_cast<Res_png_9patch*>(outData));
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
225f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinskistatic bool assertIdmapHeader(const void* idmap, size_t size) {
226f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    if (reinterpret_cast<uintptr_t>(idmap) & 0x03) {
227f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        ALOGE("idmap: header is not word aligned");
228f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        return false;
229f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    }
230f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
231f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    if (size < ResTable::IDMAP_HEADER_SIZE_BYTES) {
232f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        ALOGW("idmap: header too small (%d bytes)", (uint32_t) size);
23357f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad        return false;
23457f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad    }
235f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
236f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    const uint32_t magic = htodl(*reinterpret_cast<const uint32_t*>(idmap));
237f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    if (magic != IDMAP_MAGIC) {
238f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        ALOGW("idmap: no magic found in header (is 0x%08x, expected 0x%08x)",
239f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski             magic, IDMAP_MAGIC);
240f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        return false;
241f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    }
242f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
243f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    const uint32_t version = htodl(*(reinterpret_cast<const uint32_t*>(idmap) + 1));
244f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    if (version != IDMAP_CURRENT_VERSION) {
245f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        // We are strict about versions because files with this format are
246f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        // auto-generated and don't need backwards compatibility.
247f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        ALOGW("idmap: version mismatch in header (is 0x%08x, expected 0x%08x)",
248f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski                version, IDMAP_CURRENT_VERSION);
24957f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad        return false;
25057f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad    }
25157f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad    return true;
25257f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad}
25357f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad
254f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinskiclass IdmapEntries {
255f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinskipublic:
256f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    IdmapEntries() : mData(NULL) {}
25757f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad
258f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    bool hasEntries() const {
259f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        if (mData == NULL) {
260f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            return false;
261f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        }
262f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
263f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        return (dtohs(*mData) > 0);
26457f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad    }
265f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
266f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    size_t byteSize() const {
267f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        if (mData == NULL) {
268f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            return 0;
269f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        }
270f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        uint16_t entryCount = dtohs(mData[2]);
271f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        return (sizeof(uint16_t) * 4) + (sizeof(uint32_t) * static_cast<size_t>(entryCount));
27257f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad    }
273f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
274f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    uint8_t targetTypeId() const {
275f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        if (mData == NULL) {
276f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            return 0;
277f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        }
278f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        return dtohs(mData[0]);
27957f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad    }
280f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
281f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    uint8_t overlayTypeId() const {
282f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        if (mData == NULL) {
283f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            return 0;
284f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        }
285f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        return dtohs(mData[1]);
28657f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad    }
287f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
288f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    status_t setTo(const void* entryHeader, size_t size) {
289f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        if (reinterpret_cast<uintptr_t>(entryHeader) & 0x03) {
290f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            ALOGE("idmap: entry header is not word aligned");
291f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            return UNKNOWN_ERROR;
292f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        }
293f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
294f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        if (size < sizeof(uint16_t) * 4) {
295f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            ALOGE("idmap: entry header is too small (%u bytes)", (uint32_t) size);
296f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            return UNKNOWN_ERROR;
297f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        }
298f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
299f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        const uint16_t* header = reinterpret_cast<const uint16_t*>(entryHeader);
300f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        const uint16_t targetTypeId = dtohs(header[0]);
301f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        const uint16_t overlayTypeId = dtohs(header[1]);
302f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        if (targetTypeId == 0 || overlayTypeId == 0 || targetTypeId > 255 || overlayTypeId > 255) {
303f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            ALOGE("idmap: invalid type map (%u -> %u)", targetTypeId, overlayTypeId);
304f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            return UNKNOWN_ERROR;
305f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        }
306f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
307f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        uint16_t entryCount = dtohs(header[2]);
308f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        if (size < sizeof(uint32_t) * (entryCount + 2)) {
309f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            ALOGE("idmap: too small (%u bytes) for the number of entries (%u)",
310f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski                    (uint32_t) size, (uint32_t) entryCount);
311f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            return UNKNOWN_ERROR;
312f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        }
313f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        mData = header;
31457f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad        return NO_ERROR;
31557f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad    }
316f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
317f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    status_t lookup(uint16_t entryId, uint16_t* outEntryId) const {
318f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        uint16_t entryCount = dtohs(mData[2]);
319f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        uint16_t offset = dtohs(mData[3]);
320f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
321f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        if (entryId < offset) {
322f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            // The entry is not present in this idmap
323f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            return BAD_INDEX;
324f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        }
325f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
326f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        entryId -= offset;
327f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
328f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        if (entryId >= entryCount) {
329f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            // The entry is not present in this idmap
330f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            return BAD_INDEX;
331f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        }
332f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
333f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        // It is safe to access the type here without checking the size because
334f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        // we have checked this when it was first loaded.
335f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        const uint32_t* entries = reinterpret_cast<const uint32_t*>(mData) + 2;
336f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        uint32_t mappedEntry = dtohl(entries[entryId]);
337f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        if (mappedEntry == 0xffffffff) {
338f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            // This entry is not present in this idmap
339f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            return BAD_INDEX;
340f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        }
341f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        *outEntryId = static_cast<uint16_t>(mappedEntry);
34257f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad        return NO_ERROR;
34357f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad    }
34457f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad
345f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinskiprivate:
346f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    const uint16_t* mData;
347f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski};
34857f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad
349f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinskistatus_t parseIdmap(const void* idmap, size_t size, uint8_t* outPackageId, KeyedVector<uint8_t, IdmapEntries>* outMap) {
350f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    if (!assertIdmapHeader(idmap, size)) {
35157f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad        return UNKNOWN_ERROR;
35257f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad    }
353f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
354f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    size -= ResTable::IDMAP_HEADER_SIZE_BYTES;
355f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    if (size < sizeof(uint16_t) * 2) {
356f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        ALOGE("idmap: too small to contain any mapping");
35748d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        return UNKNOWN_ERROR;
35848d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    }
359f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
360f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    const uint16_t* data = reinterpret_cast<const uint16_t*>(
361f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            reinterpret_cast<const uint8_t*>(idmap) + ResTable::IDMAP_HEADER_SIZE_BYTES);
362f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
363f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    uint16_t targetPackageId = dtohs(*(data++));
364f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    if (targetPackageId == 0 || targetPackageId > 255) {
365f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        ALOGE("idmap: target package ID is invalid (%02x)", targetPackageId);
36648d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        return UNKNOWN_ERROR;
36748d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    }
368f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
369f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    uint16_t mapCount = dtohs(*(data++));
370f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    if (mapCount == 0) {
371f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        ALOGE("idmap: no mappings");
37248d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        return UNKNOWN_ERROR;
37348d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    }
374f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
375f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    if (mapCount > 255) {
376f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        ALOGW("idmap: too many mappings. Only 255 are possible but %u are present", (uint32_t) mapCount);
37748d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    }
37848d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad
379f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    while (size > sizeof(uint16_t) * 4) {
380f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        IdmapEntries entries;
381f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        status_t err = entries.setTo(data, size);
382f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        if (err != NO_ERROR) {
383f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            return err;
384f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        }
385f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
386f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        ssize_t index = outMap->add(entries.overlayTypeId(), entries);
387f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        if (index < 0) {
388f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            return NO_MEMORY;
389f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        }
390f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
391f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        data += entries.byteSize() / sizeof(uint16_t);
392f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        size -= entries.byteSize();
39357f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad    }
39448d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad
395f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    if (outPackageId != NULL) {
396f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        *outPackageId = static_cast<uint8_t>(targetPackageId);
397f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    }
39857f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad    return NO_ERROR;
39957f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad}
40057f4b77c89bafedf9468f9a636561c0c193405c9Mårten Kongstad
4016381dd4ff212a95be30d2b445d40ff419ab076b4Narayan KamathRes_png_9patch* Res_png_9patch::deserialize(void* inData)
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
4036381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath
4046381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(inData);
4056381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    patch->wasDeserialized = true;
4066381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    fill9patchOffsets(patch);
4076381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath
4086381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath    return patch;
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// --------------------------------------------------------------------
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// --------------------------------------------------------------------
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// --------------------------------------------------------------------
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectResStringPool::ResStringPool()
41619138468caf7050d482dc15f35a344eab11bb756Kenny Root    : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL)
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectResStringPool::ResStringPool(const void* data, size_t size, bool copyData)
42119138468caf7050d482dc15f35a344eab11bb756Kenny Root    : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL)
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    setTo(data, size, copyData);
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectResStringPool::~ResStringPool()
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uninit();
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
431de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinskivoid ResStringPool::setToEmpty()
432de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski{
433de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    uninit();
434de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski
435de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    mOwnedData = calloc(1, sizeof(ResStringPool_header));
436de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    ResStringPool_header* header = (ResStringPool_header*) mOwnedData;
437de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    mSize = 0;
438de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    mEntries = NULL;
439de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    mStrings = NULL;
440de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    mStringPoolSize = 0;
441de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    mEntryStyles = NULL;
442de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    mStyles = NULL;
443de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    mStylePoolSize = 0;
444de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    mHeader = (const ResStringPool_header*) header;
445de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski}
446de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!data || !size) {
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mError=BAD_TYPE);
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uninit();
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const bool notDeviceEndian = htods(0xf0) != 0xf0;
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (copyData || notDeviceEndian) {
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mOwnedData = malloc(size);
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mOwnedData == NULL) {
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return (mError=NO_MEMORY);
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        memcpy(mOwnedData, data, size);
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        data = mOwnedData;
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mHeader = (const ResStringPool_header*)data;
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (notDeviceEndian) {
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ResStringPool_header* h = const_cast<ResStringPool_header*>(mHeader);
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        h->header.headerSize = dtohs(mHeader->header.headerSize);
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        h->header.type = dtohs(mHeader->header.type);
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        h->header.size = dtohl(mHeader->header.size);
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        h->stringCount = dtohl(mHeader->stringCount);
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        h->styleCount = dtohl(mHeader->styleCount);
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        h->flags = dtohl(mHeader->flags);
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        h->stringsStart = dtohl(mHeader->stringsStart);
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        h->stylesStart = dtohl(mHeader->stylesStart);
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mHeader->header.headerSize > mHeader->header.size
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            || mHeader->header.size > size) {
4828564c8da817a845353d213acd8636b76f567b234Steve Block        ALOGW("Bad string block: header size %d or total size %d is larger than data size %d\n",
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                (int)mHeader->header.headerSize, (int)mHeader->header.size, (int)size);
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mError=BAD_TYPE);
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mSize = mHeader->header.size;
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEntries = (const uint32_t*)
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        (((const uint8_t*)data)+mHeader->header.headerSize);
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mHeader->stringCount > 0) {
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((mHeader->stringCount*sizeof(uint32_t) < mHeader->stringCount)  // uint32 overflow?
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            || (mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t)))
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                > size) {
4948564c8da817a845353d213acd8636b76f567b234Steve Block            ALOGW("Bad string block: entry of %d items extends past data size %d\n",
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (int)(mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t))),
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (int)size);
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return (mError=BAD_TYPE);
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
49919138468caf7050d482dc15f35a344eab11bb756Kenny Root
50019138468caf7050d482dc15f35a344eab11bb756Kenny Root        size_t charSize;
50119138468caf7050d482dc15f35a344eab11bb756Kenny Root        if (mHeader->flags&ResStringPool_header::UTF8_FLAG) {
50219138468caf7050d482dc15f35a344eab11bb756Kenny Root            charSize = sizeof(uint8_t);
50319138468caf7050d482dc15f35a344eab11bb756Kenny Root        } else {
5044bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski            charSize = sizeof(uint16_t);
50519138468caf7050d482dc15f35a344eab11bb756Kenny Root        }
50619138468caf7050d482dc15f35a344eab11bb756Kenny Root
507f28d505dc5f72d82cd791a5b9c7be3775eab75e5Adam Lesinski        // There should be at least space for the smallest string
508f28d505dc5f72d82cd791a5b9c7be3775eab75e5Adam Lesinski        // (2 bytes length, null terminator).
509f28d505dc5f72d82cd791a5b9c7be3775eab75e5Adam Lesinski        if (mHeader->stringsStart >= (mSize - sizeof(uint16_t))) {
5108564c8da817a845353d213acd8636b76f567b234Steve Block            ALOGW("Bad string block: string pool starts at %d, after total size %d\n",
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (int)mHeader->stringsStart, (int)mHeader->header.size);
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return (mError=BAD_TYPE);
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
514f28d505dc5f72d82cd791a5b9c7be3775eab75e5Adam Lesinski
515f28d505dc5f72d82cd791a5b9c7be3775eab75e5Adam Lesinski        mStrings = (const void*)
516f28d505dc5f72d82cd791a5b9c7be3775eab75e5Adam Lesinski            (((const uint8_t*)data) + mHeader->stringsStart);
517f28d505dc5f72d82cd791a5b9c7be3775eab75e5Adam Lesinski
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mHeader->styleCount == 0) {
519f28d505dc5f72d82cd791a5b9c7be3775eab75e5Adam Lesinski            mStringPoolSize = (mSize - mHeader->stringsStart) / charSize;
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
5215e4d9a04fdf9bf28650853cb19a1b06b0d543c51Kenny Root            // check invariant: styles starts before end of data
522f28d505dc5f72d82cd791a5b9c7be3775eab75e5Adam Lesinski            if (mHeader->stylesStart >= (mSize - sizeof(uint16_t))) {
5238564c8da817a845353d213acd8636b76f567b234Steve Block                ALOGW("Bad style block: style block starts at %d past data size of %d\n",
5245e4d9a04fdf9bf28650853cb19a1b06b0d543c51Kenny Root                    (int)mHeader->stylesStart, (int)mHeader->header.size);
5255e4d9a04fdf9bf28650853cb19a1b06b0d543c51Kenny Root                return (mError=BAD_TYPE);
5265e4d9a04fdf9bf28650853cb19a1b06b0d543c51Kenny Root            }
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // check invariant: styles follow the strings
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mHeader->stylesStart <= mHeader->stringsStart) {
5298564c8da817a845353d213acd8636b76f567b234Steve Block                ALOGW("Bad style block: style block starts at %d, before strings at %d\n",
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (int)mHeader->stylesStart, (int)mHeader->stringsStart);
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return (mError=BAD_TYPE);
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStringPoolSize =
53419138468caf7050d482dc15f35a344eab11bb756Kenny Root                (mHeader->stylesStart-mHeader->stringsStart)/charSize;
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // check invariant: stringCount > 0 requires a string pool to exist
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mStringPoolSize == 0) {
5398564c8da817a845353d213acd8636b76f567b234Steve Block            ALOGW("Bad string block: stringCount is %d but pool size is 0\n", (int)mHeader->stringCount);
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return (mError=BAD_TYPE);
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (notDeviceEndian) {
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            size_t i;
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uint32_t* e = const_cast<uint32_t*>(mEntries);
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (i=0; i<mHeader->stringCount; i++) {
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                e[i] = dtohl(mEntries[i]);
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
54919138468caf7050d482dc15f35a344eab11bb756Kenny Root            if (!(mHeader->flags&ResStringPool_header::UTF8_FLAG)) {
5504bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski                const uint16_t* strings = (const uint16_t*)mStrings;
5514bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski                uint16_t* s = const_cast<uint16_t*>(strings);
55219138468caf7050d482dc15f35a344eab11bb756Kenny Root                for (i=0; i<mStringPoolSize; i++) {
55319138468caf7050d482dc15f35a344eab11bb756Kenny Root                    s[i] = dtohs(strings[i]);
55419138468caf7050d482dc15f35a344eab11bb756Kenny Root                }
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
55819138468caf7050d482dc15f35a344eab11bb756Kenny Root        if ((mHeader->flags&ResStringPool_header::UTF8_FLAG &&
55919138468caf7050d482dc15f35a344eab11bb756Kenny Root                ((uint8_t*)mStrings)[mStringPoolSize-1] != 0) ||
56019138468caf7050d482dc15f35a344eab11bb756Kenny Root                (!mHeader->flags&ResStringPool_header::UTF8_FLAG &&
5614bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski                ((uint16_t*)mStrings)[mStringPoolSize-1] != 0)) {
5628564c8da817a845353d213acd8636b76f567b234Steve Block            ALOGW("Bad string block: last string is not 0-terminated\n");
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return (mError=BAD_TYPE);
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStrings = NULL;
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStringPoolSize = 0;
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mHeader->styleCount > 0) {
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEntryStyles = mEntries + mHeader->stringCount;
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // invariant: integer overflow in calculating mEntryStyles
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEntryStyles < mEntries) {
5748564c8da817a845353d213acd8636b76f567b234Steve Block            ALOGW("Bad string block: integer overflow finding styles\n");
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return (mError=BAD_TYPE);
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader) > (int)size) {
5798564c8da817a845353d213acd8636b76f567b234Steve Block            ALOGW("Bad string block: entry of %d styles extends past data size %d\n",
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (int)((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader),
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (int)size);
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return (mError=BAD_TYPE);
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStyles = (const uint32_t*)
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            (((const uint8_t*)data)+mHeader->stylesStart);
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mHeader->stylesStart >= mHeader->header.size) {
5878564c8da817a845353d213acd8636b76f567b234Steve Block            ALOGW("Bad string block: style pool starts %d, after total size %d\n",
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (int)mHeader->stylesStart, (int)mHeader->header.size);
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return (mError=BAD_TYPE);
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStylePoolSize =
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            (mHeader->header.size-mHeader->stylesStart)/sizeof(uint32_t);
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (notDeviceEndian) {
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            size_t i;
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uint32_t* e = const_cast<uint32_t*>(mEntryStyles);
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (i=0; i<mHeader->styleCount; i++) {
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                e[i] = dtohl(mEntryStyles[i]);
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uint32_t* s = const_cast<uint32_t*>(mStyles);
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (i=0; i<mStylePoolSize; i++) {
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                s[i] = dtohl(mStyles[i]);
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const ResStringPool_span endSpan = {
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            { htodl(ResStringPool_span::END) },
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            htodl(ResStringPool_span::END), htodl(ResStringPool_span::END)
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        };
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (memcmp(&mStyles[mStylePoolSize-(sizeof(endSpan)/sizeof(uint32_t))],
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                   &endSpan, sizeof(endSpan)) != 0) {
6128564c8da817a845353d213acd8636b76f567b234Steve Block            ALOGW("Bad string block: last style is not 0xFFFFFFFF-terminated\n");
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return (mError=BAD_TYPE);
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEntryStyles = NULL;
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStyles = NULL;
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStylePoolSize = 0;
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return (mError=NO_ERROR);
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t ResStringPool::getError() const
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return mError;
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid ResStringPool::uninit()
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mError = NO_INIT;
63219138468caf7050d482dc15f35a344eab11bb756Kenny Root    if (mHeader != NULL && mCache != NULL) {
63319138468caf7050d482dc15f35a344eab11bb756Kenny Root        for (size_t x = 0; x < mHeader->stringCount; x++) {
63419138468caf7050d482dc15f35a344eab11bb756Kenny Root            if (mCache[x] != NULL) {
63519138468caf7050d482dc15f35a344eab11bb756Kenny Root                free(mCache[x]);
63619138468caf7050d482dc15f35a344eab11bb756Kenny Root                mCache[x] = NULL;
63719138468caf7050d482dc15f35a344eab11bb756Kenny Root            }
63819138468caf7050d482dc15f35a344eab11bb756Kenny Root        }
63919138468caf7050d482dc15f35a344eab11bb756Kenny Root        free(mCache);
64019138468caf7050d482dc15f35a344eab11bb756Kenny Root        mCache = NULL;
64119138468caf7050d482dc15f35a344eab11bb756Kenny Root    }
642a1d82ff39315c962fbd6839f7a581ffaafe675e4Chris Dearman    if (mOwnedData) {
643a1d82ff39315c962fbd6839f7a581ffaafe675e4Chris Dearman        free(mOwnedData);
644a1d82ff39315c962fbd6839f7a581ffaafe675e4Chris Dearman        mOwnedData = NULL;
645a1d82ff39315c962fbd6839f7a581ffaafe675e4Chris Dearman    }
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
648300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root/**
649300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root * Strings in UTF-16 format have length indicated by a length encoded in the
650300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root * stored data. It is either 1 or 2 characters of length data. This allows a
651300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root * maximum length of 0x7FFFFFF (2147483647 bytes), but if you're storing that
652300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root * much data in a string, you're abusing them.
653300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root *
654300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root * If the high bit is set, then there are two characters or 4 bytes of length
655300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root * data encoded. In that case, drop the high bit of the first character and
656300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root * add it together with the next character.
657300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root */
658300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Rootstatic inline size_t
6594bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam LesinskidecodeLength(const uint16_t** str)
660300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root{
661300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root    size_t len = **str;
662300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root    if ((len & 0x8000) != 0) {
663300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root        (*str)++;
664300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root        len = ((len & 0x7FFF) << 16) | **str;
665300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root    }
666300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root    (*str)++;
667300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root    return len;
668300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root}
669300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root
670300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root/**
671300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root * Strings in UTF-8 format have length indicated by a length encoded in the
672300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root * stored data. It is either 1 or 2 characters of length data. This allows a
673300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root * maximum length of 0x7FFF (32767 bytes), but you should consider storing
674300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root * text in another way if you're using that much data in a single string.
675300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root *
676300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root * If the high bit is set, then there are two characters or 2 bytes of length
677300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root * data encoded. In that case, drop the high bit of the first character and
678300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root * add it together with the next character.
679300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root */
680300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Rootstatic inline size_t
681300ba6846949f5b21c6d93d7698dbc39716cf832Kenny RootdecodeLength(const uint8_t** str)
682300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root{
683300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root    size_t len = **str;
684300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root    if ((len & 0x80) != 0) {
685300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root        (*str)++;
686300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root        len = ((len & 0x7F) << 8) | **str;
687300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root    }
688300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root    (*str)++;
689300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root    return len;
690300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root}
691300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root
6924bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinskiconst char16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mError == NO_ERROR && idx < mHeader->stringCount) {
69519138468caf7050d482dc15f35a344eab11bb756Kenny Root        const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0;
6964bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski        const uint32_t off = mEntries[idx]/(isUTF8?sizeof(uint8_t):sizeof(uint16_t));
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (off < (mStringPoolSize-1)) {
69819138468caf7050d482dc15f35a344eab11bb756Kenny Root            if (!isUTF8) {
6994bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski                const uint16_t* strings = (uint16_t*)mStrings;
7004bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski                const uint16_t* str = strings+off;
701300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root
702300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                *u16len = decodeLength(&str);
703300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                if ((uint32_t)(str+*u16len-strings) < mStringPoolSize) {
7044bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski                    return reinterpret_cast<const char16_t*>(str);
70519138468caf7050d482dc15f35a344eab11bb756Kenny Root                } else {
7068564c8da817a845353d213acd8636b76f567b234Steve Block                    ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
707300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                            (int)idx, (int)(str+*u16len-strings), (int)mStringPoolSize);
70819138468caf7050d482dc15f35a344eab11bb756Kenny Root                }
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
71019138468caf7050d482dc15f35a344eab11bb756Kenny Root                const uint8_t* strings = (uint8_t*)mStrings;
711300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                const uint8_t* u8str = strings+off;
712300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root
713300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                *u16len = decodeLength(&u8str);
714300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                size_t u8len = decodeLength(&u8str);
715300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root
716300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                // encLen must be less than 0x7FFF due to encoding.
717300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                if ((uint32_t)(u8str+u8len-strings) < mStringPoolSize) {
71819138468caf7050d482dc15f35a344eab11bb756Kenny Root                    AutoMutex lock(mDecodeLock);
719300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root
720d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn                    if (mCache == NULL) {
721d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn#ifndef HAVE_ANDROID_OS
722d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn                        STRING_POOL_NOISY(ALOGI("CREATING STRING CACHE OF %d bytes",
723d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn                                mHeader->stringCount*sizeof(char16_t**)));
724d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn#else
725d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn                        // We do not want to be in this case when actually running Android.
726d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn                        ALOGW("CREATING STRING CACHE OF %d bytes",
727d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn                                mHeader->stringCount*sizeof(char16_t**));
728d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn#endif
729d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn                        mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**));
730d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn                        if (mCache == NULL) {
731d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn                            ALOGW("No memory trying to allocate decode cache table of %d bytes\n",
732d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn                                    (int)(mHeader->stringCount*sizeof(char16_t**)));
733d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn                            return NULL;
734d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn                        }
735d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn                    }
736d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn
73719138468caf7050d482dc15f35a344eab11bb756Kenny Root                    if (mCache[idx] != NULL) {
73819138468caf7050d482dc15f35a344eab11bb756Kenny Root                        return mCache[idx];
73919138468caf7050d482dc15f35a344eab11bb756Kenny Root                    }
740300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root
741300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                    ssize_t actualLen = utf8_to_utf16_length(u8str, u8len);
742300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                    if (actualLen < 0 || (size_t)actualLen != *u16len) {
7438564c8da817a845353d213acd8636b76f567b234Steve Block                        ALOGW("Bad string block: string #%lld decoded length is not correct "
744300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                                "%lld vs %llu\n",
745300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                                (long long)idx, (long long)actualLen, (long long)*u16len);
746300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                        return NULL;
747300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                    }
748300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root
749300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                    char16_t *u16str = (char16_t *)calloc(*u16len+1, sizeof(char16_t));
75019138468caf7050d482dc15f35a344eab11bb756Kenny Root                    if (!u16str) {
7518564c8da817a845353d213acd8636b76f567b234Steve Block                        ALOGW("No memory when trying to allocate decode cache for string #%d\n",
75219138468caf7050d482dc15f35a344eab11bb756Kenny Root                                (int)idx);
75319138468caf7050d482dc15f35a344eab11bb756Kenny Root                        return NULL;
75419138468caf7050d482dc15f35a344eab11bb756Kenny Root                    }
755300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root
756d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn                    STRING_POOL_NOISY(ALOGI("Caching UTF8 string: %s", u8str));
757300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                    utf8_to_utf16(u8str, u8len, u16str);
75819138468caf7050d482dc15f35a344eab11bb756Kenny Root                    mCache[idx] = u16str;
75919138468caf7050d482dc15f35a344eab11bb756Kenny Root                    return u16str;
76019138468caf7050d482dc15f35a344eab11bb756Kenny Root                } else {
7618564c8da817a845353d213acd8636b76f567b234Steve Block                    ALOGW("Bad string block: string #%lld extends to %lld, past end at %lld\n",
762300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                            (long long)idx, (long long)(u8str+u8len-strings),
763300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root                            (long long)mStringPoolSize);
76419138468caf7050d482dc15f35a344eab11bb756Kenny Root                }
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
7678564c8da817a845353d213acd8636b76f567b234Steve Block            ALOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (int)idx, (int)(off*sizeof(uint16_t)),
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (int)(mStringPoolSize*sizeof(uint16_t)));
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NULL;
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
775780d2a1b714724d85227141c76b3c64f543f00b4Kenny Rootconst char* ResStringPool::string8At(size_t idx, size_t* outLen) const
776780d2a1b714724d85227141c76b3c64f543f00b4Kenny Root{
777780d2a1b714724d85227141c76b3c64f543f00b4Kenny Root    if (mError == NO_ERROR && idx < mHeader->stringCount) {
778d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn        if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) == 0) {
779d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn            return NULL;
780d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn        }
781d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn        const uint32_t off = mEntries[idx]/sizeof(char);
782780d2a1b714724d85227141c76b3c64f543f00b4Kenny Root        if (off < (mStringPoolSize-1)) {
783d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn            const uint8_t* strings = (uint8_t*)mStrings;
784d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn            const uint8_t* str = strings+off;
785d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn            *outLen = decodeLength(&str);
786d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn            size_t encLen = decodeLength(&str);
787d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn            if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
788d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn                return (const char*)str;
789d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn            } else {
790d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn                ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
791d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn                        (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
792780d2a1b714724d85227141c76b3c64f543f00b4Kenny Root            }
793780d2a1b714724d85227141c76b3c64f543f00b4Kenny Root        } else {
7948564c8da817a845353d213acd8636b76f567b234Steve Block            ALOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
795780d2a1b714724d85227141c76b3c64f543f00b4Kenny Root                    (int)idx, (int)(off*sizeof(uint16_t)),
796780d2a1b714724d85227141c76b3c64f543f00b4Kenny Root                    (int)(mStringPoolSize*sizeof(uint16_t)));
797780d2a1b714724d85227141c76b3c64f543f00b4Kenny Root        }
798780d2a1b714724d85227141c76b3c64f543f00b4Kenny Root    }
799780d2a1b714724d85227141c76b3c64f543f00b4Kenny Root    return NULL;
800780d2a1b714724d85227141c76b3c64f543f00b4Kenny Root}
801780d2a1b714724d85227141c76b3c64f543f00b4Kenny Root
8026c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackbornconst String8 ResStringPool::string8ObjectAt(size_t idx) const
8036c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn{
8046c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    size_t len;
8054b2d0f20db2e0f9395a0c12ed5d4b6020eb272cbAdam Lesinski    const char *str = string8At(idx, &len);
8066c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    if (str != NULL) {
8074b2d0f20db2e0f9395a0c12ed5d4b6020eb272cbAdam Lesinski        return String8(str, len);
8086c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    }
8094b2d0f20db2e0f9395a0c12ed5d4b6020eb272cbAdam Lesinski
8104b2d0f20db2e0f9395a0c12ed5d4b6020eb272cbAdam Lesinski    const char16_t *str16 = stringAt(idx, &len);
8114b2d0f20db2e0f9395a0c12ed5d4b6020eb272cbAdam Lesinski    if (str16 != NULL) {
8124b2d0f20db2e0f9395a0c12ed5d4b6020eb272cbAdam Lesinski        return String8(str16, len);
8134b2d0f20db2e0f9395a0c12ed5d4b6020eb272cbAdam Lesinski    }
8144b2d0f20db2e0f9395a0c12ed5d4b6020eb272cbAdam Lesinski    return String8();
8156c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn}
8166c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectconst ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return styleAt(ref.index);
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectconst ResStringPool_span* ResStringPool::styleAt(size_t idx) const
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mError == NO_ERROR && idx < mHeader->styleCount) {
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const uint32_t off = (mEntryStyles[idx]/sizeof(uint32_t));
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (off < mStylePoolSize) {
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return (const ResStringPool_span*)(mStyles+off);
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
8298564c8da817a845353d213acd8636b76f567b234Steve Block            ALOGW("Bad string block: style #%d entry is at %d, past end at %d\n",
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (int)idx, (int)(off*sizeof(uint32_t)),
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (int)(mStylePoolSize*sizeof(uint32_t)));
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NULL;
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mError != NO_ERROR) {
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mError;
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size_t len;
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
845d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn    if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) {
846d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn        STRING_POOL_NOISY(ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string()));
847d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn
848d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn        // The string pool contains UTF 8 strings; we don't want to cause
849d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn        // temporary UTF-16 strings to be created as we search.
850d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn        if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
851d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn            // Do a binary search for the string...  this is a little tricky,
852d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn            // because the strings are sorted with strzcmp16().  So to match
853d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn            // the ordering, we need to convert strings in the pool to UTF-16.
854d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn            // But we don't want to hit the cache, so instead we will have a
855d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn            // local temporary allocation for the conversions.
856d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn            char16_t* convBuffer = (char16_t*)malloc(strLen+4);
857d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn            ssize_t l = 0;
858d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn            ssize_t h = mHeader->stringCount-1;
859d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn
860d45c68dd24fe3dd510af5a9591b5e2f509b56772Dianne Hackborn            ssize_t mid;
861