AssetManager.cpp revision 30113131fb958850ef92c6a8f7f2aa2ed92a8ffe
116c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
216c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Copyright (C) 2006 The Android Open Source Project
316c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
416c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
516c4d154dca43c662571129af31b27433b919a32Adam Lesinski * you may not use this file except in compliance with the License.
616c4d154dca43c662571129af31b27433b919a32Adam Lesinski * You may obtain a copy of the License at
716c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
816c4d154dca43c662571129af31b27433b919a32Adam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
916c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
1016c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Unless required by applicable law or agreed to in writing, software
1116c4d154dca43c662571129af31b27433b919a32Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
1216c4d154dca43c662571129af31b27433b919a32Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1316c4d154dca43c662571129af31b27433b919a32Adam Lesinski * See the License for the specific language governing permissions and
1416c4d154dca43c662571129af31b27433b919a32Adam Lesinski * limitations under the License.
1516c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
1616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
1716c4d154dca43c662571129af31b27433b919a32Adam Lesinski//
1816c4d154dca43c662571129af31b27433b919a32Adam Lesinski// Provide access to read-only assets.
1916c4d154dca43c662571129af31b27433b919a32Adam Lesinski//
2016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
2116c4d154dca43c662571129af31b27433b919a32Adam Lesinski#define LOG_TAG "asset"
2216c4d154dca43c662571129af31b27433b919a32Adam Lesinski#define ATRACE_TAG ATRACE_TAG_RESOURCES
2316c4d154dca43c662571129af31b27433b919a32Adam Lesinski//#define LOG_NDEBUG 0
2416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
2516c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <androidfw/Asset.h>
2616c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <androidfw/AssetDir.h>
2716c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <androidfw/AssetManager.h>
2816c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <androidfw/misc.h>
2916c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <androidfw/ResourceTypes.h>
3016c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <androidfw/ZipFileRO.h>
3116c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <utils/Atomic.h>
3216c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <utils/Log.h>
3316c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <utils/String8.h>
3416c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <utils/String8.h>
3516c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <utils/threads.h>
3616c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <utils/Timers.h>
3716c4d154dca43c662571129af31b27433b919a32Adam Lesinski#ifdef HAVE_ANDROID_OS
3816c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <cutils/trace.h>
3916c4d154dca43c662571129af31b27433b919a32Adam Lesinski#endif
4016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
4116c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <assert.h>
4216c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <dirent.h>
4316c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <errno.h>
4448d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad#include <string.h> // strerror
4516c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <strings.h>
4616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
4716c4d154dca43c662571129af31b27433b919a32Adam Lesinski#ifndef TEMP_FAILURE_RETRY
4816c4d154dca43c662571129af31b27433b919a32Adam Lesinski/* Used to retry syscalls that can return EINTR. */
4916c4d154dca43c662571129af31b27433b919a32Adam Lesinski#define TEMP_FAILURE_RETRY(exp) ({         \
5016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    typeof (exp) _rc;                      \
5116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    do {                                   \
5216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        _rc = (exp);                       \
5316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    } while (_rc == -1 && errno == EINTR); \
5416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    _rc; })
5516c4d154dca43c662571129af31b27433b919a32Adam Lesinski#endif
5616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
5716c4d154dca43c662571129af31b27433b919a32Adam Lesinski#ifdef HAVE_ANDROID_OS
5816c4d154dca43c662571129af31b27433b919a32Adam Lesinski#define MY_TRACE_BEGIN(x) ATRACE_BEGIN(x)
5916c4d154dca43c662571129af31b27433b919a32Adam Lesinski#define MY_TRACE_END() ATRACE_END()
6016c4d154dca43c662571129af31b27433b919a32Adam Lesinski#else
6116c4d154dca43c662571129af31b27433b919a32Adam Lesinski#define MY_TRACE_BEGIN(x)
6216c4d154dca43c662571129af31b27433b919a32Adam Lesinski#define MY_TRACE_END()
6316c4d154dca43c662571129af31b27433b919a32Adam Lesinski#endif
6416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
6516c4d154dca43c662571129af31b27433b919a32Adam Lesinskiusing namespace android;
6616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
6716c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
6816c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Names for default app, locale, and vendor.  We might want to change
6916c4d154dca43c662571129af31b27433b919a32Adam Lesinski * these to be an actual locale, e.g. always use en-US as the default.
7016c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
7116c4d154dca43c662571129af31b27433b919a32Adam Lesinskistatic const char* kDefaultLocale = "default";
7216c4d154dca43c662571129af31b27433b919a32Adam Lesinskistatic const char* kDefaultVendor = "default";
7316c4d154dca43c662571129af31b27433b919a32Adam Lesinskistatic const char* kAssetsRoot = "assets";
7416c4d154dca43c662571129af31b27433b919a32Adam Lesinskistatic const char* kAppZipName = NULL; //"classes.jar";
7516c4d154dca43c662571129af31b27433b919a32Adam Lesinskistatic const char* kSystemAssets = "framework/framework-res.apk";
7648d22323ce39f9aab003dce74456889b6414af55Mårten Kongstadstatic const char* kResourceCache = "resource-cache";
77de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinskistatic const char* kAndroidManifest = "AndroidManifest.xml";
7816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
7916c4d154dca43c662571129af31b27433b919a32Adam Lesinskistatic const char* kExcludeExtension = ".EXCLUDE";
8016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
8116c4d154dca43c662571129af31b27433b919a32Adam Lesinskistatic Asset* const kExcludedAsset = (Asset*) 0xd000000d;
8216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
8316c4d154dca43c662571129af31b27433b919a32Adam Lesinskistatic volatile int32_t gCount = 0;
8416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
8565a05fd56dbc9fd9c2511a97f49c445a748fb3c5Mårten Kongstadconst char* AssetManager::RESOURCES_FILENAME = "resources.arsc";
8648d22323ce39f9aab003dce74456889b6414af55Mårten Kongstadconst char* AssetManager::IDMAP_BIN = "/system/bin/idmap";
8748d22323ce39f9aab003dce74456889b6414af55Mårten Kongstadconst char* AssetManager::OVERLAY_DIR = "/vendor/overlay";
8848d22323ce39f9aab003dce74456889b6414af55Mårten Kongstadconst char* AssetManager::TARGET_PACKAGE_NAME = "android";
8948d22323ce39f9aab003dce74456889b6414af55Mårten Kongstadconst char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk";
9048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstadconst char* AssetManager::IDMAP_DIR = "/data/resource-cache";
9165a05fd56dbc9fd9c2511a97f49c445a748fb3c5Mårten Kongstad
9216c4d154dca43c662571129af31b27433b919a32Adam Lesinskinamespace {
9316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    String8 idmapPathForPackagePath(const String8& pkgPath)
9416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    {
9516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        const char* root = getenv("ANDROID_DATA");
9616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set");
9716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        String8 path(root);
9848d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        path.appendPath(kResourceCache);
9916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
10016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        char buf[256]; // 256 chars should be enough for anyone...
10116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        strncpy(buf, pkgPath.string(), 255);
10216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        buf[255] = '\0';
10316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        char* filename = buf;
10416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        while (*filename && *filename == '/') {
10516c4d154dca43c662571129af31b27433b919a32Adam Lesinski            ++filename;
10616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
10716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        char* p = filename;
10816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        while (*p) {
10916c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (*p == '/') {
11016c4d154dca43c662571129af31b27433b919a32Adam Lesinski                *p = '@';
11116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            }
11216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            ++p;
11316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
11416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        path.appendPath(filename);
11516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        path.append("@idmap");
11616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
11716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return path;
11816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
11916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
12016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /*
12116c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * Like strdup(), but uses C++ "new" operator instead of malloc.
12216c4d154dca43c662571129af31b27433b919a32Adam Lesinski     */
12316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    static char* strdupNew(const char* str)
12416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    {
12516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        char* newStr;
12616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        int len;
12716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
12816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (str == NULL)
12916c4d154dca43c662571129af31b27433b919a32Adam Lesinski            return NULL;
13016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
13116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        len = strlen(str);
13216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        newStr = new char[len+1];
13316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        memcpy(newStr, str, len+1);
13416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
13516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return newStr;
13616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
13716c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
13816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
13916c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
14016c4d154dca43c662571129af31b27433b919a32Adam Lesinski * ===========================================================================
14116c4d154dca43c662571129af31b27433b919a32Adam Lesinski *      AssetManager
14216c4d154dca43c662571129af31b27433b919a32Adam Lesinski * ===========================================================================
14316c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
14416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
14516c4d154dca43c662571129af31b27433b919a32Adam Lesinskiint32_t AssetManager::getGlobalCount()
14616c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
14716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return gCount;
14816c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
14916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
15016c4d154dca43c662571129af31b27433b919a32Adam LesinskiAssetManager::AssetManager(CacheMode cacheMode)
15116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    : mLocale(NULL), mVendor(NULL),
15216c4d154dca43c662571129af31b27433b919a32Adam Lesinski      mResources(NULL), mConfig(new ResTable_config),
15316c4d154dca43c662571129af31b27433b919a32Adam Lesinski      mCacheMode(cacheMode), mCacheValid(false)
15416c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
15516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    int count = android_atomic_inc(&gCount)+1;
15616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    //ALOGI("Creating AssetManager %p #%d\n", this, count);
15716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    memset(mConfig, 0, sizeof(ResTable_config));
15816c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
15916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
16016c4d154dca43c662571129af31b27433b919a32Adam LesinskiAssetManager::~AssetManager(void)
16116c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
16216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    int count = android_atomic_dec(&gCount);
16316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    //ALOGI("Destroying AssetManager in %p #%d\n", this, count);
16416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
16516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    delete mConfig;
16616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    delete mResources;
16716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
16816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    // don't have a String class yet, so make sure we clean up
16916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    delete[] mLocale;
17016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    delete[] mVendor;
17116c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
17216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
173a0c6260705c841f501282e0e337970ca9a00e064Narayan Kamathbool AssetManager::addAssetPath(const String8& path, int32_t* cookie)
17416c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
17516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AutoMutex _l(mLock);
17616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
17716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    asset_path ap;
17816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
17916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    String8 realPath(path);
18016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (kAppZipName) {
18116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        realPath.appendPath(kAppZipName);
18216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
18316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    ap.type = ::getFileType(realPath.string());
18416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (ap.type == kFileTypeRegular) {
18516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        ap.path = realPath;
18616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    } else {
18716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        ap.path = path;
18816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        ap.type = ::getFileType(path.string());
18916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (ap.type != kFileTypeDirectory && ap.type != kFileTypeRegular) {
19016c4d154dca43c662571129af31b27433b919a32Adam Lesinski            ALOGW("Asset path %s is neither a directory nor file (type=%d).",
19116c4d154dca43c662571129af31b27433b919a32Adam Lesinski                 path.string(), (int)ap.type);
19216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            return false;
19316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
19416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
19516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
19616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    // Skip if we have it already.
19716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    for (size_t i=0; i<mAssetPaths.size(); i++) {
19816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (mAssetPaths[i].path == ap.path) {
19916c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (cookie) {
200a0c6260705c841f501282e0e337970ca9a00e064Narayan Kamath                *cookie = static_cast<int32_t>(i+1);
20116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            }
20216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            return true;
20316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
20416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
20516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
20616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    ALOGV("In %p Asset %s path: %s", this,
20716c4d154dca43c662571129af31b27433b919a32Adam Lesinski         ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string());
20816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
209de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    // Check that the path has an AndroidManifest.xml
210de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    Asset* manifestAsset = const_cast<AssetManager*>(this)->openNonAssetInPathLocked(
211de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski            kAndroidManifest, Asset::ACCESS_BUFFER, ap);
212de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    if (manifestAsset == NULL) {
213de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        // This asset path does not contain any resources.
214de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        delete manifestAsset;
215de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        return false;
216de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    }
217de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    delete manifestAsset;
218de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski
21916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mAssetPaths.add(ap);
22016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
22116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    // new paths are always added at the end
22216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (cookie) {
223a0c6260705c841f501282e0e337970ca9a00e064Narayan Kamath        *cookie = static_cast<int32_t>(mAssetPaths.size());
22416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
22516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
22648d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad#ifdef HAVE_ANDROID_OS
22748d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    // Load overlays, if any
22848d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    asset_path oap;
22948d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    for (size_t idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) {
23048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        mAssetPaths.add(oap);
23116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
23248d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad#endif
23316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
2347df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    if (mResources != NULL) {
2357df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        appendPathToResTable(ap);
2367df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    }
2377df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba
23816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return true;
23916c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
24016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
24148d22323ce39f9aab003dce74456889b6414af55Mårten Kongstadbool AssetManager::addOverlayPath(const String8& packagePath, int32_t* cookie)
24265a05fd56dbc9fd9c2511a97f49c445a748fb3c5Mårten Kongstad{
24348d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    const String8 idmapPath = idmapPathForPackagePath(packagePath);
24465a05fd56dbc9fd9c2511a97f49c445a748fb3c5Mårten Kongstad
24548d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    AutoMutex _l(mLock);
24665a05fd56dbc9fd9c2511a97f49c445a748fb3c5Mårten Kongstad
24748d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    for (size_t i = 0; i < mAssetPaths.size(); ++i) {
24848d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        if (mAssetPaths[i].idmap == idmapPath) {
24948d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad           *cookie = static_cast<int32_t>(i + 1);
25048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad            return true;
25148d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad         }
25248d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad     }
25365a05fd56dbc9fd9c2511a97f49c445a748fb3c5Mårten Kongstad
25448d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    Asset* idmap = NULL;
25548d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    if ((idmap = openAssetFromFileLocked(idmapPath, Asset::ACCESS_BUFFER)) == NULL) {
25648d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        ALOGW("failed to open idmap file %s\n", idmapPath.string());
25716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return false;
25816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
25916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
26048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    String8 targetPath;
26148d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    String8 overlayPath;
26248d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    if (!ResTable::getIdmapInfo(idmap->getBuffer(false), idmap->getLength(),
263f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski                NULL, NULL, NULL, &targetPath, &overlayPath)) {
26448d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        ALOGW("failed to read idmap file %s\n", idmapPath.string());
26548d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        delete idmap;
26616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return false;
26716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
26848d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    delete idmap;
26916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
27048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    if (overlayPath != packagePath) {
27148d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        ALOGW("idmap file %s inconcistent: expected path %s does not match actual path %s\n",
27248d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad                idmapPath.string(), packagePath.string(), overlayPath.string());
27316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return false;
27416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
27548d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    if (access(targetPath.string(), R_OK) != 0) {
27648d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        ALOGW("failed to access file %s: %s\n", targetPath.string(), strerror(errno));
27716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return false;
27816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
27948d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    if (access(idmapPath.string(), R_OK) != 0) {
28048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        ALOGW("failed to access file %s: %s\n", idmapPath.string(), strerror(errno));
28116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return false;
28216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
28348d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    if (access(overlayPath.string(), R_OK) != 0) {
28448d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        ALOGW("failed to access file %s: %s\n", overlayPath.string(), strerror(errno));
28516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return false;
28616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
287560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath
28848d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    asset_path oap;
28948d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    oap.path = overlayPath;
29048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    oap.type = ::getFileType(overlayPath.string());
29148d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    oap.idmap = idmapPath;
29248d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad#if 0
29348d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    ALOGD("Overlay added: targetPath=%s overlayPath=%s idmapPath=%s\n",
29448d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad            targetPath.string(), overlayPath.string(), idmapPath.string());
29548d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad#endif
29648d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    mAssetPaths.add(oap);
29748d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    *cookie = static_cast<int32_t>(mAssetPaths.size());
298560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath
29930113131fb958850ef92c6a8f7f2aa2ed92a8ffeMårten Kongstad    if (mResources != NULL) {
30030113131fb958850ef92c6a8f7f2aa2ed92a8ffeMårten Kongstad        appendPathToResTable(oap);
30130113131fb958850ef92c6a8f7f2aa2ed92a8ffeMårten Kongstad    }
30230113131fb958850ef92c6a8f7f2aa2ed92a8ffeMårten Kongstad
30348d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    return true;
30448d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad }
30516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
30648d22323ce39f9aab003dce74456889b6414af55Mårten Kongstadbool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApkPath,
3071cbea39fe1740d7d1c3e4aa0e4771a99a56c79efNick Kralevich        uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, size_t* outSize)
30816c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
30948d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    AutoMutex _l(mLock);
31048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    const String8 paths[2] = { String8(targetApkPath), String8(overlayApkPath) };
31116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    ResTable tables[2];
31216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
31316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    for (int i = 0; i < 2; ++i) {
31416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        asset_path ap;
31516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        ap.type = kFileTypeRegular;
31648d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        ap.path = paths[i];
31716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        Asset* ass = openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap);
31816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (ass == NULL) {
31916c4d154dca43c662571129af31b27433b919a32Adam Lesinski            ALOGW("failed to find resources.arsc in %s\n", ap.path.string());
32048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad            return false;
32116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
322f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski        tables[i].add(ass);
32316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
32416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
32548d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    return tables[0].createIdmap(tables[1], targetCrc, overlayCrc,
32648d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad            targetApkPath, overlayApkPath, (void**)outData, outSize) == NO_ERROR;
32716c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
32816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
32916c4d154dca43c662571129af31b27433b919a32Adam Lesinskibool AssetManager::addDefaultAssets()
33016c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
33116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    const char* root = getenv("ANDROID_ROOT");
33216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_ROOT not set");
33316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
33416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    String8 path(root);
33516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    path.appendPath(kSystemAssets);
33616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
33716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return addAssetPath(path, NULL);
33816c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
33916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
340a0c6260705c841f501282e0e337970ca9a00e064Narayan Kamathint32_t AssetManager::nextAssetPath(const int32_t cookie) const
34116c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
34216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AutoMutex _l(mLock);
343a0c6260705c841f501282e0e337970ca9a00e064Narayan Kamath    const size_t next = static_cast<size_t>(cookie) + 1;
344a0c6260705c841f501282e0e337970ca9a00e064Narayan Kamath    return next > mAssetPaths.size() ? -1 : next;
34516c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
34616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
347a0c6260705c841f501282e0e337970ca9a00e064Narayan KamathString8 AssetManager::getAssetPath(const int32_t cookie) const
34816c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
34916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AutoMutex _l(mLock);
350a0c6260705c841f501282e0e337970ca9a00e064Narayan Kamath    const size_t which = static_cast<size_t>(cookie) - 1;
35116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (which < mAssetPaths.size()) {
35216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return mAssetPaths[which].path;
35316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
35416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return String8();
35516c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
35616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
35716c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
35816c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Set the current locale.  Use NULL to indicate no locale.
35916c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
36016c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Close and reopen Zip archives as appropriate, and reset cached
36116c4d154dca43c662571129af31b27433b919a32Adam Lesinski * information in the locale-specific sections of the tree.
36216c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
36316c4d154dca43c662571129af31b27433b919a32Adam Lesinskivoid AssetManager::setLocale(const char* locale)
36416c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
36516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AutoMutex _l(mLock);
36616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    setLocaleLocked(locale);
36716c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
36816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
369e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath
370e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamathstatic const char kFilPrefix[] = "fil";
371e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamathstatic const char kTlPrefix[] = "tl";
372e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath
373e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath// The sizes of the prefixes, excluding the 0 suffix.
374e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath// char.
375e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamathstatic const int kFilPrefixLen = sizeof(kFilPrefix) - 1;
376e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamathstatic const int kTlPrefixLen = sizeof(kTlPrefix) - 1;
377e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath
37816c4d154dca43c662571129af31b27433b919a32Adam Lesinskivoid AssetManager::setLocaleLocked(const char* locale)
37916c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
38016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (mLocale != NULL) {
38116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        /* previously set, purge cached data */
38216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        purgeFileNameCacheLocked();
38316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        //mZipSet.purgeLocale();
38416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        delete[] mLocale;
38516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
386c367d48c55e5a3fa0df14fd62889e4bb6b63cb01Elliott Hughes
387e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath    // If we're attempting to set a locale that starts with "fil",
388e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath    // we should convert it to "tl" for backwards compatibility since
389e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath    // we've been using "tl" instead of "fil" prior to L.
390e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath    //
391e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath    // If the resource table already has entries for "fil", we use that
392e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath    // instead of attempting a fallback.
393e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath    if (strncmp(locale, kFilPrefix, kFilPrefixLen) == 0) {
394e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath        Vector<String8> locales;
395fec5106c8ea5791614385c17bd1bf0ecff9afe9aNarayan Kamath        ResTable* res = mResources;
396fec5106c8ea5791614385c17bd1bf0ecff9afe9aNarayan Kamath        if (res != NULL) {
397fec5106c8ea5791614385c17bd1bf0ecff9afe9aNarayan Kamath            res->getLocales(&locales);
398fec5106c8ea5791614385c17bd1bf0ecff9afe9aNarayan Kamath        }
399e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath        const size_t localesSize = locales.size();
400e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath        bool hasFil = false;
401e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath        for (size_t i = 0; i < localesSize; ++i) {
402e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath            if (locales[i].find(kFilPrefix) == 0) {
403e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath                hasFil = true;
404e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath                break;
405e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath            }
406e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath        }
407e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath
408e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath
409e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath        if (!hasFil) {
410e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath            const size_t newLocaleLen = strlen(locale);
411e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath            // This isn't a bug. We really do want mLocale to be 1 byte
412e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath            // shorter than locale, because we're replacing "fil-" with
413e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath            // "tl-".
414e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath            mLocale = new char[newLocaleLen];
415e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath            // Copy over "tl".
416e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath            memcpy(mLocale, kTlPrefix, kTlPrefixLen);
417e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath            // Copy the rest of |locale|, including the terminating '\0'.
418e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath            memcpy(mLocale + kTlPrefixLen, locale + kFilPrefixLen,
419e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath                   newLocaleLen - kFilPrefixLen + 1);
420e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath            updateResourceParamsLocked();
421e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath            return;
422e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath        }
423e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath    }
424e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath
42516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mLocale = strdupNew(locale);
42616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    updateResourceParamsLocked();
42716c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
42816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
42916c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
43016c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Set the current vendor.  Use NULL to indicate no vendor.
43116c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
43216c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Close and reopen Zip archives as appropriate, and reset cached
43316c4d154dca43c662571129af31b27433b919a32Adam Lesinski * information in the vendor-specific sections of the tree.
43416c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
43516c4d154dca43c662571129af31b27433b919a32Adam Lesinskivoid AssetManager::setVendor(const char* vendor)
43616c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
43716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AutoMutex _l(mLock);
43816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
43916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (mVendor != NULL) {
44016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        /* previously set, purge cached data */
44116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        purgeFileNameCacheLocked();
44216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        //mZipSet.purgeVendor();
44316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        delete[] mVendor;
44416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
44516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mVendor = strdupNew(vendor);
44616c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
44716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
44816c4d154dca43c662571129af31b27433b919a32Adam Lesinskivoid AssetManager::setConfiguration(const ResTable_config& config, const char* locale)
44916c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
45016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AutoMutex _l(mLock);
45116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    *mConfig = config;
45216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (locale) {
45316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        setLocaleLocked(locale);
45416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    } else if (config.language[0] != 0) {
45591447d88f2bdf9c2bf8d1a53570efef6172fba74Narayan Kamath        char spec[RESTABLE_MAX_LOCALE_LEN];
45691447d88f2bdf9c2bf8d1a53570efef6172fba74Narayan Kamath        config.getBcp47Locale(spec);
45716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        setLocaleLocked(spec);
45816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    } else {
45916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        updateResourceParamsLocked();
46016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
46116c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
46216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
46316c4d154dca43c662571129af31b27433b919a32Adam Lesinskivoid AssetManager::getConfiguration(ResTable_config* outConfig) const
46416c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
46516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AutoMutex _l(mLock);
46616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    *outConfig = *mConfig;
46716c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
46816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
46916c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
47016c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Open an asset.
47116c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
47216c4d154dca43c662571129af31b27433b919a32Adam Lesinski * The data could be;
47316c4d154dca43c662571129af31b27433b919a32Adam Lesinski *  - In a file on disk (assetBase + fileName).
47416c4d154dca43c662571129af31b27433b919a32Adam Lesinski *  - In a compressed file on disk (assetBase + fileName.gz).
47516c4d154dca43c662571129af31b27433b919a32Adam Lesinski *  - In a Zip archive, uncompressed or compressed.
47616c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
47716c4d154dca43c662571129af31b27433b919a32Adam Lesinski * It can be in a number of different directories and Zip archives.
47816c4d154dca43c662571129af31b27433b919a32Adam Lesinski * The search order is:
47916c4d154dca43c662571129af31b27433b919a32Adam Lesinski *  - [appname]
48016c4d154dca43c662571129af31b27433b919a32Adam Lesinski *    - locale + vendor
48116c4d154dca43c662571129af31b27433b919a32Adam Lesinski *    - "default" + vendor
48216c4d154dca43c662571129af31b27433b919a32Adam Lesinski *    - locale + "default"
48316c4d154dca43c662571129af31b27433b919a32Adam Lesinski *    - "default + "default"
48416c4d154dca43c662571129af31b27433b919a32Adam Lesinski *  - "common"
48516c4d154dca43c662571129af31b27433b919a32Adam Lesinski *    - (same as above)
48616c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
48716c4d154dca43c662571129af31b27433b919a32Adam Lesinski * To find a particular file, we have to try up to eight paths with
48816c4d154dca43c662571129af31b27433b919a32Adam Lesinski * all three forms of data.
48916c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
49016c4d154dca43c662571129af31b27433b919a32Adam Lesinski * We should probably reject requests for "illegal" filenames, e.g. those
49116c4d154dca43c662571129af31b27433b919a32Adam Lesinski * with illegal characters or "../" backward relative paths.
49216c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
49316c4d154dca43c662571129af31b27433b919a32Adam LesinskiAsset* AssetManager::open(const char* fileName, AccessMode mode)
49416c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
49516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AutoMutex _l(mLock);
49616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
49716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
49816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
49916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
50016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (mCacheMode != CACHE_OFF && !mCacheValid)
50116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        loadFileNameCacheLocked();
50216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
50316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    String8 assetName(kAssetsRoot);
50416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    assetName.appendPath(fileName);
50516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
50616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /*
50716c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * For each top-level asset path, search for the asset.
50816c4d154dca43c662571129af31b27433b919a32Adam Lesinski     */
50916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
51016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    size_t i = mAssetPaths.size();
51116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    while (i > 0) {
51216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        i--;
51316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        ALOGV("Looking for asset '%s' in '%s'\n",
51416c4d154dca43c662571129af31b27433b919a32Adam Lesinski                assetName.string(), mAssetPaths.itemAt(i).path.string());
51516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        Asset* pAsset = openNonAssetInPathLocked(assetName.string(), mode, mAssetPaths.itemAt(i));
51616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (pAsset != NULL) {
51716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            return pAsset != kExcludedAsset ? pAsset : NULL;
51816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
51916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
52016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
52116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return NULL;
52216c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
52316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
52416c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
52516c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Open a non-asset file as if it were an asset.
52616c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
52716c4d154dca43c662571129af31b27433b919a32Adam Lesinski * The "fileName" is the partial path starting from the application
52816c4d154dca43c662571129af31b27433b919a32Adam Lesinski * name.
52916c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
530de898ff42912bd7ca1bfb099cd439562496765a4Adam LesinskiAsset* AssetManager::openNonAsset(const char* fileName, AccessMode mode, int32_t* outCookie)
53116c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
53216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AutoMutex _l(mLock);
53316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
53416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
53516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
53616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
53716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (mCacheMode != CACHE_OFF && !mCacheValid)
53816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        loadFileNameCacheLocked();
53916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
54016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /*
54116c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * For each top-level asset path, search for the asset.
54216c4d154dca43c662571129af31b27433b919a32Adam Lesinski     */
54316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
54416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    size_t i = mAssetPaths.size();
54516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    while (i > 0) {
54616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        i--;
54716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        ALOGV("Looking for non-asset '%s' in '%s'\n", fileName, mAssetPaths.itemAt(i).path.string());
54816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        Asset* pAsset = openNonAssetInPathLocked(
54916c4d154dca43c662571129af31b27433b919a32Adam Lesinski            fileName, mode, mAssetPaths.itemAt(i));
55016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (pAsset != NULL) {
551de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski            if (outCookie != NULL) *outCookie = static_cast<int32_t>(i + 1);
55216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            return pAsset != kExcludedAsset ? pAsset : NULL;
55316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
55416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
55516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
55616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return NULL;
55716c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
55816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
559a0c6260705c841f501282e0e337970ca9a00e064Narayan KamathAsset* AssetManager::openNonAsset(const int32_t cookie, const char* fileName, AccessMode mode)
56016c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
561a0c6260705c841f501282e0e337970ca9a00e064Narayan Kamath    const size_t which = static_cast<size_t>(cookie) - 1;
56216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
56316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AutoMutex _l(mLock);
56416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
56516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
56616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
56716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (mCacheMode != CACHE_OFF && !mCacheValid)
56816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        loadFileNameCacheLocked();
56916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
57016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (which < mAssetPaths.size()) {
57116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        ALOGV("Looking for non-asset '%s' in '%s'\n", fileName,
57216c4d154dca43c662571129af31b27433b919a32Adam Lesinski                mAssetPaths.itemAt(which).path.string());
57316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        Asset* pAsset = openNonAssetInPathLocked(
57416c4d154dca43c662571129af31b27433b919a32Adam Lesinski            fileName, mode, mAssetPaths.itemAt(which));
57516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (pAsset != NULL) {
57616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            return pAsset != kExcludedAsset ? pAsset : NULL;
57716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
57816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
57916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
58016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return NULL;
58116c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
58216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
58316c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
58416c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Get the type of a file in the asset namespace.
58516c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
58616c4d154dca43c662571129af31b27433b919a32Adam Lesinski * This currently only works for regular files.  All others (including
58716c4d154dca43c662571129af31b27433b919a32Adam Lesinski * directories) will return kFileTypeNonexistent.
58816c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
58916c4d154dca43c662571129af31b27433b919a32Adam LesinskiFileType AssetManager::getFileType(const char* fileName)
59016c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
59116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    Asset* pAsset = NULL;
59216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
59316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /*
59416c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * Open the asset.  This is less efficient than simply finding the
59516c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * file, but it's not too bad (we don't uncompress or mmap data until
59616c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * the first read() call).
59716c4d154dca43c662571129af31b27433b919a32Adam Lesinski     */
59816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    pAsset = open(fileName, Asset::ACCESS_STREAMING);
59916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    delete pAsset;
60016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
60116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (pAsset == NULL)
60216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return kFileTypeNonexistent;
60316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    else
60416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return kFileTypeRegular;
60516c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
60616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
6077df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosibabool AssetManager::appendPathToResTable(const asset_path& ap) const {
6087df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    Asset* ass = NULL;
6097df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    ResTable* sharedRes = NULL;
6107df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    bool shared = true;
6117df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    bool onlyEmptyResources = true;
6127df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    MY_TRACE_BEGIN(ap.path.string());
6137df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    Asset* idmap = openIdmapLocked(ap);
6147df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    size_t nextEntryIdx = mResources->getTableCount();
6157df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    ALOGV("Looking for resource asset in '%s'\n", ap.path.string());
6167df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    if (ap.type != kFileTypeDirectory) {
6177df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        if (nextEntryIdx == 0) {
6187df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba            // The first item is typically the framework resources,
6197df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba            // which we want to avoid parsing every time.
6207df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba            sharedRes = const_cast<AssetManager*>(this)->
6217df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                mZipSet.getZipResourceTable(ap.path);
6227df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba            if (sharedRes != NULL) {
6237df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                // skip ahead the number of system overlay packages preloaded
6247df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                nextEntryIdx = sharedRes->getTableCount();
6257df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba            }
6267df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        }
6277df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        if (sharedRes == NULL) {
6287df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba            ass = const_cast<AssetManager*>(this)->
6297df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                mZipSet.getZipResourceTableAsset(ap.path);
6307df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba            if (ass == NULL) {
6317df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                ALOGV("loading resource table %s\n", ap.path.string());
6327df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                ass = const_cast<AssetManager*>(this)->
6337df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                    openNonAssetInPathLocked("resources.arsc",
6347df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                                             Asset::ACCESS_BUFFER,
6357df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                                             ap);
6367df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                if (ass != NULL && ass != kExcludedAsset) {
6377df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                    ass = const_cast<AssetManager*>(this)->
6387df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                        mZipSet.setZipResourceTableAsset(ap.path, ass);
6397df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                }
6407df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba            }
6417df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba
6427df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba            if (nextEntryIdx == 0 && ass != NULL) {
6437df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                // If this is the first resource table in the asset
6447df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                // manager, then we are going to cache it so that we
6457df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                // can quickly copy it out for others.
6467df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                ALOGV("Creating shared resources for %s", ap.path.string());
6477df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                sharedRes = new ResTable();
6487df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                sharedRes->add(ass, idmap, nextEntryIdx + 1, false);
6497df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba#ifdef HAVE_ANDROID_OS
6507df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                const char* data = getenv("ANDROID_DATA");
6517df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                LOG_ALWAYS_FATAL_IF(data == NULL, "ANDROID_DATA not set");
6527df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                String8 overlaysListPath(data);
6537df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                overlaysListPath.appendPath(kResourceCache);
6547df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                overlaysListPath.appendPath("overlays.list");
6557df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                addSystemOverlays(overlaysListPath.string(), ap.path, sharedRes, nextEntryIdx);
6567df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba#endif
6577df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                sharedRes = const_cast<AssetManager*>(this)->
6587df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                    mZipSet.setZipResourceTable(ap.path, sharedRes);
6597df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba            }
6607df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        }
6617df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    } else {
6627df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        ALOGV("loading resource table %s\n", ap.path.string());
6637df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        ass = const_cast<AssetManager*>(this)->
6647df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba            openNonAssetInPathLocked("resources.arsc",
6657df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                                     Asset::ACCESS_BUFFER,
6667df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba                                     ap);
6677df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        shared = false;
6687df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    }
6697df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba
6707df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    if ((ass != NULL || sharedRes != NULL) && ass != kExcludedAsset) {
6717df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        ALOGV("Installing resource asset %p in to table %p\n", ass, mResources);
6727df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        if (sharedRes != NULL) {
6737df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba            ALOGV("Copying existing resources for %s", ap.path.string());
6747df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba            mResources->add(sharedRes);
6757df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        } else {
6767df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba            ALOGV("Parsing resources for %s", ap.path.string());
6777df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba            mResources->add(ass, idmap, nextEntryIdx + 1, !shared);
6787df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        }
6797df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        onlyEmptyResources = false;
6807df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba
6817df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        if (!shared) {
6827df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba            delete ass;
6837df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        }
6847df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    } else {
6857df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        ALOGV("Installing empty resources in to table %p\n", mResources);
6867df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        mResources->addEmpty(nextEntryIdx + 1);
6877df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    }
6887df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba
6897df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    if (idmap != NULL) {
6907df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        delete idmap;
6917df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    }
6927df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    MY_TRACE_END();
6937df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba
6947df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba    return onlyEmptyResources;
6957df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba}
6967df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba
69716c4d154dca43c662571129af31b27433b919a32Adam Lesinskiconst ResTable* AssetManager::getResTable(bool required) const
69816c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
69916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    ResTable* rt = mResources;
70016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (rt) {
70116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return rt;
70216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
70316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
70416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    // Iterate through all asset packages, collecting resources from each.
70516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
70616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AutoMutex _l(mLock);
70716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
70816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (mResources != NULL) {
70916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return mResources;
71016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
71116c4d154dca43c662571129af31b27433b919a32Adam Lesinski
71216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (required) {
71316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
71416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
71516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
716de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    if (mCacheMode != CACHE_OFF && !mCacheValid) {
71716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        const_cast<AssetManager*>(this)->loadFileNameCacheLocked();
718de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    }
719de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski
720de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    mResources = new ResTable();
721de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    updateResourceParamsLocked();
72216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
723de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    bool onlyEmptyResources = true;
72416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    const size_t N = mAssetPaths.size();
72516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    for (size_t i=0; i<N; i++) {
7267df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        bool empty = appendPathToResTable(mAssetPaths.itemAt(i));
7277df3625d5bb28d11cce9ac23429f5e3c6ebac030Martin Kosiba        onlyEmptyResources = onlyEmptyResources && empty;
72816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
72916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
730de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    if (required && onlyEmptyResources) {
731de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        ALOGW("Unable to find resources file resources.arsc");
732de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        delete mResources;
733de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        mResources = NULL;
73416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
735de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski
736de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    return mResources;
73716c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
73816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
73916c4d154dca43c662571129af31b27433b919a32Adam Lesinskivoid AssetManager::updateResourceParamsLocked() const
74016c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
74116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    ResTable* res = mResources;
74216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (!res) {
74316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return;
74416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
74516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
74691447d88f2bdf9c2bf8d1a53570efef6172fba74Narayan Kamath    if (mLocale) {
74791447d88f2bdf9c2bf8d1a53570efef6172fba74Narayan Kamath        mConfig->setBcp47Locale(mLocale);
74891447d88f2bdf9c2bf8d1a53570efef6172fba74Narayan Kamath    } else {
74991447d88f2bdf9c2bf8d1a53570efef6172fba74Narayan Kamath        mConfig->clearLocale();
75016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
75116c4d154dca43c662571129af31b27433b919a32Adam Lesinski
75216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    res->setParameters(mConfig);
75316c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
75416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
75516c4d154dca43c662571129af31b27433b919a32Adam LesinskiAsset* AssetManager::openIdmapLocked(const struct asset_path& ap) const
75616c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
75716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    Asset* ass = NULL;
75816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (ap.idmap.size() != 0) {
75916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        ass = const_cast<AssetManager*>(this)->
76016c4d154dca43c662571129af31b27433b919a32Adam Lesinski            openAssetFromFileLocked(ap.idmap, Asset::ACCESS_BUFFER);
76116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (ass) {
76216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            ALOGV("loading idmap %s\n", ap.idmap.string());
76316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        } else {
76416c4d154dca43c662571129af31b27433b919a32Adam Lesinski            ALOGW("failed to load idmap %s\n", ap.idmap.string());
76516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
76616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
76716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return ass;
76816c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
76916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
77048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstadvoid AssetManager::addSystemOverlays(const char* pathOverlaysList,
77148d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        const String8& targetPackagePath, ResTable* sharedRes, size_t offset) const
77248d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad{
77348d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    FILE* fin = fopen(pathOverlaysList, "r");
77448d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    if (fin == NULL) {
77548d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        return;
77648d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    }
77748d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad
77848d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    char buf[1024];
77948d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    while (fgets(buf, sizeof(buf), fin)) {
78048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        // format of each line:
78148d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        //   <path to apk><space><path to idmap><newline>
78248d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        char* space = strchr(buf, ' ');
78348d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        char* newline = strchr(buf, '\n');
78448d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        asset_path oap;
78548d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad
78648d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        if (space == NULL || newline == NULL || newline < space) {
78748d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad            continue;
78848d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        }
78948d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad
79048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        oap.path = String8(buf, space - buf);
79148d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        oap.type = kFileTypeRegular;
79248d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        oap.idmap = String8(space + 1, newline - space - 1);
79348d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad
79448d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        Asset* oass = const_cast<AssetManager*>(this)->
79548d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad            openNonAssetInPathLocked("resources.arsc",
79648d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad                    Asset::ACCESS_BUFFER,
79748d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad                    oap);
79848d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad
79948d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        if (oass != NULL) {
80048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad            Asset* oidmap = openIdmapLocked(oap);
80148d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad            offset++;
802f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski            sharedRes->add(oass, oidmap, offset + 1, false);
80348d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad            const_cast<AssetManager*>(this)->mAssetPaths.add(oap);
80448d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad            const_cast<AssetManager*>(this)->mZipSet.addOverlay(targetPackagePath, oap);
80548d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        }
80648d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    }
80748d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    fclose(fin);
80848d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad}
80948d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad
81016c4d154dca43c662571129af31b27433b919a32Adam Lesinskiconst ResTable& AssetManager::getResources(bool required) const
81116c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
81216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    const ResTable* rt = getResTable(required);
81316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return *rt;
81416c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
81516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
81616c4d154dca43c662571129af31b27433b919a32Adam Lesinskibool AssetManager::isUpToDate()
81716c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
81816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AutoMutex _l(mLock);
81916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return mZipSet.isUpToDate();
82016c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
82116c4d154dca43c662571129af31b27433b919a32Adam Lesinski
82216c4d154dca43c662571129af31b27433b919a32Adam Lesinskivoid AssetManager::getLocales(Vector<String8>* locales) const
82316c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
82416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    ResTable* res = mResources;
82516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (res != NULL) {
82616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        res->getLocales(locales);
82716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
828e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath
829e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath    const size_t numLocales = locales->size();
830e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath    for (size_t i = 0; i < numLocales; ++i) {
831e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath        const String8& localeStr = locales->itemAt(i);
832e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath        if (localeStr.find(kTlPrefix) == 0) {
833e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath            String8 replaced("fil");
834e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath            replaced += (localeStr.string() + kTlPrefixLen);
835e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath            locales->editItemAt(i) = replaced;
836e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath        }
837e4345dbd2a892f38e62269d94e5ee7002d121bedNarayan Kamath    }
83816c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
83916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
84016c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
84116c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Open a non-asset file as if it were an asset, searching for it in the
84216c4d154dca43c662571129af31b27433b919a32Adam Lesinski * specified app.
84316c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
84416c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Pass in a NULL values for "appName" if the common app directory should
84516c4d154dca43c662571129af31b27433b919a32Adam Lesinski * be used.
84616c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
84716c4d154dca43c662571129af31b27433b919a32Adam LesinskiAsset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode mode,
84816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    const asset_path& ap)
84916c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
85016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    Asset* pAsset = NULL;
85116c4d154dca43c662571129af31b27433b919a32Adam Lesinski
85216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /* look at the filesystem on disk */
85316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (ap.type == kFileTypeDirectory) {
85416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        String8 path(ap.path);
85516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        path.appendPath(fileName);
85616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
85716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        pAsset = openAssetFromFileLocked(path, mode);
85816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
85916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (pAsset == NULL) {
86016c4d154dca43c662571129af31b27433b919a32Adam Lesinski            /* try again, this time with ".gz" */
86116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            path.append(".gz");
86216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            pAsset = openAssetFromFileLocked(path, mode);
86316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
86416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
86516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (pAsset != NULL) {
86616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            //printf("FOUND NA '%s' on disk\n", fileName);
86716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            pAsset->setAssetSource(path);
86816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
86916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
87016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /* look inside the zip file */
87116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    } else {
87216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        String8 path(fileName);
87316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
87416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        /* check the appropriate Zip file */
875560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath        ZipFileRO* pZip = getZipFileLocked(ap);
87616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (pZip != NULL) {
87716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            //printf("GOT zip, checking NA '%s'\n", (const char*) path);
878560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath            ZipEntryRO entry = pZip->findEntryByName(path.string());
87916c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (entry != NULL) {
88016c4d154dca43c662571129af31b27433b919a32Adam Lesinski                //printf("FOUND NA in Zip file for %s\n", appName ? appName : kAppCommon);
88116c4d154dca43c662571129af31b27433b919a32Adam Lesinski                pAsset = openAssetFromZipLocked(pZip, entry, mode, path);
882560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath                pZip->releaseEntry(entry);
88316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            }
88416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
88516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
88616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (pAsset != NULL) {
88716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            /* create a "source" name, for debug/display */
88816c4d154dca43c662571129af31b27433b919a32Adam Lesinski            pAsset->setAssetSource(
88916c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    createZipSourceNameLocked(ZipSet::getPathName(ap.path.string()), String8(""),
89016c4d154dca43c662571129af31b27433b919a32Adam Lesinski                                                String8(fileName)));
89116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
89216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
89316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
89416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return pAsset;
89516c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
89616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
89716c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
89816c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Open an asset, searching for it in the directory hierarchy for the
89916c4d154dca43c662571129af31b27433b919a32Adam Lesinski * specified app.
90016c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
90116c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Pass in a NULL values for "appName" if the common app directory should
90216c4d154dca43c662571129af31b27433b919a32Adam Lesinski * be used.
90316c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
90416c4d154dca43c662571129af31b27433b919a32Adam LesinskiAsset* AssetManager::openInPathLocked(const char* fileName, AccessMode mode,
90516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    const asset_path& ap)
90616c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
90716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    Asset* pAsset = NULL;
90816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
90916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /*
91016c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * Try various combinations of locale and vendor.
91116c4d154dca43c662571129af31b27433b919a32Adam Lesinski     */
91216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (mLocale != NULL && mVendor != NULL)
91316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        pAsset = openInLocaleVendorLocked(fileName, mode, ap, mLocale, mVendor);
91416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (pAsset == NULL && mVendor != NULL)
91516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        pAsset = openInLocaleVendorLocked(fileName, mode, ap, NULL, mVendor);
91616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (pAsset == NULL && mLocale != NULL)
91716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        pAsset = openInLocaleVendorLocked(fileName, mode, ap, mLocale, NULL);
91816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (pAsset == NULL)
91916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        pAsset = openInLocaleVendorLocked(fileName, mode, ap, NULL, NULL);
92016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
92116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return pAsset;
92216c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
92316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
92416c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
92516c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Open an asset, searching for it in the directory hierarchy for the
92616c4d154dca43c662571129af31b27433b919a32Adam Lesinski * specified locale and vendor.
92716c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
92816c4d154dca43c662571129af31b27433b919a32Adam Lesinski * We also search in "app.jar".
92916c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
93016c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Pass in NULL values for "appName", "locale", and "vendor" if the
93116c4d154dca43c662571129af31b27433b919a32Adam Lesinski * defaults should be used.
93216c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
93316c4d154dca43c662571129af31b27433b919a32Adam LesinskiAsset* AssetManager::openInLocaleVendorLocked(const char* fileName, AccessMode mode,
93416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    const asset_path& ap, const char* locale, const char* vendor)
93516c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
93616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    Asset* pAsset = NULL;
93716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
93816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (ap.type == kFileTypeDirectory) {
93916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (mCacheMode == CACHE_OFF) {
94016c4d154dca43c662571129af31b27433b919a32Adam Lesinski            /* look at the filesystem on disk */
94116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            String8 path(createPathNameLocked(ap, locale, vendor));
94216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            path.appendPath(fileName);
94316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
94416c4d154dca43c662571129af31b27433b919a32Adam Lesinski            String8 excludeName(path);
94516c4d154dca43c662571129af31b27433b919a32Adam Lesinski            excludeName.append(kExcludeExtension);
94616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (::getFileType(excludeName.string()) != kFileTypeNonexistent) {
94716c4d154dca43c662571129af31b27433b919a32Adam Lesinski                /* say no more */
94816c4d154dca43c662571129af31b27433b919a32Adam Lesinski                //printf("+++ excluding '%s'\n", (const char*) excludeName);
94916c4d154dca43c662571129af31b27433b919a32Adam Lesinski                return kExcludedAsset;
95016c4d154dca43c662571129af31b27433b919a32Adam Lesinski            }
95116c4d154dca43c662571129af31b27433b919a32Adam Lesinski
95216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            pAsset = openAssetFromFileLocked(path, mode);
95316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
95416c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (pAsset == NULL) {
95516c4d154dca43c662571129af31b27433b919a32Adam Lesinski                /* try again, this time with ".gz" */
95616c4d154dca43c662571129af31b27433b919a32Adam Lesinski                path.append(".gz");
95716c4d154dca43c662571129af31b27433b919a32Adam Lesinski                pAsset = openAssetFromFileLocked(path, mode);
95816c4d154dca43c662571129af31b27433b919a32Adam Lesinski            }
95916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
96016c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (pAsset != NULL)
96116c4d154dca43c662571129af31b27433b919a32Adam Lesinski                pAsset->setAssetSource(path);
96216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        } else {
96316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            /* find in cache */
96416c4d154dca43c662571129af31b27433b919a32Adam Lesinski            String8 path(createPathNameLocked(ap, locale, vendor));
96516c4d154dca43c662571129af31b27433b919a32Adam Lesinski            path.appendPath(fileName);
96616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
96716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            AssetDir::FileInfo tmpInfo;
96816c4d154dca43c662571129af31b27433b919a32Adam Lesinski            bool found = false;
96916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
97016c4d154dca43c662571129af31b27433b919a32Adam Lesinski            String8 excludeName(path);
97116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            excludeName.append(kExcludeExtension);
97216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
97316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (mCache.indexOf(excludeName) != NAME_NOT_FOUND) {
97416c4d154dca43c662571129af31b27433b919a32Adam Lesinski                /* go no farther */
97516c4d154dca43c662571129af31b27433b919a32Adam Lesinski                //printf("+++ Excluding '%s'\n", (const char*) excludeName);
97616c4d154dca43c662571129af31b27433b919a32Adam Lesinski                return kExcludedAsset;
97716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            }
97816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
97916c4d154dca43c662571129af31b27433b919a32Adam Lesinski            /*
98016c4d154dca43c662571129af31b27433b919a32Adam Lesinski             * File compression extensions (".gz") don't get stored in the
98116c4d154dca43c662571129af31b27433b919a32Adam Lesinski             * name cache, so we have to try both here.
98216c4d154dca43c662571129af31b27433b919a32Adam Lesinski             */
98316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (mCache.indexOf(path) != NAME_NOT_FOUND) {
98416c4d154dca43c662571129af31b27433b919a32Adam Lesinski                found = true;
98516c4d154dca43c662571129af31b27433b919a32Adam Lesinski                pAsset = openAssetFromFileLocked(path, mode);
98616c4d154dca43c662571129af31b27433b919a32Adam Lesinski                if (pAsset == NULL) {
98716c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    /* try again, this time with ".gz" */
98816c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    path.append(".gz");
98916c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    pAsset = openAssetFromFileLocked(path, mode);
99016c4d154dca43c662571129af31b27433b919a32Adam Lesinski                }
99116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            }
99216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
99316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (pAsset != NULL)
99416c4d154dca43c662571129af31b27433b919a32Adam Lesinski                pAsset->setAssetSource(path);
99516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
99616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            /*
99716c4d154dca43c662571129af31b27433b919a32Adam Lesinski             * Don't continue the search into the Zip files.  Our cached info
99816c4d154dca43c662571129af31b27433b919a32Adam Lesinski             * said it was a file on disk; to be consistent with openDir()
99916c4d154dca43c662571129af31b27433b919a32Adam Lesinski             * we want to return the loose asset.  If the cached file gets
100016c4d154dca43c662571129af31b27433b919a32Adam Lesinski             * removed, we fail.
100116c4d154dca43c662571129af31b27433b919a32Adam Lesinski             *
100216c4d154dca43c662571129af31b27433b919a32Adam Lesinski             * The alternative is to update our cache when files get deleted,
100316c4d154dca43c662571129af31b27433b919a32Adam Lesinski             * or make some sort of "best effort" promise, but for now I'm
100416c4d154dca43c662571129af31b27433b919a32Adam Lesinski             * taking the hard line.
100516c4d154dca43c662571129af31b27433b919a32Adam Lesinski             */
100616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (found) {
100716c4d154dca43c662571129af31b27433b919a32Adam Lesinski                if (pAsset == NULL)
100816c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    ALOGD("Expected file not found: '%s'\n", path.string());
100916c4d154dca43c662571129af31b27433b919a32Adam Lesinski                return pAsset;
101016c4d154dca43c662571129af31b27433b919a32Adam Lesinski            }
101116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
101216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
101316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
101416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /*
101516c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * Either it wasn't found on disk or on the cached view of the disk.
101616c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * Dig through the currently-opened set of Zip files.  If caching
101716c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * is disabled, the Zip file may get reopened.
101816c4d154dca43c662571129af31b27433b919a32Adam Lesinski     */
101916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (pAsset == NULL && ap.type == kFileTypeRegular) {
102016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        String8 path;
102116c4d154dca43c662571129af31b27433b919a32Adam Lesinski
102216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        path.appendPath((locale != NULL) ? locale : kDefaultLocale);
102316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        path.appendPath((vendor != NULL) ? vendor : kDefaultVendor);
102416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        path.appendPath(fileName);
102516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
102616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        /* check the appropriate Zip file */
1027560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath        ZipFileRO* pZip = getZipFileLocked(ap);
102816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (pZip != NULL) {
102916c4d154dca43c662571129af31b27433b919a32Adam Lesinski            //printf("GOT zip, checking '%s'\n", (const char*) path);
1030560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath            ZipEntryRO entry = pZip->findEntryByName(path.string());
103116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (entry != NULL) {
103216c4d154dca43c662571129af31b27433b919a32Adam Lesinski                //printf("FOUND in Zip file for %s/%s-%s\n",
103316c4d154dca43c662571129af31b27433b919a32Adam Lesinski                //    appName, locale, vendor);
103416c4d154dca43c662571129af31b27433b919a32Adam Lesinski                pAsset = openAssetFromZipLocked(pZip, entry, mode, path);
1035560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath                pZip->releaseEntry(entry);
103616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            }
103716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
103816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
103916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (pAsset != NULL) {
104016c4d154dca43c662571129af31b27433b919a32Adam Lesinski            /* create a "source" name, for debug/display */
104116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            pAsset->setAssetSource(createZipSourceNameLocked(ZipSet::getPathName(ap.path.string()),
104216c4d154dca43c662571129af31b27433b919a32Adam Lesinski                                                             String8(""), String8(fileName)));
104316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
104416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
104516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
104616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return pAsset;
104716c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
104816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
104916c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
105016c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Create a "source name" for a file from a Zip archive.
105116c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
105216c4d154dca43c662571129af31b27433b919a32Adam LesinskiString8 AssetManager::createZipSourceNameLocked(const String8& zipFileName,
105316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    const String8& dirName, const String8& fileName)
105416c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
105516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    String8 sourceName("zip:");
105616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    sourceName.append(zipFileName);
105716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    sourceName.append(":");
105816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (dirName.length() > 0) {
105916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        sourceName.appendPath(dirName);
106016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
106116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    sourceName.appendPath(fileName);
106216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return sourceName;
106316c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
106416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
106516c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
106616c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Create a path to a loose asset (asset-base/app/locale/vendor).
106716c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
106816c4d154dca43c662571129af31b27433b919a32Adam LesinskiString8 AssetManager::createPathNameLocked(const asset_path& ap, const char* locale,
106916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    const char* vendor)
107016c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
107116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    String8 path(ap.path);
107216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    path.appendPath((locale != NULL) ? locale : kDefaultLocale);
107316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    path.appendPath((vendor != NULL) ? vendor : kDefaultVendor);
107416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return path;
107516c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
107616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
107716c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
107816c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Create a path to a loose asset (asset-base/app/rootDir).
107916c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
108016c4d154dca43c662571129af31b27433b919a32Adam LesinskiString8 AssetManager::createPathNameLocked(const asset_path& ap, const char* rootDir)
108116c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
108216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    String8 path(ap.path);
108316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (rootDir != NULL) path.appendPath(rootDir);
108416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return path;
108516c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
108616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
108716c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
108816c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Return a pointer to one of our open Zip archives.  Returns NULL if no
108916c4d154dca43c662571129af31b27433b919a32Adam Lesinski * matching Zip file exists.
109016c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
109116c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Right now we have 2 possible Zip files (1 each in app/"common").
109216c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
109316c4d154dca43c662571129af31b27433b919a32Adam Lesinski * If caching is set to CACHE_OFF, to get the expected behavior we
109416c4d154dca43c662571129af31b27433b919a32Adam Lesinski * need to reopen the Zip file on every request.  That would be silly
109516c4d154dca43c662571129af31b27433b919a32Adam Lesinski * and expensive, so instead we just check the file modification date.
109616c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
109716c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Pass in NULL values for "appName", "locale", and "vendor" if the
109816c4d154dca43c662571129af31b27433b919a32Adam Lesinski * generics should be used.
109916c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
110016c4d154dca43c662571129af31b27433b919a32Adam LesinskiZipFileRO* AssetManager::getZipFileLocked(const asset_path& ap)
110116c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
110216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    ALOGV("getZipFileLocked() in %p\n", this);
110316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
110416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return mZipSet.getZip(ap.path);
110516c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
110616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
110716c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
110816c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Try to open an asset from a file on disk.
110916c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
111016c4d154dca43c662571129af31b27433b919a32Adam Lesinski * If the file is compressed with gzip, we seek to the start of the
111116c4d154dca43c662571129af31b27433b919a32Adam Lesinski * deflated data and pass that in (just like we would for a Zip archive).
111216c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
111316c4d154dca43c662571129af31b27433b919a32Adam Lesinski * For uncompressed data, we may already have an mmap()ed version sitting
111416c4d154dca43c662571129af31b27433b919a32Adam Lesinski * around.  If so, we want to hand that to the Asset instead.
111516c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
111616c4d154dca43c662571129af31b27433b919a32Adam Lesinski * This returns NULL if the file doesn't exist, couldn't be opened, or
111716c4d154dca43c662571129af31b27433b919a32Adam Lesinski * claims to be a ".gz" but isn't.
111816c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
111916c4d154dca43c662571129af31b27433b919a32Adam LesinskiAsset* AssetManager::openAssetFromFileLocked(const String8& pathName,
112016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AccessMode mode)
112116c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
112216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    Asset* pAsset = NULL;
112316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
112416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (strcasecmp(pathName.getPathExtension().string(), ".gz") == 0) {
112516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        //printf("TRYING '%s'\n", (const char*) pathName);
112616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        pAsset = Asset::createFromCompressedFile(pathName.string(), mode);
112716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    } else {
112816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        //printf("TRYING '%s'\n", (const char*) pathName);
112916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        pAsset = Asset::createFromFile(pathName.string(), mode);
113016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
113116c4d154dca43c662571129af31b27433b919a32Adam Lesinski
113216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return pAsset;
113316c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
113416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
113516c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
113616c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Given an entry in a Zip archive, create a new Asset object.
113716c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
113816c4d154dca43c662571129af31b27433b919a32Adam Lesinski * If the entry is uncompressed, we may want to create or share a
113916c4d154dca43c662571129af31b27433b919a32Adam Lesinski * slice of shared memory.
114016c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
114116c4d154dca43c662571129af31b27433b919a32Adam LesinskiAsset* AssetManager::openAssetFromZipLocked(const ZipFileRO* pZipFile,
114216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    const ZipEntryRO entry, AccessMode mode, const String8& entryName)
114316c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
114416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    Asset* pAsset = NULL;
114516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
114616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    // TODO: look for previously-created shared memory slice?
114716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    int method;
114816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    size_t uncompressedLen;
114916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
115016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    //printf("USING Zip '%s'\n", pEntry->getFileName());
115116c4d154dca43c662571129af31b27433b919a32Adam Lesinski
115216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    //pZipFile->getEntryInfo(entry, &method, &uncompressedLen, &compressedLen,
115316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    //    &offset);
115416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (!pZipFile->getEntryInfo(entry, &method, &uncompressedLen, NULL, NULL,
115516c4d154dca43c662571129af31b27433b919a32Adam Lesinski            NULL, NULL))
115616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    {
115716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        ALOGW("getEntryInfo failed\n");
115816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return NULL;
115916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
116016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
116116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    FileMap* dataMap = pZipFile->createEntryFileMap(entry);
116216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (dataMap == NULL) {
116316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        ALOGW("create map from entry failed\n");
116416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return NULL;
116516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
116616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
116716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (method == ZipFileRO::kCompressStored) {
116816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        pAsset = Asset::createFromUncompressedMap(dataMap, mode);
116916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        ALOGV("Opened uncompressed entry %s in zip %s mode %d: %p", entryName.string(),
117016c4d154dca43c662571129af31b27433b919a32Adam Lesinski                dataMap->getFileName(), mode, pAsset);
117116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    } else {
117216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        pAsset = Asset::createFromCompressedMap(dataMap, method,
117316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            uncompressedLen, mode);
117416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        ALOGV("Opened compressed entry %s in zip %s mode %d: %p", entryName.string(),
117516c4d154dca43c662571129af31b27433b919a32Adam Lesinski                dataMap->getFileName(), mode, pAsset);
117616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
117716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (pAsset == NULL) {
117816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        /* unexpected */
117916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        ALOGW("create from segment failed\n");
118016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
118116c4d154dca43c662571129af31b27433b919a32Adam Lesinski
118216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return pAsset;
118316c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
118416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
118516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
118616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
118716c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
118816c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Open a directory in the asset namespace.
118916c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
119016c4d154dca43c662571129af31b27433b919a32Adam Lesinski * An "asset directory" is simply the combination of all files in all
119116c4d154dca43c662571129af31b27433b919a32Adam Lesinski * locations, with ".gz" stripped for loose files.  With app, locale, and
119216c4d154dca43c662571129af31b27433b919a32Adam Lesinski * vendor defined, we have 8 directories and 2 Zip archives to scan.
119316c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
119416c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Pass in "" for the root dir.
119516c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
119616c4d154dca43c662571129af31b27433b919a32Adam LesinskiAssetDir* AssetManager::openDir(const char* dirName)
119716c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
119816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AutoMutex _l(mLock);
119916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
120016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AssetDir* pDir = NULL;
120116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    SortedVector<AssetDir::FileInfo>* pMergedInfo = NULL;
120216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
120316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
120416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    assert(dirName != NULL);
120516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
120616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    //printf("+++ openDir(%s) in '%s'\n", dirName, (const char*) mAssetBase);
120716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
120816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (mCacheMode != CACHE_OFF && !mCacheValid)
120916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        loadFileNameCacheLocked();
121016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
121116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    pDir = new AssetDir;
121216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
121316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /*
121416c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * Scan the various directories, merging what we find into a single
121516c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * vector.  We want to scan them in reverse priority order so that
121616c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * the ".EXCLUDE" processing works correctly.  Also, if we decide we
121716c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * want to remember where the file is coming from, we'll get the right
121816c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * version.
121916c4d154dca43c662571129af31b27433b919a32Adam Lesinski     *
122016c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * We start with Zip archives, then do loose files.
122116c4d154dca43c662571129af31b27433b919a32Adam Lesinski     */
122216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    pMergedInfo = new SortedVector<AssetDir::FileInfo>;
122316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
122416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    size_t i = mAssetPaths.size();
122516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    while (i > 0) {
122616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        i--;
122716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        const asset_path& ap = mAssetPaths.itemAt(i);
122816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (ap.type == kFileTypeRegular) {
122916c4d154dca43c662571129af31b27433b919a32Adam Lesinski            ALOGV("Adding directory %s from zip %s", dirName, ap.path.string());
123016c4d154dca43c662571129af31b27433b919a32Adam Lesinski            scanAndMergeZipLocked(pMergedInfo, ap, kAssetsRoot, dirName);
123116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        } else {
123216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            ALOGV("Adding directory %s from dir %s", dirName, ap.path.string());
123316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            scanAndMergeDirLocked(pMergedInfo, ap, kAssetsRoot, dirName);
123416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
123516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
123616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
123716c4d154dca43c662571129af31b27433b919a32Adam Lesinski#if 0
123816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    printf("FILE LIST:\n");
123916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    for (i = 0; i < (size_t) pMergedInfo->size(); i++) {
124016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        printf(" %d: (%d) '%s'\n", i,
124116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            pMergedInfo->itemAt(i).getFileType(),
124216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            (const char*) pMergedInfo->itemAt(i).getFileName());
124316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
124416c4d154dca43c662571129af31b27433b919a32Adam Lesinski#endif
124516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
124616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    pDir->setFileList(pMergedInfo);
124716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return pDir;
124816c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
124916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
125016c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
125116c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Open a directory in the non-asset namespace.
125216c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
125316c4d154dca43c662571129af31b27433b919a32Adam Lesinski * An "asset directory" is simply the combination of all files in all
125416c4d154dca43c662571129af31b27433b919a32Adam Lesinski * locations, with ".gz" stripped for loose files.  With app, locale, and
125516c4d154dca43c662571129af31b27433b919a32Adam Lesinski * vendor defined, we have 8 directories and 2 Zip archives to scan.
125616c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
125716c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Pass in "" for the root dir.
125816c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
1259a0c6260705c841f501282e0e337970ca9a00e064Narayan KamathAssetDir* AssetManager::openNonAssetDir(const int32_t cookie, const char* dirName)
126016c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
126116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AutoMutex _l(mLock);
126216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
126316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AssetDir* pDir = NULL;
126416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    SortedVector<AssetDir::FileInfo>* pMergedInfo = NULL;
126516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
126616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
126716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    assert(dirName != NULL);
126816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
126916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    //printf("+++ openDir(%s) in '%s'\n", dirName, (const char*) mAssetBase);
127016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
127116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (mCacheMode != CACHE_OFF && !mCacheValid)
127216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        loadFileNameCacheLocked();
127316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
127416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    pDir = new AssetDir;
127516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
127616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    pMergedInfo = new SortedVector<AssetDir::FileInfo>;
127716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
1278a0c6260705c841f501282e0e337970ca9a00e064Narayan Kamath    const size_t which = static_cast<size_t>(cookie) - 1;
127916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
128016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (which < mAssetPaths.size()) {
128116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        const asset_path& ap = mAssetPaths.itemAt(which);
128216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (ap.type == kFileTypeRegular) {
128316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            ALOGV("Adding directory %s from zip %s", dirName, ap.path.string());
128416c4d154dca43c662571129af31b27433b919a32Adam Lesinski            scanAndMergeZipLocked(pMergedInfo, ap, NULL, dirName);
128516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        } else {
128616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            ALOGV("Adding directory %s from dir %s", dirName, ap.path.string());
128716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            scanAndMergeDirLocked(pMergedInfo, ap, NULL, dirName);
128816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
128916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
129016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
129116c4d154dca43c662571129af31b27433b919a32Adam Lesinski#if 0
129216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    printf("FILE LIST:\n");
129316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    for (i = 0; i < (size_t) pMergedInfo->size(); i++) {
129416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        printf(" %d: (%d) '%s'\n", i,
129516c4d154dca43c662571129af31b27433b919a32Adam Lesinski            pMergedInfo->itemAt(i).getFileType(),
129616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            (const char*) pMergedInfo->itemAt(i).getFileName());
129716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
129816c4d154dca43c662571129af31b27433b919a32Adam Lesinski#endif
129916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
130016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    pDir->setFileList(pMergedInfo);
130116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return pDir;
130216c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
130316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
130416c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
130516c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Scan the contents of the specified directory and merge them into the
130616c4d154dca43c662571129af31b27433b919a32Adam Lesinski * "pMergedInfo" vector, removing previous entries if we find "exclude"
130716c4d154dca43c662571129af31b27433b919a32Adam Lesinski * directives.
130816c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
130916c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Returns "false" if we found nothing to contribute.
131016c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
131116c4d154dca43c662571129af31b27433b919a32Adam Lesinskibool AssetManager::scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
131216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    const asset_path& ap, const char* rootDir, const char* dirName)
131316c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
131416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    SortedVector<AssetDir::FileInfo>* pContents;
131516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    String8 path;
131616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
131716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    assert(pMergedInfo != NULL);
131816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
131916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    //printf("scanAndMergeDir: %s %s %s %s\n", appName, locale, vendor,dirName);
132016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
132116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (mCacheValid) {
132216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        int i, start, count;
132316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
132416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        pContents = new SortedVector<AssetDir::FileInfo>;
132516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
132616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        /*
132716c4d154dca43c662571129af31b27433b919a32Adam Lesinski         * Get the basic partial path and find it in the cache.  That's
132816c4d154dca43c662571129af31b27433b919a32Adam Lesinski         * the start point for the search.
132916c4d154dca43c662571129af31b27433b919a32Adam Lesinski         */
133016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        path = createPathNameLocked(ap, rootDir);
133116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (dirName[0] != '\0')
133216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            path.appendPath(dirName);
133316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
133416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        start = mCache.indexOf(path);
133516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (start == NAME_NOT_FOUND) {
133616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            //printf("+++ not found in cache: dir '%s'\n", (const char*) path);
133716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            delete pContents;
133816c4d154dca43c662571129af31b27433b919a32Adam Lesinski            return false;
133916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
134016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
134116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        /*
134216c4d154dca43c662571129af31b27433b919a32Adam Lesinski         * The match string looks like "common/default/default/foo/bar/".
134316c4d154dca43c662571129af31b27433b919a32Adam Lesinski         * The '/' on the end ensures that we don't match on the directory
134416c4d154dca43c662571129af31b27433b919a32Adam Lesinski         * itself or on ".../foo/barfy/".
134516c4d154dca43c662571129af31b27433b919a32Adam Lesinski         */
134616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        path.append("/");
134716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
134816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        count = mCache.size();
134916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
135016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        /*
135116c4d154dca43c662571129af31b27433b919a32Adam Lesinski         * Pick out the stuff in the current dir by examining the pathname.
135216c4d154dca43c662571129af31b27433b919a32Adam Lesinski         * It needs to match the partial pathname prefix, and not have a '/'
135316c4d154dca43c662571129af31b27433b919a32Adam Lesinski         * (fssep) anywhere after the prefix.
135416c4d154dca43c662571129af31b27433b919a32Adam Lesinski         */
135516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        for (i = start+1; i < count; i++) {
135616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (mCache[i].getFileName().length() > path.length() &&
135716c4d154dca43c662571129af31b27433b919a32Adam Lesinski                strncmp(mCache[i].getFileName().string(), path.string(), path.length()) == 0)
135816c4d154dca43c662571129af31b27433b919a32Adam Lesinski            {
135916c4d154dca43c662571129af31b27433b919a32Adam Lesinski                const char* name = mCache[i].getFileName().string();
136016c4d154dca43c662571129af31b27433b919a32Adam Lesinski                // XXX THIS IS BROKEN!  Looks like we need to store the full
136116c4d154dca43c662571129af31b27433b919a32Adam Lesinski                // path prefix separately from the file path.
136216c4d154dca43c662571129af31b27433b919a32Adam Lesinski                if (strchr(name + path.length(), '/') == NULL) {
136316c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    /* grab it, reducing path to just the filename component */
136416c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    AssetDir::FileInfo tmp = mCache[i];
136516c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    tmp.setFileName(tmp.getFileName().getPathLeaf());
136616c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    pContents->add(tmp);
136716c4d154dca43c662571129af31b27433b919a32Adam Lesinski                }
136816c4d154dca43c662571129af31b27433b919a32Adam Lesinski            } else {
136916c4d154dca43c662571129af31b27433b919a32Adam Lesinski                /* no longer in the dir or its subdirs */
137016c4d154dca43c662571129af31b27433b919a32Adam Lesinski                break;
137116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            }
137216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
137316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
137416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    } else {
137516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        path = createPathNameLocked(ap, rootDir);
137616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (dirName[0] != '\0')
137716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            path.appendPath(dirName);
137816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        pContents = scanDirLocked(path);
137916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (pContents == NULL)
138016c4d154dca43c662571129af31b27433b919a32Adam Lesinski            return false;
138116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
138216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
138316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    // if we wanted to do an incremental cache fill, we would do it here
138416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
138516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /*
138616c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * Process "exclude" directives.  If we find a filename that ends with
138716c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * ".EXCLUDE", we look for a matching entry in the "merged" set, and
138816c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * remove it if we find it.  We also delete the "exclude" entry.
138916c4d154dca43c662571129af31b27433b919a32Adam Lesinski     */
139016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    int i, count, exclExtLen;
139116c4d154dca43c662571129af31b27433b919a32Adam Lesinski
139216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    count = pContents->size();
139316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    exclExtLen = strlen(kExcludeExtension);
139416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    for (i = 0; i < count; i++) {
139516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        const char* name;
139616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        int nameLen;
139716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
139816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        name = pContents->itemAt(i).getFileName().string();
139916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        nameLen = strlen(name);
140016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (nameLen > exclExtLen &&
140116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            strcmp(name + (nameLen - exclExtLen), kExcludeExtension) == 0)
140216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        {
140316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            String8 match(name, nameLen - exclExtLen);
140416c4d154dca43c662571129af31b27433b919a32Adam Lesinski            int matchIdx;
140516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
140616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            matchIdx = AssetDir::FileInfo::findEntry(pMergedInfo, match);
140716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (matchIdx > 0) {
140816c4d154dca43c662571129af31b27433b919a32Adam Lesinski                ALOGV("Excluding '%s' [%s]\n",
140916c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    pMergedInfo->itemAt(matchIdx).getFileName().string(),
141016c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    pMergedInfo->itemAt(matchIdx).getSourceName().string());
141116c4d154dca43c662571129af31b27433b919a32Adam Lesinski                pMergedInfo->removeAt(matchIdx);
141216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            } else {
141316c4d154dca43c662571129af31b27433b919a32Adam Lesinski                //printf("+++ no match on '%s'\n", (const char*) match);
141416c4d154dca43c662571129af31b27433b919a32Adam Lesinski            }
141516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
141616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            ALOGD("HEY: size=%d removing %d\n", (int)pContents->size(), i);
141716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            pContents->removeAt(i);
141816c4d154dca43c662571129af31b27433b919a32Adam Lesinski            i--;        // adjust "for" loop
141916c4d154dca43c662571129af31b27433b919a32Adam Lesinski            count--;    //  and loop limit
142016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
142116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
142216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
142316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mergeInfoLocked(pMergedInfo, pContents);
142416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
142516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    delete pContents;
142616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
142716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return true;
142816c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
142916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
143016c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
143116c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Scan the contents of the specified directory, and stuff what we find
143216c4d154dca43c662571129af31b27433b919a32Adam Lesinski * into a newly-allocated vector.
143316c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
143416c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Files ending in ".gz" will have their extensions removed.
143516c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
143616c4d154dca43c662571129af31b27433b919a32Adam Lesinski * We should probably think about skipping files with "illegal" names,
143716c4d154dca43c662571129af31b27433b919a32Adam Lesinski * e.g. illegal characters (/\:) or excessive length.
143816c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
143916c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Returns NULL if the specified directory doesn't exist.
144016c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
144116c4d154dca43c662571129af31b27433b919a32Adam LesinskiSortedVector<AssetDir::FileInfo>* AssetManager::scanDirLocked(const String8& path)
144216c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
144316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    SortedVector<AssetDir::FileInfo>* pContents = NULL;
144416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    DIR* dir;
144516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    struct dirent* entry;
144616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    FileType fileType;
144716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
144816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    ALOGV("Scanning dir '%s'\n", path.string());
144916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
145016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    dir = opendir(path.string());
145116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (dir == NULL)
145216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return NULL;
145316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
145416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    pContents = new SortedVector<AssetDir::FileInfo>;
145516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
145616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    while (1) {
145716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        entry = readdir(dir);
145816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (entry == NULL)
145916c4d154dca43c662571129af31b27433b919a32Adam Lesinski            break;
146016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
146116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (strcmp(entry->d_name, ".") == 0 ||
146216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            strcmp(entry->d_name, "..") == 0)
146316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            continue;
146416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
146516c4d154dca43c662571129af31b27433b919a32Adam Lesinski#ifdef _DIRENT_HAVE_D_TYPE
146616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (entry->d_type == DT_REG)
146716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            fileType = kFileTypeRegular;
146816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        else if (entry->d_type == DT_DIR)
146916c4d154dca43c662571129af31b27433b919a32Adam Lesinski            fileType = kFileTypeDirectory;
147016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        else
147116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            fileType = kFileTypeUnknown;
147216c4d154dca43c662571129af31b27433b919a32Adam Lesinski#else
147316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        // stat the file
147416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        fileType = ::getFileType(path.appendPathCopy(entry->d_name).string());
147516c4d154dca43c662571129af31b27433b919a32Adam Lesinski#endif
147616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
147716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (fileType != kFileTypeRegular && fileType != kFileTypeDirectory)
147816c4d154dca43c662571129af31b27433b919a32Adam Lesinski            continue;
147916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
148016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        AssetDir::FileInfo info;
148116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        info.set(String8(entry->d_name), fileType);
148216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (strcasecmp(info.getFileName().getPathExtension().string(), ".gz") == 0)
148316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            info.setFileName(info.getFileName().getBasePath());
148416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        info.setSourceName(path.appendPathCopy(info.getFileName()));
148516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        pContents->add(info);
148616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
148716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
148816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    closedir(dir);
148916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return pContents;
149016c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
149116c4d154dca43c662571129af31b27433b919a32Adam Lesinski
149216c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
149316c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Scan the contents out of the specified Zip archive, and merge what we
149416c4d154dca43c662571129af31b27433b919a32Adam Lesinski * find into "pMergedInfo".  If the Zip archive in question doesn't exist,
149516c4d154dca43c662571129af31b27433b919a32Adam Lesinski * we return immediately.
149616c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
149716c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Returns "false" if we found nothing to contribute.
149816c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
149916c4d154dca43c662571129af31b27433b919a32Adam Lesinskibool AssetManager::scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
150016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    const asset_path& ap, const char* rootDir, const char* baseDirName)
150116c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
150216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    ZipFileRO* pZip;
150316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    Vector<String8> dirs;
150416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AssetDir::FileInfo info;
150516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    SortedVector<AssetDir::FileInfo> contents;
150616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    String8 sourceName, zipName, dirName;
150716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
150816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    pZip = mZipSet.getZip(ap.path);
150916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (pZip == NULL) {
151016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        ALOGW("Failure opening zip %s\n", ap.path.string());
151116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return false;
151216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
151316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
151416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    zipName = ZipSet::getPathName(ap.path.string());
151516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
151616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /* convert "sounds" to "rootDir/sounds" */
151716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (rootDir != NULL) dirName = rootDir;
151816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    dirName.appendPath(baseDirName);
151916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
152016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /*
152116c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * Scan through the list of files, looking for a match.  The files in
152216c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * the Zip table of contents are not in sorted order, so we have to
152316c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * process the entire list.  We're looking for a string that begins
152416c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * with the characters in "dirName", is followed by a '/', and has no
152516c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * subsequent '/' in the stuff that follows.
152616c4d154dca43c662571129af31b27433b919a32Adam Lesinski     *
152716c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * What makes this especially fun is that directories are not stored
152816c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * explicitly in Zip archives, so we have to infer them from context.
152916c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * When we see "sounds/foo.wav" we have to leave a note to ourselves
153016c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * to insert a directory called "sounds" into the list.  We store
153116c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * these in temporary vector so that we only return each one once.
153216c4d154dca43c662571129af31b27433b919a32Adam Lesinski     *
153316c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * Name comparisons are case-sensitive to match UNIX filesystem
153416c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * semantics.
153516c4d154dca43c662571129af31b27433b919a32Adam Lesinski     */
153616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    int dirNameLen = dirName.length();
1537560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath    void *iterationCookie;
1538560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath    if (!pZip->startIteration(&iterationCookie)) {
1539560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath        ALOGW("ZipFileRO::startIteration returned false");
1540560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath        return false;
1541560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath    }
1542560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath
1543560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath    ZipEntryRO entry;
1544560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath    while ((entry = pZip->nextEntry(iterationCookie)) != NULL) {
154516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        char nameBuf[256];
154616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
154716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (pZip->getEntryFileName(entry, nameBuf, sizeof(nameBuf)) != 0) {
154816c4d154dca43c662571129af31b27433b919a32Adam Lesinski            // TODO: fix this if we expect to have long names
154916c4d154dca43c662571129af31b27433b919a32Adam Lesinski            ALOGE("ARGH: name too long?\n");
155016c4d154dca43c662571129af31b27433b919a32Adam Lesinski            continue;
155116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
155216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        //printf("Comparing %s in %s?\n", nameBuf, dirName.string());
155316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (dirNameLen == 0 ||
155416c4d154dca43c662571129af31b27433b919a32Adam Lesinski            (strncmp(nameBuf, dirName.string(), dirNameLen) == 0 &&
155516c4d154dca43c662571129af31b27433b919a32Adam Lesinski             nameBuf[dirNameLen] == '/'))
155616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        {
155716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            const char* cp;
155816c4d154dca43c662571129af31b27433b919a32Adam Lesinski            const char* nextSlash;
155916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
156016c4d154dca43c662571129af31b27433b919a32Adam Lesinski            cp = nameBuf + dirNameLen;
156116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (dirNameLen != 0)
156216c4d154dca43c662571129af31b27433b919a32Adam Lesinski                cp++;       // advance past the '/'
156316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
156416c4d154dca43c662571129af31b27433b919a32Adam Lesinski            nextSlash = strchr(cp, '/');
156516c4d154dca43c662571129af31b27433b919a32Adam Lesinski//xxx this may break if there are bare directory entries
156616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (nextSlash == NULL) {
156716c4d154dca43c662571129af31b27433b919a32Adam Lesinski                /* this is a file in the requested directory */
156816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
156916c4d154dca43c662571129af31b27433b919a32Adam Lesinski                info.set(String8(nameBuf).getPathLeaf(), kFileTypeRegular);
157016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
157116c4d154dca43c662571129af31b27433b919a32Adam Lesinski                info.setSourceName(
157216c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    createZipSourceNameLocked(zipName, dirName, info.getFileName()));
157316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
157416c4d154dca43c662571129af31b27433b919a32Adam Lesinski                contents.add(info);
157516c4d154dca43c662571129af31b27433b919a32Adam Lesinski                //printf("FOUND: file '%s'\n", info.getFileName().string());
157616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            } else {
157716c4d154dca43c662571129af31b27433b919a32Adam Lesinski                /* this is a subdir; add it if we don't already have it*/
157816c4d154dca43c662571129af31b27433b919a32Adam Lesinski                String8 subdirName(cp, nextSlash - cp);
157916c4d154dca43c662571129af31b27433b919a32Adam Lesinski                size_t j;
158016c4d154dca43c662571129af31b27433b919a32Adam Lesinski                size_t N = dirs.size();
158116c4d154dca43c662571129af31b27433b919a32Adam Lesinski
158216c4d154dca43c662571129af31b27433b919a32Adam Lesinski                for (j = 0; j < N; j++) {
158316c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    if (subdirName == dirs[j]) {
158416c4d154dca43c662571129af31b27433b919a32Adam Lesinski                        break;
158516c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    }
158616c4d154dca43c662571129af31b27433b919a32Adam Lesinski                }
158716c4d154dca43c662571129af31b27433b919a32Adam Lesinski                if (j == N) {
158816c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    dirs.add(subdirName);
158916c4d154dca43c662571129af31b27433b919a32Adam Lesinski                }
159016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
159116c4d154dca43c662571129af31b27433b919a32Adam Lesinski                //printf("FOUND: dir '%s'\n", subdirName.string());
159216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            }
159316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
159416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
159516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
1596560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath    pZip->endIteration(iterationCookie);
1597560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath
159816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /*
159916c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * Add the set of unique directories.
160016c4d154dca43c662571129af31b27433b919a32Adam Lesinski     */
160116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    for (int i = 0; i < (int) dirs.size(); i++) {
160216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        info.set(dirs[i], kFileTypeDirectory);
160316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        info.setSourceName(
160416c4d154dca43c662571129af31b27433b919a32Adam Lesinski            createZipSourceNameLocked(zipName, dirName, info.getFileName()));
160516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        contents.add(info);
160616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
160716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
160816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mergeInfoLocked(pMergedInfo, &contents);
160916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
161016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return true;
161116c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
161216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
161316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
161416c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
161516c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Merge two vectors of FileInfo.
161616c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
161716c4d154dca43c662571129af31b27433b919a32Adam Lesinski * The merged contents will be stuffed into *pMergedInfo.
161816c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
161916c4d154dca43c662571129af31b27433b919a32Adam Lesinski * If an entry for a file exists in both "pMergedInfo" and "pContents",
162016c4d154dca43c662571129af31b27433b919a32Adam Lesinski * we use the newer "pContents" entry.
162116c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
162216c4d154dca43c662571129af31b27433b919a32Adam Lesinskivoid AssetManager::mergeInfoLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
162316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    const SortedVector<AssetDir::FileInfo>* pContents)
162416c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
162516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /*
162616c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * Merge what we found in this directory with what we found in
162716c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * other places.
162816c4d154dca43c662571129af31b27433b919a32Adam Lesinski     *
162916c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * Two basic approaches:
163016c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * (1) Create a new array that holds the unique values of the two
163116c4d154dca43c662571129af31b27433b919a32Adam Lesinski     *     arrays.
163216c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * (2) Take the elements from pContents and shove them into pMergedInfo.
163316c4d154dca43c662571129af31b27433b919a32Adam Lesinski     *
163416c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * Because these are vectors of complex objects, moving elements around
163516c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * inside the vector requires constructing new objects and allocating
163616c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * storage for members.  With approach #1, we're always adding to the
163716c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * end, whereas with #2 we could be inserting multiple elements at the
163816c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * front of the vector.  Approach #1 requires a full copy of the
163916c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * contents of pMergedInfo, but approach #2 requires the same copy for
164016c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * every insertion at the front of pMergedInfo.
164116c4d154dca43c662571129af31b27433b919a32Adam Lesinski     *
164216c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * (We should probably use a SortedVector interface that allows us to
164316c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * just stuff items in, trusting us to maintain the sort order.)
164416c4d154dca43c662571129af31b27433b919a32Adam Lesinski     */
164516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    SortedVector<AssetDir::FileInfo>* pNewSorted;
164616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    int mergeMax, contMax;
164716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    int mergeIdx, contIdx;
164816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
164916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    pNewSorted = new SortedVector<AssetDir::FileInfo>;
165016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mergeMax = pMergedInfo->size();
165116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    contMax = pContents->size();
165216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mergeIdx = contIdx = 0;
165316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
165416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    while (mergeIdx < mergeMax || contIdx < contMax) {
165516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (mergeIdx == mergeMax) {
165616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            /* hit end of "merge" list, copy rest of "contents" */
165716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            pNewSorted->add(pContents->itemAt(contIdx));
165816c4d154dca43c662571129af31b27433b919a32Adam Lesinski            contIdx++;
165916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        } else if (contIdx == contMax) {
166016c4d154dca43c662571129af31b27433b919a32Adam Lesinski            /* hit end of "cont" list, copy rest of "merge" */
166116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            pNewSorted->add(pMergedInfo->itemAt(mergeIdx));
166216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            mergeIdx++;
166316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        } else if (pMergedInfo->itemAt(mergeIdx) == pContents->itemAt(contIdx))
166416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        {
166516c4d154dca43c662571129af31b27433b919a32Adam Lesinski            /* items are identical, add newer and advance both indices */
166616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            pNewSorted->add(pContents->itemAt(contIdx));
166716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            mergeIdx++;
166816c4d154dca43c662571129af31b27433b919a32Adam Lesinski            contIdx++;
166916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        } else if (pMergedInfo->itemAt(mergeIdx) < pContents->itemAt(contIdx))
167016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        {
167116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            /* "merge" is lower, add that one */
167216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            pNewSorted->add(pMergedInfo->itemAt(mergeIdx));
167316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            mergeIdx++;
167416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        } else {
167516c4d154dca43c662571129af31b27433b919a32Adam Lesinski            /* "cont" is lower, add that one */
167616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            assert(pContents->itemAt(contIdx) < pMergedInfo->itemAt(mergeIdx));
167716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            pNewSorted->add(pContents->itemAt(contIdx));
167816c4d154dca43c662571129af31b27433b919a32Adam Lesinski            contIdx++;
167916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
168016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
168116c4d154dca43c662571129af31b27433b919a32Adam Lesinski
168216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /*
168316c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * Overwrite the "merged" list with the new stuff.
168416c4d154dca43c662571129af31b27433b919a32Adam Lesinski     */
168516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    *pMergedInfo = *pNewSorted;
168616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    delete pNewSorted;
168716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
168816c4d154dca43c662571129af31b27433b919a32Adam Lesinski#if 0       // for Vector, rather than SortedVector
168916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    int i, j;
169016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    for (i = pContents->size() -1; i >= 0; i--) {
169116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        bool add = true;
169216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
169316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        for (j = pMergedInfo->size() -1; j >= 0; j--) {
169416c4d154dca43c662571129af31b27433b919a32Adam Lesinski            /* case-sensitive comparisons, to behave like UNIX fs */
169516c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (strcmp(pContents->itemAt(i).mFileName,
169616c4d154dca43c662571129af31b27433b919a32Adam Lesinski                       pMergedInfo->itemAt(j).mFileName) == 0)
169716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            {
169816c4d154dca43c662571129af31b27433b919a32Adam Lesinski                /* match, don't add this entry */
169916c4d154dca43c662571129af31b27433b919a32Adam Lesinski                add = false;
170016c4d154dca43c662571129af31b27433b919a32Adam Lesinski                break;
170116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            }
170216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
170316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
170416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (add)
170516c4d154dca43c662571129af31b27433b919a32Adam Lesinski            pMergedInfo->add(pContents->itemAt(i));
170616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
170716c4d154dca43c662571129af31b27433b919a32Adam Lesinski#endif
170816c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
170916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
171016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
171116c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
171216c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Load all files into the file name cache.  We want to do this across
171316c4d154dca43c662571129af31b27433b919a32Adam Lesinski * all combinations of { appname, locale, vendor }, performing a recursive
171416c4d154dca43c662571129af31b27433b919a32Adam Lesinski * directory traversal.
171516c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
171616c4d154dca43c662571129af31b27433b919a32Adam Lesinski * This is not the most efficient data structure.  Also, gathering the
171716c4d154dca43c662571129af31b27433b919a32Adam Lesinski * information as we needed it (file-by-file or directory-by-directory)
171816c4d154dca43c662571129af31b27433b919a32Adam Lesinski * would be faster.  However, on the actual device, 99% of the files will
171916c4d154dca43c662571129af31b27433b919a32Adam Lesinski * live in Zip archives, so this list will be very small.  The trouble
172016c4d154dca43c662571129af31b27433b919a32Adam Lesinski * is that we have to check the "loose" files first, so it's important
172116c4d154dca43c662571129af31b27433b919a32Adam Lesinski * that we don't beat the filesystem silly looking for files that aren't
172216c4d154dca43c662571129af31b27433b919a32Adam Lesinski * there.
172316c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
172416c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Note on thread safety: this is the only function that causes updates
172516c4d154dca43c662571129af31b27433b919a32Adam Lesinski * to mCache, and anybody who tries to use it will call here if !mCacheValid,
172616c4d154dca43c662571129af31b27433b919a32Adam Lesinski * so we need to employ a mutex here.
172716c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
172816c4d154dca43c662571129af31b27433b919a32Adam Lesinskivoid AssetManager::loadFileNameCacheLocked(void)
172916c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
173016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    assert(!mCacheValid);
173116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    assert(mCache.size() == 0);
173216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
173316c4d154dca43c662571129af31b27433b919a32Adam Lesinski#ifdef DO_TIMINGS   // need to link against -lrt for this now
173416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    DurationTimer timer;
173516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    timer.start();
173616c4d154dca43c662571129af31b27433b919a32Adam Lesinski#endif
173716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
173816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    fncScanLocked(&mCache, "");
173916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
174016c4d154dca43c662571129af31b27433b919a32Adam Lesinski#ifdef DO_TIMINGS
174116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    timer.stop();
174216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    ALOGD("Cache scan took %.3fms\n",
174316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        timer.durationUsecs() / 1000.0);
174416c4d154dca43c662571129af31b27433b919a32Adam Lesinski#endif
174516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
174616c4d154dca43c662571129af31b27433b919a32Adam Lesinski#if 0
174716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    int i;
174816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    printf("CACHED FILE LIST (%d entries):\n", mCache.size());
174916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    for (i = 0; i < (int) mCache.size(); i++) {
175016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        printf(" %d: (%d) '%s'\n", i,
175116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            mCache.itemAt(i).getFileType(),
175216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            (const char*) mCache.itemAt(i).getFileName());
175316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
175416c4d154dca43c662571129af31b27433b919a32Adam Lesinski#endif
175516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
175616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mCacheValid = true;
175716c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
175816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
175916c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
176016c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Scan up to 8 versions of the specified directory.
176116c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
176216c4d154dca43c662571129af31b27433b919a32Adam Lesinskivoid AssetManager::fncScanLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
176316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    const char* dirName)
176416c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
176516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    size_t i = mAssetPaths.size();
176616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    while (i > 0) {
176716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        i--;
176816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        const asset_path& ap = mAssetPaths.itemAt(i);
176916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        fncScanAndMergeDirLocked(pMergedInfo, ap, NULL, NULL, dirName);
177016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (mLocale != NULL)
177116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            fncScanAndMergeDirLocked(pMergedInfo, ap, mLocale, NULL, dirName);
177216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (mVendor != NULL)
177316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            fncScanAndMergeDirLocked(pMergedInfo, ap, NULL, mVendor, dirName);
177416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (mLocale != NULL && mVendor != NULL)
177516c4d154dca43c662571129af31b27433b919a32Adam Lesinski            fncScanAndMergeDirLocked(pMergedInfo, ap, mLocale, mVendor, dirName);
177616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
177716c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
177816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
177916c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
178016c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Recursively scan this directory and all subdirs.
178116c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
178216c4d154dca43c662571129af31b27433b919a32Adam Lesinski * This is similar to scanAndMergeDir, but we don't remove the .EXCLUDE
178316c4d154dca43c662571129af31b27433b919a32Adam Lesinski * files, and we prepend the extended partial path to the filenames.
178416c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
178516c4d154dca43c662571129af31b27433b919a32Adam Lesinskibool AssetManager::fncScanAndMergeDirLocked(
178616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    SortedVector<AssetDir::FileInfo>* pMergedInfo,
178716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    const asset_path& ap, const char* locale, const char* vendor,
178816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    const char* dirName)
178916c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
179016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    SortedVector<AssetDir::FileInfo>* pContents;
179116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    String8 partialPath;
179216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    String8 fullPath;
179316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
179416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    // XXX This is broken -- the filename cache needs to hold the base
179516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    // asset path separately from its filename.
179616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
179716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    partialPath = createPathNameLocked(ap, locale, vendor);
179816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (dirName[0] != '\0') {
179916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        partialPath.appendPath(dirName);
180016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
180116c4d154dca43c662571129af31b27433b919a32Adam Lesinski
180216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    fullPath = partialPath;
180316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    pContents = scanDirLocked(fullPath);
180416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (pContents == NULL) {
180516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return false;       // directory did not exist
180616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
180716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
180816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /*
180916c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * Scan all subdirectories of the current dir, merging what we find
181016c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * into "pMergedInfo".
181116c4d154dca43c662571129af31b27433b919a32Adam Lesinski     */
181216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    for (int i = 0; i < (int) pContents->size(); i++) {
181316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (pContents->itemAt(i).getFileType() == kFileTypeDirectory) {
181416c4d154dca43c662571129af31b27433b919a32Adam Lesinski            String8 subdir(dirName);
181516c4d154dca43c662571129af31b27433b919a32Adam Lesinski            subdir.appendPath(pContents->itemAt(i).getFileName());
181616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
181716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            fncScanAndMergeDirLocked(pMergedInfo, ap, locale, vendor, subdir.string());
181816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
181916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
182016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
182116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /*
182216c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * To be consistent, we want entries for the root directory.  If
182316c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * we're the root, add one now.
182416c4d154dca43c662571129af31b27433b919a32Adam Lesinski     */
182516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (dirName[0] == '\0') {
182616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        AssetDir::FileInfo tmpInfo;
182716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
182816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        tmpInfo.set(String8(""), kFileTypeDirectory);
182916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        tmpInfo.setSourceName(createPathNameLocked(ap, locale, vendor));
183016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        pContents->add(tmpInfo);
183116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
183216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
183316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    /*
183416c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * We want to prepend the extended partial path to every entry in
183516c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * "pContents".  It's the same value for each entry, so this will
183616c4d154dca43c662571129af31b27433b919a32Adam Lesinski     * not change the sorting order of the vector contents.
183716c4d154dca43c662571129af31b27433b919a32Adam Lesinski     */
183816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    for (int i = 0; i < (int) pContents->size(); i++) {
183916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        const AssetDir::FileInfo& info = pContents->itemAt(i);
184016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        pContents->editItemAt(i).setFileName(partialPath.appendPathCopy(info.getFileName()));
184116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
184216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
184316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mergeInfoLocked(pMergedInfo, pContents);
18447c57d2337150ab52c148d30d9126f3b99ca951b4sean_lu    delete pContents;
184516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return true;
184616c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
184716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
184816c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
184916c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Trash the cache.
185016c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
185116c4d154dca43c662571129af31b27433b919a32Adam Lesinskivoid AssetManager::purgeFileNameCacheLocked(void)
185216c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
185316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mCacheValid = false;
185416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mCache.clear();
185516c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
185616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
185716c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
185816c4d154dca43c662571129af31b27433b919a32Adam Lesinski * ===========================================================================
185916c4d154dca43c662571129af31b27433b919a32Adam Lesinski *      AssetManager::SharedZip
186016c4d154dca43c662571129af31b27433b919a32Adam Lesinski * ===========================================================================
186116c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
186216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
186316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
186416c4d154dca43c662571129af31b27433b919a32Adam LesinskiMutex AssetManager::SharedZip::gLock;
186516c4d154dca43c662571129af31b27433b919a32Adam LesinskiDefaultKeyedVector<String8, wp<AssetManager::SharedZip> > AssetManager::SharedZip::gOpen;
186616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
186716c4d154dca43c662571129af31b27433b919a32Adam LesinskiAssetManager::SharedZip::SharedZip(const String8& path, time_t modWhen)
186816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    : mPath(path), mZipFile(NULL), mModWhen(modWhen),
186916c4d154dca43c662571129af31b27433b919a32Adam Lesinski      mResourceTableAsset(NULL), mResourceTable(NULL)
187016c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
187116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    //ALOGI("Creating SharedZip %p %s\n", this, (const char*)mPath);
187216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    ALOGV("+++ opening zip '%s'\n", mPath.string());
1873560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath    mZipFile = ZipFileRO::open(mPath.string());
1874560566d2915c03bed338fc532ac7f7aa3620cfdfNarayan Kamath    if (mZipFile == NULL) {
187516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        ALOGD("failed to open Zip archive '%s'\n", mPath.string());
187616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
187716c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
187816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
187948d22323ce39f9aab003dce74456889b6414af55Mårten Kongstadsp<AssetManager::SharedZip> AssetManager::SharedZip::get(const String8& path,
188048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        bool createIfNotPresent)
188116c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
188216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    AutoMutex _l(gLock);
188316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    time_t modWhen = getFileModDate(path);
188416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    sp<SharedZip> zip = gOpen.valueFor(path).promote();
188516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (zip != NULL && zip->mModWhen == modWhen) {
188616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        return zip;
188716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
188848d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    if (zip == NULL && !createIfNotPresent) {
188948d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        return NULL;
189048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    }
189116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    zip = new SharedZip(path, modWhen);
189216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    gOpen.add(path, zip);
189316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return zip;
189416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
189516c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
189616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
189716c4d154dca43c662571129af31b27433b919a32Adam LesinskiZipFileRO* AssetManager::SharedZip::getZip()
189816c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
189916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return mZipFile;
190016c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
190116c4d154dca43c662571129af31b27433b919a32Adam Lesinski
190216c4d154dca43c662571129af31b27433b919a32Adam LesinskiAsset* AssetManager::SharedZip::getResourceTableAsset()
190316c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
190416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    ALOGV("Getting from SharedZip %p resource asset %p\n", this, mResourceTableAsset);
190516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return mResourceTableAsset;
190616c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
190716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
190816c4d154dca43c662571129af31b27433b919a32Adam LesinskiAsset* AssetManager::SharedZip::setResourceTableAsset(Asset* asset)
190916c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
191016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    {
191116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        AutoMutex _l(gLock);
191216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (mResourceTableAsset == NULL) {
191316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            mResourceTableAsset = asset;
191416c4d154dca43c662571129af31b27433b919a32Adam Lesinski            // This is not thread safe the first time it is called, so
191516c4d154dca43c662571129af31b27433b919a32Adam Lesinski            // do it here with the global lock held.
191616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            asset->getBuffer(true);
191716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            return asset;
191816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
191916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
192016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    delete asset;
192116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return mResourceTableAsset;
192216c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
192316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
192416c4d154dca43c662571129af31b27433b919a32Adam LesinskiResTable* AssetManager::SharedZip::getResourceTable()
192516c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
192616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    ALOGV("Getting from SharedZip %p resource table %p\n", this, mResourceTable);
192716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return mResourceTable;
192816c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
192916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
193016c4d154dca43c662571129af31b27433b919a32Adam LesinskiResTable* AssetManager::SharedZip::setResourceTable(ResTable* res)
193116c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
193216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    {
193316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        AutoMutex _l(gLock);
193416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (mResourceTable == NULL) {
193516c4d154dca43c662571129af31b27433b919a32Adam Lesinski            mResourceTable = res;
193616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            return res;
193716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
193816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
193916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    delete res;
194016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return mResourceTable;
194116c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
194216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
194316c4d154dca43c662571129af31b27433b919a32Adam Lesinskibool AssetManager::SharedZip::isUpToDate()
194416c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
194516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    time_t modWhen = getFileModDate(mPath.string());
194616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return mModWhen == modWhen;
194716c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
194816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
194948d22323ce39f9aab003dce74456889b6414af55Mårten Kongstadvoid AssetManager::SharedZip::addOverlay(const asset_path& ap)
195048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad{
195148d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    mOverlays.add(ap);
195248d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad}
195348d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad
195448d22323ce39f9aab003dce74456889b6414af55Mårten Kongstadbool AssetManager::SharedZip::getOverlay(size_t idx, asset_path* out) const
195548d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad{
195648d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    if (idx >= mOverlays.size()) {
195748d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        return false;
195848d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    }
195948d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    *out = mOverlays[idx];
196048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    return true;
196148d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad}
196248d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad
196316c4d154dca43c662571129af31b27433b919a32Adam LesinskiAssetManager::SharedZip::~SharedZip()
196416c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
196516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    //ALOGI("Destroying SharedZip %p %s\n", this, (const char*)mPath);
196616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (mResourceTable != NULL) {
196716c4d154dca43c662571129af31b27433b919a32Adam Lesinski        delete mResourceTable;
196816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
196916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (mResourceTableAsset != NULL) {
197016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        delete mResourceTableAsset;
197116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
197216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (mZipFile != NULL) {
197316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        delete mZipFile;
197416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        ALOGV("Closed '%s'\n", mPath.string());
197516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
197616c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
197716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
197816c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
197916c4d154dca43c662571129af31b27433b919a32Adam Lesinski * ===========================================================================
198016c4d154dca43c662571129af31b27433b919a32Adam Lesinski *      AssetManager::ZipSet
198116c4d154dca43c662571129af31b27433b919a32Adam Lesinski * ===========================================================================
198216c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
198316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
198416c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
198516c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Constructor.
198616c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
198716c4d154dca43c662571129af31b27433b919a32Adam LesinskiAssetManager::ZipSet::ZipSet(void)
198816c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
198916c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
199016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
199116c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
199216c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Destructor.  Close any open archives.
199316c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
199416c4d154dca43c662571129af31b27433b919a32Adam LesinskiAssetManager::ZipSet::~ZipSet(void)
199516c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
199616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    size_t N = mZipFile.size();
199716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    for (size_t i = 0; i < N; i++)
199816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        closeZip(i);
199916c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
200016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
200116c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
200216c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Close a Zip file and reset the entry.
200316c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
200416c4d154dca43c662571129af31b27433b919a32Adam Lesinskivoid AssetManager::ZipSet::closeZip(int idx)
200516c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
200616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mZipFile.editItemAt(idx) = NULL;
200716c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
200816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
200916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
201016c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
201116c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Retrieve the appropriate Zip file from the set.
201216c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
201316c4d154dca43c662571129af31b27433b919a32Adam LesinskiZipFileRO* AssetManager::ZipSet::getZip(const String8& path)
201416c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
201516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    int idx = getIndex(path);
201616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    sp<SharedZip> zip = mZipFile[idx];
201716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (zip == NULL) {
201816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        zip = SharedZip::get(path);
201916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        mZipFile.editItemAt(idx) = zip;
202016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
202116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return zip->getZip();
202216c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
202316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
202416c4d154dca43c662571129af31b27433b919a32Adam LesinskiAsset* AssetManager::ZipSet::getZipResourceTableAsset(const String8& path)
202516c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
202616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    int idx = getIndex(path);
202716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    sp<SharedZip> zip = mZipFile[idx];
202816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (zip == NULL) {
202916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        zip = SharedZip::get(path);
203016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        mZipFile.editItemAt(idx) = zip;
203116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
203216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return zip->getResourceTableAsset();
203316c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
203416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
203516c4d154dca43c662571129af31b27433b919a32Adam LesinskiAsset* AssetManager::ZipSet::setZipResourceTableAsset(const String8& path,
203616c4d154dca43c662571129af31b27433b919a32Adam Lesinski                                                 Asset* asset)
203716c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
203816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    int idx = getIndex(path);
203916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    sp<SharedZip> zip = mZipFile[idx];
204016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    // doesn't make sense to call before previously accessing.
204116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return zip->setResourceTableAsset(asset);
204216c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
204316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
204416c4d154dca43c662571129af31b27433b919a32Adam LesinskiResTable* AssetManager::ZipSet::getZipResourceTable(const String8& path)
204516c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
204616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    int idx = getIndex(path);
204716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    sp<SharedZip> zip = mZipFile[idx];
204816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (zip == NULL) {
204916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        zip = SharedZip::get(path);
205016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        mZipFile.editItemAt(idx) = zip;
205116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
205216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return zip->getResourceTable();
205316c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
205416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
205516c4d154dca43c662571129af31b27433b919a32Adam LesinskiResTable* AssetManager::ZipSet::setZipResourceTable(const String8& path,
205616c4d154dca43c662571129af31b27433b919a32Adam Lesinski                                                    ResTable* res)
205716c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
205816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    int idx = getIndex(path);
205916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    sp<SharedZip> zip = mZipFile[idx];
206016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    // doesn't make sense to call before previously accessing.
206116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return zip->setResourceTable(res);
206216c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
206316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
206416c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
206516c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Generate the partial pathname for the specified archive.  The caller
206616c4d154dca43c662571129af31b27433b919a32Adam Lesinski * gets to prepend the asset root directory.
206716c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
206816c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Returns something like "common/en-US-noogle.jar".
206916c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
207016c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*static*/ String8 AssetManager::ZipSet::getPathName(const char* zipPath)
207116c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
207216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return String8(zipPath);
207316c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
207416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
207516c4d154dca43c662571129af31b27433b919a32Adam Lesinskibool AssetManager::ZipSet::isUpToDate()
207616c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
207716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    const size_t N = mZipFile.size();
207816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    for (size_t i=0; i<N; i++) {
207916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (mZipFile[i] != NULL && !mZipFile[i]->isUpToDate()) {
208016c4d154dca43c662571129af31b27433b919a32Adam Lesinski            return false;
208116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
208216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
208316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return true;
208416c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
208516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
208648d22323ce39f9aab003dce74456889b6414af55Mårten Kongstadvoid AssetManager::ZipSet::addOverlay(const String8& path, const asset_path& overlay)
208748d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad{
208848d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    int idx = getIndex(path);
208948d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    sp<SharedZip> zip = mZipFile[idx];
209048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    zip->addOverlay(overlay);
209148d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad}
209248d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad
209348d22323ce39f9aab003dce74456889b6414af55Mårten Kongstadbool AssetManager::ZipSet::getOverlay(const String8& path, size_t idx, asset_path* out) const
209448d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad{
209548d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    sp<SharedZip> zip = SharedZip::get(path, false);
209648d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    if (zip == NULL) {
209748d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad        return false;
209848d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    }
209948d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad    return zip->getOverlay(idx, out);
210048d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad}
210148d22323ce39f9aab003dce74456889b6414af55Mårten Kongstad
210216c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
210316c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Compute the zip file's index.
210416c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
210516c4d154dca43c662571129af31b27433b919a32Adam Lesinski * "appName", "locale", and "vendor" should be set to NULL to indicate the
210616c4d154dca43c662571129af31b27433b919a32Adam Lesinski * default directory.
210716c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
210816c4d154dca43c662571129af31b27433b919a32Adam Lesinskiint AssetManager::ZipSet::getIndex(const String8& zip) const
210916c4d154dca43c662571129af31b27433b919a32Adam Lesinski{
211016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    const size_t N = mZipPath.size();
211116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    for (size_t i=0; i<N; i++) {
211216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (mZipPath[i] == zip) {
211316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            return i;
211416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
211516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
211616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
211716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mZipPath.add(zip);
211816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mZipFile.add(NULL);
211916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
212016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return mZipPath.size()-1;
212116c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
2122