diff options
author | Mike Lockwood <lockwood@google.com> | 2013-08-28 09:44:17 -0700 |
---|---|---|
committer | Mike Lockwood <lockwood@google.com> | 2013-08-28 09:44:17 -0700 |
commit | 9f6a119c8aa276432ece4fe2118bd8a3c9b1067e (patch) | |
tree | 1391656f9ad624aa99d4c7d2880d38121801a424 /tools/aapt | |
parent | 647b6f5ed276bf93d95e5801e5e8af2802ef5fbb (diff) | |
download | frameworks_base-9f6a119c8aa276432ece4fe2118bd8a3c9b1067e.zip frameworks_base-9f6a119c8aa276432ece4fe2118bd8a3c9b1067e.tar.gz frameworks_base-9f6a119c8aa276432ece4fe2118bd8a3c9b1067e.tar.bz2 |
Move frameworks/base/tools/ to frameworks/tools/
Change-Id: I3ffafdab27cc4aca256c3a5806b630795b75d5c8
Diffstat (limited to 'tools/aapt')
49 files changed, 0 insertions, 23046 deletions
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp deleted file mode 100644 index 3797b49..0000000 --- a/tools/aapt/AaptAssets.cpp +++ /dev/null @@ -1,2689 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// - -#include "AaptAssets.h" -#include "ResourceFilter.h" -#include "Main.h" - -#include <utils/misc.h> -#include <utils/SortedVector.h> - -#include <ctype.h> -#include <dirent.h> -#include <errno.h> - -static const char* kDefaultLocale = "default"; -static const char* kWildcardName = "any"; -static const char* kAssetDir = "assets"; -static const char* kResourceDir = "res"; -static const char* kValuesDir = "values"; -static const char* kMipmapDir = "mipmap"; -static const char* kInvalidChars = "/\\:"; -static const size_t kMaxAssetFileName = 100; - -static const String8 kResString(kResourceDir); - -/* - * Names of asset files must meet the following criteria: - * - * - the filename length must be less than kMaxAssetFileName bytes long - * (and can't be empty) - * - all characters must be 7-bit printable ASCII - * - none of { '/' '\\' ':' } - * - * Pass in just the filename, not the full path. - */ -static bool validateFileName(const char* fileName) -{ - const char* cp = fileName; - size_t len = 0; - - while (*cp != '\0') { - if ((*cp & 0x80) != 0) - return false; // reject high ASCII - if (*cp < 0x20 || *cp >= 0x7f) - return false; // reject control chars and 0x7f - if (strchr(kInvalidChars, *cp) != NULL) - return false; // reject path sep chars - cp++; - len++; - } - - if (len < 1 || len > kMaxAssetFileName) - return false; // reject empty or too long - - return true; -} - -// The default to use if no other ignore pattern is defined. -const char * const gDefaultIgnoreAssets = - "!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"; -// The ignore pattern that can be passed via --ignore-assets in Main.cpp -const char * gUserIgnoreAssets = NULL; - -static bool isHidden(const char *root, const char *path) -{ - // Patterns syntax: - // - Delimiter is : - // - Entry can start with the flag ! to avoid printing a warning - // about the file being ignored. - // - Entry can have the flag "<dir>" to match only directories - // or <file> to match only files. Default is to match both. - // - Entry can be a simplified glob "<prefix>*" or "*<suffix>" - // where prefix/suffix must have at least 1 character (so that - // we don't match a '*' catch-all pattern.) - // - The special filenames "." and ".." are always ignored. - // - Otherwise the full string is matched. - // - match is not case-sensitive. - - if (strcmp(path, ".") == 0 || strcmp(path, "..") == 0) { - return true; - } - - const char *delim = ":"; - const char *p = gUserIgnoreAssets; - if (!p || !p[0]) { - p = getenv("ANDROID_AAPT_IGNORE"); - } - if (!p || !p[0]) { - p = gDefaultIgnoreAssets; - } - char *patterns = strdup(p); - - bool ignore = false; - bool chatty = true; - char *matchedPattern = NULL; - - String8 fullPath(root); - fullPath.appendPath(path); - FileType type = getFileType(fullPath); - - int plen = strlen(path); - - // Note: we don't have strtok_r under mingw. - for(char *token = strtok(patterns, delim); - !ignore && token != NULL; - token = strtok(NULL, delim)) { - chatty = token[0] != '!'; - if (!chatty) token++; // skip ! - if (strncasecmp(token, "<dir>" , 5) == 0) { - if (type != kFileTypeDirectory) continue; - token += 5; - } - if (strncasecmp(token, "<file>", 6) == 0) { - if (type != kFileTypeRegular) continue; - token += 6; - } - - matchedPattern = token; - int n = strlen(token); - - if (token[0] == '*') { - // Match *suffix - token++; - n--; - if (n <= plen) { - ignore = strncasecmp(token, path + plen - n, n) == 0; - } - } else if (n > 1 && token[n - 1] == '*') { - // Match prefix* - ignore = strncasecmp(token, path, n - 1) == 0; - } else { - ignore = strcasecmp(token, path) == 0; - } - } - - if (ignore && chatty) { - fprintf(stderr, " (skipping %s '%s' due to ANDROID_AAPT_IGNORE pattern '%s')\n", - type == kFileTypeDirectory ? "dir" : "file", - path, - matchedPattern ? matchedPattern : ""); - } - - free(patterns); - return ignore; -} - -// ========================================================================= -// ========================================================================= -// ========================================================================= - -status_t -AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value) -{ - ResTable_config config; - - // IMSI - MCC - if (getMccName(part.string(), &config)) { - *axis = AXIS_MCC; - *value = config.mcc; - return 0; - } - - // IMSI - MNC - if (getMncName(part.string(), &config)) { - *axis = AXIS_MNC; - *value = config.mnc; - return 0; - } - - // locale - language - if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) { - *axis = AXIS_LANGUAGE; - *value = part[1] << 8 | part[0]; - return 0; - } - - // locale - language_REGION - if (part.length() == 5 && isalpha(part[0]) && isalpha(part[1]) - && part[2] == '_' && isalpha(part[3]) && isalpha(part[4])) { - *axis = AXIS_LANGUAGE; - *value = (part[4] << 24) | (part[3] << 16) | (part[1] << 8) | (part[0]); - return 0; - } - - // layout direction - if (getLayoutDirectionName(part.string(), &config)) { - *axis = AXIS_LAYOUTDIR; - *value = (config.screenLayout&ResTable_config::MASK_LAYOUTDIR); - return 0; - } - - // smallest screen dp width - if (getSmallestScreenWidthDpName(part.string(), &config)) { - *axis = AXIS_SMALLESTSCREENWIDTHDP; - *value = config.smallestScreenWidthDp; - return 0; - } - - // screen dp width - if (getScreenWidthDpName(part.string(), &config)) { - *axis = AXIS_SCREENWIDTHDP; - *value = config.screenWidthDp; - return 0; - } - - // screen dp height - if (getScreenHeightDpName(part.string(), &config)) { - *axis = AXIS_SCREENHEIGHTDP; - *value = config.screenHeightDp; - return 0; - } - - // screen layout size - if (getScreenLayoutSizeName(part.string(), &config)) { - *axis = AXIS_SCREENLAYOUTSIZE; - *value = (config.screenLayout&ResTable_config::MASK_SCREENSIZE); - return 0; - } - - // screen layout long - if (getScreenLayoutLongName(part.string(), &config)) { - *axis = AXIS_SCREENLAYOUTLONG; - *value = (config.screenLayout&ResTable_config::MASK_SCREENLONG); - return 0; - } - - // orientation - if (getOrientationName(part.string(), &config)) { - *axis = AXIS_ORIENTATION; - *value = config.orientation; - return 0; - } - - // ui mode type - if (getUiModeTypeName(part.string(), &config)) { - *axis = AXIS_UIMODETYPE; - *value = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE); - return 0; - } - - // ui mode night - if (getUiModeNightName(part.string(), &config)) { - *axis = AXIS_UIMODENIGHT; - *value = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT); - return 0; - } - - // density - if (getDensityName(part.string(), &config)) { - *axis = AXIS_DENSITY; - *value = config.density; - return 0; - } - - // touchscreen - if (getTouchscreenName(part.string(), &config)) { - *axis = AXIS_TOUCHSCREEN; - *value = config.touchscreen; - return 0; - } - - // keyboard hidden - if (getKeysHiddenName(part.string(), &config)) { - *axis = AXIS_KEYSHIDDEN; - *value = config.inputFlags; - return 0; - } - - // keyboard - if (getKeyboardName(part.string(), &config)) { - *axis = AXIS_KEYBOARD; - *value = config.keyboard; - return 0; - } - - // navigation hidden - if (getNavHiddenName(part.string(), &config)) { - *axis = AXIS_NAVHIDDEN; - *value = config.inputFlags; - return 0; - } - - // navigation - if (getNavigationName(part.string(), &config)) { - *axis = AXIS_NAVIGATION; - *value = config.navigation; - return 0; - } - - // screen size - if (getScreenSizeName(part.string(), &config)) { - *axis = AXIS_SCREENSIZE; - *value = config.screenSize; - return 0; - } - - // version - if (getVersionName(part.string(), &config)) { - *axis = AXIS_VERSION; - *value = config.version; - return 0; - } - - return 1; -} - -uint32_t -AaptGroupEntry::getConfigValueForAxis(const ResTable_config& config, int axis) -{ - switch (axis) { - case AXIS_MCC: - return config.mcc; - case AXIS_MNC: - return config.mnc; - case AXIS_LANGUAGE: - return (((uint32_t)config.country[1]) << 24) | (((uint32_t)config.country[0]) << 16) - | (((uint32_t)config.language[1]) << 8) | (config.language[0]); - case AXIS_LAYOUTDIR: - return config.screenLayout&ResTable_config::MASK_LAYOUTDIR; - case AXIS_SCREENLAYOUTSIZE: - return config.screenLayout&ResTable_config::MASK_SCREENSIZE; - case AXIS_ORIENTATION: - return config.orientation; - case AXIS_UIMODETYPE: - return (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE); - case AXIS_UIMODENIGHT: - return (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT); - case AXIS_DENSITY: - return config.density; - case AXIS_TOUCHSCREEN: - return config.touchscreen; - case AXIS_KEYSHIDDEN: - return config.inputFlags; - case AXIS_KEYBOARD: - return config.keyboard; - case AXIS_NAVIGATION: - return config.navigation; - case AXIS_SCREENSIZE: - return config.screenSize; - case AXIS_SMALLESTSCREENWIDTHDP: - return config.smallestScreenWidthDp; - case AXIS_SCREENWIDTHDP: - return config.screenWidthDp; - case AXIS_SCREENHEIGHTDP: - return config.screenHeightDp; - case AXIS_VERSION: - return config.version; - } - return 0; -} - -bool -AaptGroupEntry::configSameExcept(const ResTable_config& config, - const ResTable_config& otherConfig, int axis) -{ - for (int i=AXIS_START; i<=AXIS_END; i++) { - if (i == axis) { - continue; - } - if (getConfigValueForAxis(config, i) != getConfigValueForAxis(otherConfig, i)) { - return false; - } - } - return true; -} - -bool -AaptGroupEntry::initFromDirName(const char* dir, String8* resType) -{ - mParamsChanged = true; - - Vector<String8> parts; - - String8 mcc, mnc, loc, layoutsize, layoutlong, orient, den; - String8 touch, key, keysHidden, nav, navHidden, size, layoutDir, vers; - String8 uiModeType, uiModeNight, smallestwidthdp, widthdp, heightdp; - - const char *p = dir; - const char *q; - while (NULL != (q = strchr(p, '-'))) { - String8 val(p, q-p); - val.toLower(); - parts.add(val); - //printf("part: %s\n", parts[parts.size()-1].string()); - p = q+1; - } - String8 val(p); - val.toLower(); - parts.add(val); - //printf("part: %s\n", parts[parts.size()-1].string()); - - const int N = parts.size(); - int index = 0; - String8 part = parts[index]; - - // resource type - if (!isValidResourceType(part)) { - return false; - } - *resType = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - - // imsi - mcc - if (getMccName(part.string())) { - mcc = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not mcc: %s\n", part.string()); - } - - // imsi - mnc - if (getMncName(part.string())) { - mnc = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not mcc: %s\n", part.string()); - } - - // locale - language - if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) { - loc = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not language: %s\n", part.string()); - } - - // locale - region - if (loc.length() > 0 - && part.length() == 3 && part[0] == 'r' && part[0] && part[1]) { - loc += "-"; - part.toUpper(); - loc += part.string() + 1; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not region: %s\n", part.string()); - } - - if (getLayoutDirectionName(part.string())) { - layoutDir = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not layout direction: %s\n", part.string()); - } - - if (getSmallestScreenWidthDpName(part.string())) { - smallestwidthdp = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not smallest screen width dp: %s\n", part.string()); - } - - if (getScreenWidthDpName(part.string())) { - widthdp = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not screen width dp: %s\n", part.string()); - } - - if (getScreenHeightDpName(part.string())) { - heightdp = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not screen height dp: %s\n", part.string()); - } - - if (getScreenLayoutSizeName(part.string())) { - layoutsize = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not screen layout size: %s\n", part.string()); - } - - if (getScreenLayoutLongName(part.string())) { - layoutlong = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not screen layout long: %s\n", part.string()); - } - - // orientation - if (getOrientationName(part.string())) { - orient = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not orientation: %s\n", part.string()); - } - - // ui mode type - if (getUiModeTypeName(part.string())) { - uiModeType = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not ui mode type: %s\n", part.string()); - } - - // ui mode night - if (getUiModeNightName(part.string())) { - uiModeNight = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not ui mode night: %s\n", part.string()); - } - - // density - if (getDensityName(part.string())) { - den = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not density: %s\n", part.string()); - } - - // touchscreen - if (getTouchscreenName(part.string())) { - touch = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not touchscreen: %s\n", part.string()); - } - - // keyboard hidden - if (getKeysHiddenName(part.string())) { - keysHidden = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not keysHidden: %s\n", part.string()); - } - - // keyboard - if (getKeyboardName(part.string())) { - key = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not keyboard: %s\n", part.string()); - } - - // navigation hidden - if (getNavHiddenName(part.string())) { - navHidden = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not navHidden: %s\n", part.string()); - } - - if (getNavigationName(part.string())) { - nav = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not navigation: %s\n", part.string()); - } - - if (getScreenSizeName(part.string())) { - size = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not screen size: %s\n", part.string()); - } - - if (getVersionName(part.string())) { - vers = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not version: %s\n", part.string()); - } - - // if there are extra parts, it doesn't match - return false; - -success: - this->mcc = mcc; - this->mnc = mnc; - this->locale = loc; - this->screenLayoutSize = layoutsize; - this->screenLayoutLong = layoutlong; - this->smallestScreenWidthDp = smallestwidthdp; - this->screenWidthDp = widthdp; - this->screenHeightDp = heightdp; - this->orientation = orient; - this->uiModeType = uiModeType; - this->uiModeNight = uiModeNight; - this->density = den; - this->touchscreen = touch; - this->keysHidden = keysHidden; - this->keyboard = key; - this->navHidden = navHidden; - this->navigation = nav; - this->screenSize = size; - this->layoutDirection = layoutDir; - this->version = vers; - - // what is this anyway? - this->vendor = ""; - - return true; -} - -String8 -AaptGroupEntry::toString() const -{ - String8 s = this->mcc; - s += ","; - s += this->mnc; - s += ","; - s += this->locale; - s += ","; - s += layoutDirection; - s += ","; - s += smallestScreenWidthDp; - s += ","; - s += screenWidthDp; - s += ","; - s += screenHeightDp; - s += ","; - s += screenLayoutSize; - s += ","; - s += screenLayoutLong; - s += ","; - s += this->orientation; - s += ","; - s += uiModeType; - s += ","; - s += uiModeNight; - s += ","; - s += density; - s += ","; - s += touchscreen; - s += ","; - s += keysHidden; - s += ","; - s += keyboard; - s += ","; - s += navHidden; - s += ","; - s += navigation; - s += ","; - s += screenSize; - s += ","; - s += version; - return s; -} - -String8 -AaptGroupEntry::toDirName(const String8& resType) const -{ - String8 s = resType; - if (this->mcc != "") { - if (s.length() > 0) { - s += "-"; - } - s += mcc; - } - if (this->mnc != "") { - if (s.length() > 0) { - s += "-"; - } - s += mnc; - } - if (this->locale != "") { - if (s.length() > 0) { - s += "-"; - } - s += locale; - } - if (this->layoutDirection != "") { - if (s.length() > 0) { - s += "-"; - } - s += layoutDirection; - } - if (this->smallestScreenWidthDp != "") { - if (s.length() > 0) { - s += "-"; - } - s += smallestScreenWidthDp; - } - if (this->screenWidthDp != "") { - if (s.length() > 0) { - s += "-"; - } - s += screenWidthDp; - } - if (this->screenHeightDp != "") { - if (s.length() > 0) { - s += "-"; - } - s += screenHeightDp; - } - if (this->screenLayoutSize != "") { - if (s.length() > 0) { - s += "-"; - } - s += screenLayoutSize; - } - if (this->screenLayoutLong != "") { - if (s.length() > 0) { - s += "-"; - } - s += screenLayoutLong; - } - if (this->orientation != "") { - if (s.length() > 0) { - s += "-"; - } - s += orientation; - } - if (this->uiModeType != "") { - if (s.length() > 0) { - s += "-"; - } - s += uiModeType; - } - if (this->uiModeNight != "") { - if (s.length() > 0) { - s += "-"; - } - s += uiModeNight; - } - if (this->density != "") { - if (s.length() > 0) { - s += "-"; - } - s += density; - } - if (this->touchscreen != "") { - if (s.length() > 0) { - s += "-"; - } - s += touchscreen; - } - if (this->keysHidden != "") { - if (s.length() > 0) { - s += "-"; - } - s += keysHidden; - } - if (this->keyboard != "") { - if (s.length() > 0) { - s += "-"; - } - s += keyboard; - } - if (this->navHidden != "") { - if (s.length() > 0) { - s += "-"; - } - s += navHidden; - } - if (this->navigation != "") { - if (s.length() > 0) { - s += "-"; - } - s += navigation; - } - if (this->screenSize != "") { - if (s.length() > 0) { - s += "-"; - } - s += screenSize; - } - if (this->version != "") { - if (s.length() > 0) { - s += "-"; - } - s += version; - } - - return s; -} - -bool AaptGroupEntry::getMccName(const char* name, - ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) out->mcc = 0; - return true; - } - const char* c = name; - if (tolower(*c) != 'm') return false; - c++; - if (tolower(*c) != 'c') return false; - c++; - if (tolower(*c) != 'c') return false; - c++; - - const char* val = c; - - while (*c >= '0' && *c <= '9') { - c++; - } - if (*c != 0) return false; - if (c-val != 3) return false; - - int d = atoi(val); - if (d != 0) { - if (out) out->mcc = d; - return true; - } - - return false; -} - -bool AaptGroupEntry::getMncName(const char* name, - ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) out->mcc = 0; - return true; - } - const char* c = name; - if (tolower(*c) != 'm') return false; - c++; - if (tolower(*c) != 'n') return false; - c++; - if (tolower(*c) != 'c') return false; - c++; - - const char* val = c; - - while (*c >= '0' && *c <= '9') { - c++; - } - if (*c != 0) return false; - if (c-val == 0 || c-val > 3) return false; - - if (out) { - out->mnc = atoi(val); - if (out->mnc == 0) { - out->mnc = ACONFIGURATION_MNC_ZERO; - } - } - - return true; -} - -/* - * Does this directory name fit the pattern of a locale dir ("en-rUS" or - * "default")? - * - * TODO: Should insist that the first two letters are lower case, and the - * second two are upper. - */ -bool AaptGroupEntry::getLocaleName(const char* fileName, - ResTable_config* out) -{ - if (strcmp(fileName, kWildcardName) == 0 - || strcmp(fileName, kDefaultLocale) == 0) { - if (out) { - out->language[0] = 0; - out->language[1] = 0; - out->country[0] = 0; - out->country[1] = 0; - } - return true; - } - - if (strlen(fileName) == 2 && isalpha(fileName[0]) && isalpha(fileName[1])) { - if (out) { - out->language[0] = fileName[0]; - out->language[1] = fileName[1]; - out->country[0] = 0; - out->country[1] = 0; - } - return true; - } - - if (strlen(fileName) == 5 && - isalpha(fileName[0]) && - isalpha(fileName[1]) && - fileName[2] == '-' && - isalpha(fileName[3]) && - isalpha(fileName[4])) { - if (out) { - out->language[0] = fileName[0]; - out->language[1] = fileName[1]; - out->country[0] = fileName[3]; - out->country[1] = fileName[4]; - } - return true; - } - - return false; -} - -bool AaptGroupEntry::getLayoutDirectionName(const char* name, ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) out->screenLayout = - (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR) - | ResTable_config::LAYOUTDIR_ANY; - return true; - } else if (strcmp(name, "ldltr") == 0) { - if (out) out->screenLayout = - (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR) - | ResTable_config::LAYOUTDIR_LTR; - return true; - } else if (strcmp(name, "ldrtl") == 0) { - if (out) out->screenLayout = - (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR) - | ResTable_config::LAYOUTDIR_RTL; - return true; - } - - return false; -} - -bool AaptGroupEntry::getScreenLayoutSizeName(const char* name, - ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) out->screenLayout = - (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) - | ResTable_config::SCREENSIZE_ANY; - return true; - } else if (strcmp(name, "small") == 0) { - if (out) out->screenLayout = - (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) - | ResTable_config::SCREENSIZE_SMALL; - return true; - } else if (strcmp(name, "normal") == 0) { - if (out) out->screenLayout = - (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) - | ResTable_config::SCREENSIZE_NORMAL; - return true; - } else if (strcmp(name, "large") == 0) { - if (out) out->screenLayout = - (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) - | ResTable_config::SCREENSIZE_LARGE; - return true; - } else if (strcmp(name, "xlarge") == 0) { - if (out) out->screenLayout = - (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) - | ResTable_config::SCREENSIZE_XLARGE; - return true; - } - - return false; -} - -bool AaptGroupEntry::getScreenLayoutLongName(const char* name, - ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) out->screenLayout = - (out->screenLayout&~ResTable_config::MASK_SCREENLONG) - | ResTable_config::SCREENLONG_ANY; - return true; - } else if (strcmp(name, "long") == 0) { - if (out) out->screenLayout = - (out->screenLayout&~ResTable_config::MASK_SCREENLONG) - | ResTable_config::SCREENLONG_YES; - return true; - } else if (strcmp(name, "notlong") == 0) { - if (out) out->screenLayout = - (out->screenLayout&~ResTable_config::MASK_SCREENLONG) - | ResTable_config::SCREENLONG_NO; - return true; - } - - return false; -} - -bool AaptGroupEntry::getOrientationName(const char* name, - ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) out->orientation = out->ORIENTATION_ANY; - return true; - } else if (strcmp(name, "port") == 0) { - if (out) out->orientation = out->ORIENTATION_PORT; - return true; - } else if (strcmp(name, "land") == 0) { - if (out) out->orientation = out->ORIENTATION_LAND; - return true; - } else if (strcmp(name, "square") == 0) { - if (out) out->orientation = out->ORIENTATION_SQUARE; - return true; - } - - return false; -} - -bool AaptGroupEntry::getUiModeTypeName(const char* name, - ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) out->uiMode = - (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) - | ResTable_config::UI_MODE_TYPE_ANY; - return true; - } else if (strcmp(name, "desk") == 0) { - if (out) out->uiMode = - (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) - | ResTable_config::UI_MODE_TYPE_DESK; - return true; - } else if (strcmp(name, "car") == 0) { - if (out) out->uiMode = - (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) - | ResTable_config::UI_MODE_TYPE_CAR; - return true; - } else if (strcmp(name, "television") == 0) { - if (out) out->uiMode = - (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) - | ResTable_config::UI_MODE_TYPE_TELEVISION; - return true; - } else if (strcmp(name, "appliance") == 0) { - if (out) out->uiMode = - (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) - | ResTable_config::UI_MODE_TYPE_APPLIANCE; - return true; - } - - return false; -} - -bool AaptGroupEntry::getUiModeNightName(const char* name, - ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) out->uiMode = - (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) - | ResTable_config::UI_MODE_NIGHT_ANY; - return true; - } else if (strcmp(name, "night") == 0) { - if (out) out->uiMode = - (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) - | ResTable_config::UI_MODE_NIGHT_YES; - return true; - } else if (strcmp(name, "notnight") == 0) { - if (out) out->uiMode = - (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) - | ResTable_config::UI_MODE_NIGHT_NO; - return true; - } - - return false; -} - -bool AaptGroupEntry::getDensityName(const char* name, - ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) out->density = ResTable_config::DENSITY_DEFAULT; - return true; - } - - if (strcmp(name, "nodpi") == 0) { - if (out) out->density = ResTable_config::DENSITY_NONE; - return true; - } - - if (strcmp(name, "ldpi") == 0) { - if (out) out->density = ResTable_config::DENSITY_LOW; - return true; - } - - if (strcmp(name, "mdpi") == 0) { - if (out) out->density = ResTable_config::DENSITY_MEDIUM; - return true; - } - - if (strcmp(name, "tvdpi") == 0) { - if (out) out->density = ResTable_config::DENSITY_TV; - return true; - } - - if (strcmp(name, "hdpi") == 0) { - if (out) out->density = ResTable_config::DENSITY_HIGH; - return true; - } - - if (strcmp(name, "xhdpi") == 0) { - if (out) out->density = ResTable_config::DENSITY_XHIGH; - return true; - } - - if (strcmp(name, "xxhdpi") == 0) { - if (out) out->density = ResTable_config::DENSITY_XXHIGH; - return true; - } - - if (strcmp(name, "xxxhdpi") == 0) { - if (out) out->density = ResTable_config::DENSITY_XXXHIGH; - return true; - } - - char* c = (char*)name; - while (*c >= '0' && *c <= '9') { - c++; - } - - // check that we have 'dpi' after the last digit. - if (toupper(c[0]) != 'D' || - toupper(c[1]) != 'P' || - toupper(c[2]) != 'I' || - c[3] != 0) { - return false; - } - - // temporarily replace the first letter with \0 to - // use atoi. - char tmp = c[0]; - c[0] = '\0'; - - int d = atoi(name); - c[0] = tmp; - - if (d != 0) { - if (out) out->density = d; - return true; - } - - return false; -} - -bool AaptGroupEntry::getTouchscreenName(const char* name, - ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) out->touchscreen = out->TOUCHSCREEN_ANY; - return true; - } else if (strcmp(name, "notouch") == 0) { - if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH; - return true; - } else if (strcmp(name, "stylus") == 0) { - if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS; - return true; - } else if (strcmp(name, "finger") == 0) { - if (out) out->touchscreen = out->TOUCHSCREEN_FINGER; - return true; - } - - return false; -} - -bool AaptGroupEntry::getKeysHiddenName(const char* name, - ResTable_config* out) -{ - uint8_t mask = 0; - uint8_t value = 0; - if (strcmp(name, kWildcardName) == 0) { - mask = ResTable_config::MASK_KEYSHIDDEN; - value = ResTable_config::KEYSHIDDEN_ANY; - } else if (strcmp(name, "keysexposed") == 0) { - mask = ResTable_config::MASK_KEYSHIDDEN; - value = ResTable_config::KEYSHIDDEN_NO; - } else if (strcmp(name, "keyshidden") == 0) { - mask = ResTable_config::MASK_KEYSHIDDEN; - value = ResTable_config::KEYSHIDDEN_YES; - } else if (strcmp(name, "keyssoft") == 0) { - mask = ResTable_config::MASK_KEYSHIDDEN; - value = ResTable_config::KEYSHIDDEN_SOFT; - } - - if (mask != 0) { - if (out) out->inputFlags = (out->inputFlags&~mask) | value; - return true; - } - - return false; -} - -bool AaptGroupEntry::getKeyboardName(const char* name, - ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) out->keyboard = out->KEYBOARD_ANY; - return true; - } else if (strcmp(name, "nokeys") == 0) { - if (out) out->keyboard = out->KEYBOARD_NOKEYS; - return true; - } else if (strcmp(name, "qwerty") == 0) { - if (out) out->keyboard = out->KEYBOARD_QWERTY; - return true; - } else if (strcmp(name, "12key") == 0) { - if (out) out->keyboard = out->KEYBOARD_12KEY; - return true; - } - - return false; -} - -bool AaptGroupEntry::getNavHiddenName(const char* name, - ResTable_config* out) -{ - uint8_t mask = 0; - uint8_t value = 0; - if (strcmp(name, kWildcardName) == 0) { - mask = ResTable_config::MASK_NAVHIDDEN; - value = ResTable_config::NAVHIDDEN_ANY; - } else if (strcmp(name, "navexposed") == 0) { - mask = ResTable_config::MASK_NAVHIDDEN; - value = ResTable_config::NAVHIDDEN_NO; - } else if (strcmp(name, "navhidden") == 0) { - mask = ResTable_config::MASK_NAVHIDDEN; - value = ResTable_config::NAVHIDDEN_YES; - } - - if (mask != 0) { - if (out) out->inputFlags = (out->inputFlags&~mask) | value; - return true; - } - - return false; -} - -bool AaptGroupEntry::getNavigationName(const char* name, - ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) out->navigation = out->NAVIGATION_ANY; - return true; - } else if (strcmp(name, "nonav") == 0) { - if (out) out->navigation = out->NAVIGATION_NONAV; - return true; - } else if (strcmp(name, "dpad") == 0) { - if (out) out->navigation = out->NAVIGATION_DPAD; - return true; - } else if (strcmp(name, "trackball") == 0) { - if (out) out->navigation = out->NAVIGATION_TRACKBALL; - return true; - } else if (strcmp(name, "wheel") == 0) { - if (out) out->navigation = out->NAVIGATION_WHEEL; - return true; - } - - return false; -} - -bool AaptGroupEntry::getScreenSizeName(const char* name, ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) { - out->screenWidth = out->SCREENWIDTH_ANY; - out->screenHeight = out->SCREENHEIGHT_ANY; - } - return true; - } - - const char* x = name; - while (*x >= '0' && *x <= '9') x++; - if (x == name || *x != 'x') return false; - String8 xName(name, x-name); - x++; - - const char* y = x; - while (*y >= '0' && *y <= '9') y++; - if (y == name || *y != 0) return false; - String8 yName(x, y-x); - - uint16_t w = (uint16_t)atoi(xName.string()); - uint16_t h = (uint16_t)atoi(yName.string()); - if (w < h) { - return false; - } - - if (out) { - out->screenWidth = w; - out->screenHeight = h; - } - - return true; -} - -bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name, ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) { - out->smallestScreenWidthDp = out->SCREENWIDTH_ANY; - } - return true; - } - - if (*name != 's') return false; - name++; - if (*name != 'w') return false; - name++; - const char* x = name; - while (*x >= '0' && *x <= '9') x++; - if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false; - String8 xName(name, x-name); - - if (out) { - out->smallestScreenWidthDp = (uint16_t)atoi(xName.string()); - } - - return true; -} - -bool AaptGroupEntry::getScreenWidthDpName(const char* name, ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) { - out->screenWidthDp = out->SCREENWIDTH_ANY; - } - return true; - } - - if (*name != 'w') return false; - name++; - const char* x = name; - while (*x >= '0' && *x <= '9') x++; - if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false; - String8 xName(name, x-name); - - if (out) { - out->screenWidthDp = (uint16_t)atoi(xName.string()); - } - - return true; -} - -bool AaptGroupEntry::getScreenHeightDpName(const char* name, ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) { - out->screenHeightDp = out->SCREENWIDTH_ANY; - } - return true; - } - - if (*name != 'h') return false; - name++; - const char* x = name; - while (*x >= '0' && *x <= '9') x++; - if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false; - String8 xName(name, x-name); - - if (out) { - out->screenHeightDp = (uint16_t)atoi(xName.string()); - } - - return true; -} - -bool AaptGroupEntry::getVersionName(const char* name, ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) { - out->sdkVersion = out->SDKVERSION_ANY; - out->minorVersion = out->MINORVERSION_ANY; - } - return true; - } - - if (*name != 'v') { - return false; - } - - name++; - const char* s = name; - while (*s >= '0' && *s <= '9') s++; - if (s == name || *s != 0) return false; - String8 sdkName(name, s-name); - - if (out) { - out->sdkVersion = (uint16_t)atoi(sdkName.string()); - out->minorVersion = 0; - } - - return true; -} - -int AaptGroupEntry::compare(const AaptGroupEntry& o) const -{ - int v = mcc.compare(o.mcc); - if (v == 0) v = mnc.compare(o.mnc); - if (v == 0) v = locale.compare(o.locale); - if (v == 0) v = layoutDirection.compare(o.layoutDirection); - if (v == 0) v = vendor.compare(o.vendor); - if (v == 0) v = smallestScreenWidthDp.compare(o.smallestScreenWidthDp); - if (v == 0) v = screenWidthDp.compare(o.screenWidthDp); - if (v == 0) v = screenHeightDp.compare(o.screenHeightDp); - if (v == 0) v = screenLayoutSize.compare(o.screenLayoutSize); - if (v == 0) v = screenLayoutLong.compare(o.screenLayoutLong); - if (v == 0) v = orientation.compare(o.orientation); - if (v == 0) v = uiModeType.compare(o.uiModeType); - if (v == 0) v = uiModeNight.compare(o.uiModeNight); - if (v == 0) v = density.compare(o.density); - if (v == 0) v = touchscreen.compare(o.touchscreen); - if (v == 0) v = keysHidden.compare(o.keysHidden); - if (v == 0) v = keyboard.compare(o.keyboard); - if (v == 0) v = navHidden.compare(o.navHidden); - if (v == 0) v = navigation.compare(o.navigation); - if (v == 0) v = screenSize.compare(o.screenSize); - if (v == 0) v = version.compare(o.version); - return v; -} - -const ResTable_config& AaptGroupEntry::toParams() const -{ - if (!mParamsChanged) { - return mParams; - } - - mParamsChanged = false; - ResTable_config& params(mParams); - memset(¶ms, 0, sizeof(params)); - getMccName(mcc.string(), ¶ms); - getMncName(mnc.string(), ¶ms); - getLocaleName(locale.string(), ¶ms); - getLayoutDirectionName(layoutDirection.string(), ¶ms); - getSmallestScreenWidthDpName(smallestScreenWidthDp.string(), ¶ms); - getScreenWidthDpName(screenWidthDp.string(), ¶ms); - getScreenHeightDpName(screenHeightDp.string(), ¶ms); - getScreenLayoutSizeName(screenLayoutSize.string(), ¶ms); - getScreenLayoutLongName(screenLayoutLong.string(), ¶ms); - getOrientationName(orientation.string(), ¶ms); - getUiModeTypeName(uiModeType.string(), ¶ms); - getUiModeNightName(uiModeNight.string(), ¶ms); - getDensityName(density.string(), ¶ms); - getTouchscreenName(touchscreen.string(), ¶ms); - getKeysHiddenName(keysHidden.string(), ¶ms); - getKeyboardName(keyboard.string(), ¶ms); - getNavHiddenName(navHidden.string(), ¶ms); - getNavigationName(navigation.string(), ¶ms); - getScreenSizeName(screenSize.string(), ¶ms); - getVersionName(version.string(), ¶ms); - - // Fix up version number based on specified parameters. - int minSdk = 0; - if (params.smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY - || params.screenWidthDp != ResTable_config::SCREENWIDTH_ANY - || params.screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) { - minSdk = SDK_HONEYCOMB_MR2; - } else if ((params.uiMode&ResTable_config::MASK_UI_MODE_TYPE) - != ResTable_config::UI_MODE_TYPE_ANY - || (params.uiMode&ResTable_config::MASK_UI_MODE_NIGHT) - != ResTable_config::UI_MODE_NIGHT_ANY) { - minSdk = SDK_FROYO; - } else if ((params.screenLayout&ResTable_config::MASK_SCREENSIZE) - != ResTable_config::SCREENSIZE_ANY - || (params.screenLayout&ResTable_config::MASK_SCREENLONG) - != ResTable_config::SCREENLONG_ANY - || params.density != ResTable_config::DENSITY_DEFAULT) { - minSdk = SDK_DONUT; - } - - if (minSdk > params.sdkVersion) { - params.sdkVersion = minSdk; - } - - return params; -} - -// ========================================================================= -// ========================================================================= -// ========================================================================= - -void* AaptFile::editData(size_t size) -{ - if (size <= mBufferSize) { - mDataSize = size; - return mData; - } - size_t allocSize = (size*3)/2; - void* buf = realloc(mData, allocSize); - if (buf == NULL) { - return NULL; - } - mData = buf; - mDataSize = size; - mBufferSize = allocSize; - return buf; -} - -void* AaptFile::editData(size_t* outSize) -{ - if (outSize) { - *outSize = mDataSize; - } - return mData; -} - -void* AaptFile::padData(size_t wordSize) -{ - const size_t extra = mDataSize%wordSize; - if (extra == 0) { - return mData; - } - - size_t initial = mDataSize; - void* data = editData(initial+(wordSize-extra)); - if (data != NULL) { - memset(((uint8_t*)data) + initial, 0, wordSize-extra); - } - return data; -} - -status_t AaptFile::writeData(const void* data, size_t size) -{ - size_t end = mDataSize; - size_t total = size + end; - void* buf = editData(total); - if (buf == NULL) { - return UNKNOWN_ERROR; - } - memcpy(((char*)buf)+end, data, size); - return NO_ERROR; -} - -void AaptFile::clearData() -{ - if (mData != NULL) free(mData); - mData = NULL; - mDataSize = 0; - mBufferSize = 0; -} - -String8 AaptFile::getPrintableSource() const -{ - if (hasData()) { - String8 name(mGroupEntry.toDirName(String8())); - name.appendPath(mPath); - name.append(" #generated"); - return name; - } - return mSourceFile; -} - -// ========================================================================= -// ========================================================================= -// ========================================================================= - -status_t AaptGroup::addFile(const sp<AaptFile>& file) -{ - if (mFiles.indexOfKey(file->getGroupEntry()) < 0) { - file->mPath = mPath; - mFiles.add(file->getGroupEntry(), file); - return NO_ERROR; - } - -#if 0 - printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n", - file->getSourceFile().string(), - file->getGroupEntry().toDirName(String8()).string(), - mLeaf.string(), mPath.string()); -#endif - - SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.", - getPrintableSource().string()); - return UNKNOWN_ERROR; -} - -void AaptGroup::removeFile(size_t index) -{ - mFiles.removeItemsAt(index); -} - -void AaptGroup::print(const String8& prefix) const -{ - printf("%s%s\n", prefix.string(), getPath().string()); - const size_t N=mFiles.size(); - size_t i; - for (i=0; i<N; i++) { - sp<AaptFile> file = mFiles.valueAt(i); - const AaptGroupEntry& e = file->getGroupEntry(); - if (file->hasData()) { - printf("%s Gen: (%s) %d bytes\n", prefix.string(), e.toDirName(String8()).string(), - (int)file->getSize()); - } else { - printf("%s Src: (%s) %s\n", prefix.string(), e.toDirName(String8()).string(), - file->getPrintableSource().string()); - } - //printf("%s File Group Entry: %s\n", prefix.string(), - // file->getGroupEntry().toDirName(String8()).string()); - } -} - -String8 AaptGroup::getPrintableSource() const -{ - if (mFiles.size() > 0) { - // Arbitrarily pull the first source file out of the list. - return mFiles.valueAt(0)->getPrintableSource(); - } - - // Should never hit this case, but to be safe... - return getPath(); - -} - -// ========================================================================= -// ========================================================================= -// ========================================================================= - -status_t AaptDir::addFile(const String8& name, const sp<AaptGroup>& file) -{ - if (mFiles.indexOfKey(name) >= 0) { - return ALREADY_EXISTS; - } - mFiles.add(name, file); - return NO_ERROR; -} - -status_t AaptDir::addDir(const String8& name, const sp<AaptDir>& dir) -{ - if (mDirs.indexOfKey(name) >= 0) { - return ALREADY_EXISTS; - } - mDirs.add(name, dir); - return NO_ERROR; -} - -sp<AaptDir> AaptDir::makeDir(const String8& path) -{ - String8 name; - String8 remain = path; - - sp<AaptDir> subdir = this; - while (name = remain.walkPath(&remain), remain != "") { - subdir = subdir->makeDir(name); - } - - ssize_t i = subdir->mDirs.indexOfKey(name); - if (i >= 0) { - return subdir->mDirs.valueAt(i); - } - sp<AaptDir> dir = new AaptDir(name, subdir->mPath.appendPathCopy(name)); - subdir->mDirs.add(name, dir); - return dir; -} - -void AaptDir::removeFile(const String8& name) -{ - mFiles.removeItem(name); -} - -void AaptDir::removeDir(const String8& name) -{ - mDirs.removeItem(name); -} - -status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file) -{ - sp<AaptGroup> group; - if (mFiles.indexOfKey(leafName) >= 0) { - group = mFiles.valueFor(leafName); - } else { - group = new AaptGroup(leafName, mPath.appendPathCopy(leafName)); - mFiles.add(leafName, group); - } - - return group->addFile(file); -} - -ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir, - const AaptGroupEntry& kind, const String8& resType, - sp<FilePathStore>& fullResPaths) -{ - Vector<String8> fileNames; - { - DIR* dir = NULL; - - dir = opendir(srcDir.string()); - if (dir == NULL) { - fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno)); - return UNKNOWN_ERROR; - } - - /* - * Slurp the filenames out of the directory. - */ - while (1) { - struct dirent* entry; - - entry = readdir(dir); - if (entry == NULL) - break; - - if (isHidden(srcDir.string(), entry->d_name)) - continue; - - String8 name(entry->d_name); - fileNames.add(name); - // Add fully qualified path for dependency purposes - // if we're collecting them - if (fullResPaths != NULL) { - fullResPaths->add(srcDir.appendPathCopy(name)); - } - } - closedir(dir); - } - - ssize_t count = 0; - - /* - * Stash away the files and recursively descend into subdirectories. - */ - const size_t N = fileNames.size(); - size_t i; - for (i = 0; i < N; i++) { - String8 pathName(srcDir); - FileType type; - - pathName.appendPath(fileNames[i].string()); - type = getFileType(pathName.string()); - if (type == kFileTypeDirectory) { - sp<AaptDir> subdir; - bool notAdded = false; - if (mDirs.indexOfKey(fileNames[i]) >= 0) { - subdir = mDirs.valueFor(fileNames[i]); - } else { - subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i])); - notAdded = true; - } - ssize_t res = subdir->slurpFullTree(bundle, pathName, kind, - resType, fullResPaths); - if (res < NO_ERROR) { - return res; - } - if (res > 0 && notAdded) { - mDirs.add(fileNames[i], subdir); - } - count += res; - } else if (type == kFileTypeRegular) { - sp<AaptFile> file = new AaptFile(pathName, kind, resType); - status_t err = addLeafFile(fileNames[i], file); - if (err != NO_ERROR) { - return err; - } - - count++; - - } else { - if (bundle->getVerbose()) - printf(" (ignoring non-file/dir '%s')\n", pathName.string()); - } - } - - return count; -} - -status_t AaptDir::validate() const -{ - const size_t NF = mFiles.size(); - const size_t ND = mDirs.size(); - size_t i; - for (i = 0; i < NF; i++) { - if (!validateFileName(mFiles.valueAt(i)->getLeaf().string())) { - SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error( - "Invalid filename. Unable to add."); - return UNKNOWN_ERROR; - } - - size_t j; - for (j = i+1; j < NF; j++) { - if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(), - mFiles.valueAt(j)->getLeaf().string()) == 0) { - SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error( - "File is case-insensitive equivalent to: %s", - mFiles.valueAt(j)->getPrintableSource().string()); - return UNKNOWN_ERROR; - } - - // TODO: if ".gz", check for non-.gz; if non-, check for ".gz" - // (this is mostly caught by the "marked" stuff, below) - } - - for (j = 0; j < ND; j++) { - if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(), - mDirs.valueAt(j)->getLeaf().string()) == 0) { - SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error( - "File conflicts with dir from: %s", - mDirs.valueAt(j)->getPrintableSource().string()); - return UNKNOWN_ERROR; - } - } - } - - for (i = 0; i < ND; i++) { - if (!validateFileName(mDirs.valueAt(i)->getLeaf().string())) { - SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error( - "Invalid directory name, unable to add."); - return UNKNOWN_ERROR; - } - - size_t j; - for (j = i+1; j < ND; j++) { - if (strcasecmp(mDirs.valueAt(i)->getLeaf().string(), - mDirs.valueAt(j)->getLeaf().string()) == 0) { - SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error( - "Directory is case-insensitive equivalent to: %s", - mDirs.valueAt(j)->getPrintableSource().string()); - return UNKNOWN_ERROR; - } - } - - status_t err = mDirs.valueAt(i)->validate(); - if (err != NO_ERROR) { - return err; - } - } - - return NO_ERROR; -} - -void AaptDir::print(const String8& prefix) const -{ - const size_t ND=getDirs().size(); - size_t i; - for (i=0; i<ND; i++) { - getDirs().valueAt(i)->print(prefix); - } - - const size_t NF=getFiles().size(); - for (i=0; i<NF; i++) { - getFiles().valueAt(i)->print(prefix); - } -} - -String8 AaptDir::getPrintableSource() const -{ - if (mFiles.size() > 0) { - // Arbitrarily pull the first file out of the list as the source dir. - return mFiles.valueAt(0)->getPrintableSource().getPathDir(); - } - if (mDirs.size() > 0) { - // Or arbitrarily pull the first dir out of the list as the source dir. - return mDirs.valueAt(0)->getPrintableSource().getPathDir(); - } - - // Should never hit this case, but to be safe... - return mPath; - -} - -// ========================================================================= -// ========================================================================= -// ========================================================================= - -status_t AaptSymbols::applyJavaSymbols(const sp<AaptSymbols>& javaSymbols) -{ - status_t err = NO_ERROR; - size_t N = javaSymbols->mSymbols.size(); - for (size_t i=0; i<N; i++) { - const String8& name = javaSymbols->mSymbols.keyAt(i); - const AaptSymbolEntry& entry = javaSymbols->mSymbols.valueAt(i); - ssize_t pos = mSymbols.indexOfKey(name); - if (pos < 0) { - entry.sourcePos.error("Symbol '%s' declared with <java-symbol> not defined\n", name.string()); - err = UNKNOWN_ERROR; - continue; - } - //printf("**** setting symbol #%d/%d %s to isJavaSymbol=%d\n", - // i, N, name.string(), entry.isJavaSymbol ? 1 : 0); - mSymbols.editValueAt(pos).isJavaSymbol = entry.isJavaSymbol; - } - - N = javaSymbols->mNestedSymbols.size(); - for (size_t i=0; i<N; i++) { - const String8& name = javaSymbols->mNestedSymbols.keyAt(i); - const sp<AaptSymbols>& symbols = javaSymbols->mNestedSymbols.valueAt(i); - ssize_t pos = mNestedSymbols.indexOfKey(name); - if (pos < 0) { - SourcePos pos; - pos.error("Java symbol dir %s not defined\n", name.string()); - err = UNKNOWN_ERROR; - continue; - } - //printf("**** applying java symbols in dir %s\n", name.string()); - status_t myerr = mNestedSymbols.valueAt(pos)->applyJavaSymbols(symbols); - if (myerr != NO_ERROR) { - err = myerr; - } - } - - return err; -} - -// ========================================================================= -// ========================================================================= -// ========================================================================= - -AaptAssets::AaptAssets() - : AaptDir(String8(), String8()), - mChanged(false), mHaveIncludedAssets(false), mRes(NULL) -{ -} - -const SortedVector<AaptGroupEntry>& AaptAssets::getGroupEntries() const { - if (mChanged) { - } - return mGroupEntries; -} - -status_t AaptAssets::addFile(const String8& name, const sp<AaptGroup>& file) -{ - mChanged = true; - return AaptDir::addFile(name, file); -} - -sp<AaptFile> AaptAssets::addFile( - const String8& filePath, const AaptGroupEntry& entry, - const String8& srcDir, sp<AaptGroup>* outGroup, - const String8& resType) -{ - sp<AaptDir> dir = this; - sp<AaptGroup> group; - sp<AaptFile> file; - String8 root, remain(filePath), partialPath; - while (remain.length() > 0) { - root = remain.walkPath(&remain); - partialPath.appendPath(root); - - const String8 rootStr(root); - - if (remain.length() == 0) { - ssize_t i = dir->getFiles().indexOfKey(rootStr); - if (i >= 0) { - group = dir->getFiles().valueAt(i); - } else { - group = new AaptGroup(rootStr, filePath); - status_t res = dir->addFile(rootStr, group); - if (res != NO_ERROR) { - return NULL; - } - } - file = new AaptFile(srcDir.appendPathCopy(filePath), entry, resType); - status_t res = group->addFile(file); - if (res != NO_ERROR) { - return NULL; - } - break; - - } else { - ssize_t i = dir->getDirs().indexOfKey(rootStr); - if (i >= 0) { - dir = dir->getDirs().valueAt(i); - } else { - sp<AaptDir> subdir = new AaptDir(rootStr, partialPath); - status_t res = dir->addDir(rootStr, subdir); - if (res != NO_ERROR) { - return NULL; - } - dir = subdir; - } - } - } - - mGroupEntries.add(entry); - if (outGroup) *outGroup = group; - return file; -} - -void AaptAssets::addResource(const String8& leafName, const String8& path, - const sp<AaptFile>& file, const String8& resType) -{ - sp<AaptDir> res = AaptDir::makeDir(kResString); - String8 dirname = file->getGroupEntry().toDirName(resType); - sp<AaptDir> subdir = res->makeDir(dirname); - sp<AaptGroup> grr = new AaptGroup(leafName, path); - grr->addFile(file); - - subdir->addFile(leafName, grr); -} - - -ssize_t AaptAssets::slurpFromArgs(Bundle* bundle) -{ - int count; - int totalCount = 0; - FileType type; - const Vector<const char *>& resDirs = bundle->getResourceSourceDirs(); - const size_t dirCount =resDirs.size(); - sp<AaptAssets> current = this; - - const int N = bundle->getFileSpecCount(); - - /* - * If a package manifest was specified, include that first. - */ - if (bundle->getAndroidManifestFile() != NULL) { - // place at root of zip. - String8 srcFile(bundle->getAndroidManifestFile()); - addFile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(), - NULL, String8()); - totalCount++; - } - - /* - * If a directory of custom assets was supplied, slurp 'em up. - */ - if (bundle->getAssetSourceDir()) { - const char* assetDir = bundle->getAssetSourceDir(); - - FileType type = getFileType(assetDir); - if (type == kFileTypeNonexistent) { - fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDir); - return UNKNOWN_ERROR; - } - if (type != kFileTypeDirectory) { - fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir); - return UNKNOWN_ERROR; - } - - String8 assetRoot(assetDir); - sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir)); - AaptGroupEntry group; - count = assetAaptDir->slurpFullTree(bundle, assetRoot, group, - String8(), mFullAssetPaths); - if (count < 0) { - totalCount = count; - goto bail; - } - if (count > 0) { - mGroupEntries.add(group); - } - totalCount += count; - - if (bundle->getVerbose()) - printf("Found %d custom asset file%s in %s\n", - count, (count==1) ? "" : "s", assetDir); - } - - /* - * If a directory of resource-specific assets was supplied, slurp 'em up. - */ - for (size_t i=0; i<dirCount; i++) { - const char *res = resDirs[i]; - if (res) { - type = getFileType(res); - if (type == kFileTypeNonexistent) { - fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res); - return UNKNOWN_ERROR; - } - if (type == kFileTypeDirectory) { - if (i>0) { - sp<AaptAssets> nextOverlay = new AaptAssets(); - current->setOverlay(nextOverlay); - current = nextOverlay; - current->setFullResPaths(mFullResPaths); - } - count = current->slurpResourceTree(bundle, String8(res)); - - if (count < 0) { - totalCount = count; - goto bail; - } - totalCount += count; - } - else { - fprintf(stderr, "ERROR: '%s' is not a directory\n", res); - return UNKNOWN_ERROR; - } - } - - } - /* - * Now do any additional raw files. - */ - for (int arg=0; arg<N; arg++) { - const char* assetDir = bundle->getFileSpecEntry(arg); - - FileType type = getFileType(assetDir); - if (type == kFileTypeNonexistent) { - fprintf(stderr, "ERROR: input directory '%s' does not exist\n", assetDir); - return UNKNOWN_ERROR; - } - if (type != kFileTypeDirectory) { - fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir); - return UNKNOWN_ERROR; - } - - String8 assetRoot(assetDir); - - if (bundle->getVerbose()) - printf("Processing raw dir '%s'\n", (const char*) assetDir); - - /* - * Do a recursive traversal of subdir tree. We don't make any - * guarantees about ordering, so we're okay with an inorder search - * using whatever order the OS happens to hand back to us. - */ - count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8(), mFullAssetPaths); - if (count < 0) { - /* failure; report error and remove archive */ - totalCount = count; - goto bail; - } - totalCount += count; - - if (bundle->getVerbose()) - printf("Found %d asset file%s in %s\n", - count, (count==1) ? "" : "s", assetDir); - } - - count = validate(); - if (count != NO_ERROR) { - totalCount = count; - goto bail; - } - - count = filter(bundle); - if (count != NO_ERROR) { - totalCount = count; - goto bail; - } - -bail: - return totalCount; -} - -ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir, - const AaptGroupEntry& kind, - const String8& resType, - sp<FilePathStore>& fullResPaths) -{ - ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths); - if (res > 0) { - mGroupEntries.add(kind); - } - - return res; -} - -ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir) -{ - ssize_t err = 0; - - DIR* dir = opendir(srcDir.string()); - if (dir == NULL) { - fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno)); - return UNKNOWN_ERROR; - } - - status_t count = 0; - - /* - * Run through the directory, looking for dirs that match the - * expected pattern. - */ - while (1) { - struct dirent* entry = readdir(dir); - if (entry == NULL) { - break; - } - - if (isHidden(srcDir.string(), entry->d_name)) { - continue; - } - - String8 subdirName(srcDir); - subdirName.appendPath(entry->d_name); - - AaptGroupEntry group; - String8 resType; - bool b = group.initFromDirName(entry->d_name, &resType); - if (!b) { - fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(), - entry->d_name); - err = -1; - continue; - } - - if (bundle->getMaxResVersion() != NULL && group.getVersionString().length() != 0) { - int maxResInt = atoi(bundle->getMaxResVersion()); - const char *verString = group.getVersionString().string(); - int dirVersionInt = atoi(verString + 1); // skip 'v' in version name - if (dirVersionInt > maxResInt) { - fprintf(stderr, "max res %d, skipping %s\n", maxResInt, entry->d_name); - continue; - } - } - - FileType type = getFileType(subdirName.string()); - - if (type == kFileTypeDirectory) { - sp<AaptDir> dir = makeDir(resType); - ssize_t res = dir->slurpFullTree(bundle, subdirName, group, - resType, mFullResPaths); - if (res < 0) { - count = res; - goto bail; - } - if (res > 0) { - mGroupEntries.add(group); - count += res; - } - - // Only add this directory if we don't already have a resource dir - // for the current type. This ensures that we only add the dir once - // for all configs. - sp<AaptDir> rdir = resDir(resType); - if (rdir == NULL) { - mResDirs.add(dir); - } - } else { - if (bundle->getVerbose()) { - fprintf(stderr, " (ignoring file '%s')\n", subdirName.string()); - } - } - } - -bail: - closedir(dir); - dir = NULL; - - if (err != 0) { - return err; - } - return count; -} - -ssize_t -AaptAssets::slurpResourceZip(Bundle* bundle, const char* filename) -{ - int count = 0; - SortedVector<AaptGroupEntry> entries; - - ZipFile* zip = new ZipFile; - status_t err = zip->open(filename, ZipFile::kOpenReadOnly); - if (err != NO_ERROR) { - fprintf(stderr, "error opening zip file %s\n", filename); - count = err; - delete zip; - return -1; - } - - const int N = zip->getNumEntries(); - for (int i=0; i<N; i++) { - ZipEntry* entry = zip->getEntryByIndex(i); - if (entry->getDeleted()) { - continue; - } - - String8 entryName(entry->getFileName()); - - String8 dirName = entryName.getPathDir(); - sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName); - - String8 resType; - AaptGroupEntry kind; - - String8 remain; - if (entryName.walkPath(&remain) == kResourceDir) { - // these are the resources, pull their type out of the directory name - kind.initFromDirName(remain.walkPath().string(), &resType); - } else { - // these are untyped and don't have an AaptGroupEntry - } - if (entries.indexOf(kind) < 0) { - entries.add(kind); - mGroupEntries.add(kind); - } - - // use the one from the zip file if they both exist. - dir->removeFile(entryName.getPathLeaf()); - - sp<AaptFile> file = new AaptFile(entryName, kind, resType); - status_t err = dir->addLeafFile(entryName.getPathLeaf(), file); - if (err != NO_ERROR) { - fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string()); - count = err; - goto bail; - } - file->setCompressionMethod(entry->getCompressionMethod()); - -#if 0 - if (entryName == "AndroidManifest.xml") { - printf("AndroidManifest.xml\n"); - } - printf("\n\nfile: %s\n", entryName.string()); -#endif - - size_t len = entry->getUncompressedLen(); - void* data = zip->uncompress(entry); - void* buf = file->editData(len); - memcpy(buf, data, len); - -#if 0 - const int OFF = 0; - const unsigned char* p = (unsigned char*)data; - const unsigned char* end = p+len; - p += OFF; - for (int i=0; i<32 && p < end; i++) { - printf("0x%03x ", i*0x10 + OFF); - for (int j=0; j<0x10 && p < end; j++) { - printf(" %02x", *p); - p++; - } - printf("\n"); - } -#endif - - free(data); - - count++; - } - -bail: - delete zip; - return count; -} - -status_t AaptAssets::filter(Bundle* bundle) -{ - ResourceFilter reqFilter; - status_t err = reqFilter.parse(bundle->getConfigurations()); - if (err != NO_ERROR) { - return err; - } - - ResourceFilter prefFilter; - err = prefFilter.parse(bundle->getPreferredConfigurations()); - if (err != NO_ERROR) { - return err; - } - - if (reqFilter.isEmpty() && prefFilter.isEmpty()) { - return NO_ERROR; - } - - if (bundle->getVerbose()) { - if (!reqFilter.isEmpty()) { - printf("Applying required filter: %s\n", - bundle->getConfigurations()); - } - if (!prefFilter.isEmpty()) { - printf("Applying preferred filter: %s\n", - bundle->getPreferredConfigurations()); - } - } - - const Vector<sp<AaptDir> >& resdirs = mResDirs; - const size_t ND = resdirs.size(); - for (size_t i=0; i<ND; i++) { - const sp<AaptDir>& dir = resdirs.itemAt(i); - if (dir->getLeaf() == kValuesDir) { - // The "value" dir is special since a single file defines - // multiple resources, so we can not do filtering on the - // files themselves. - continue; - } - if (dir->getLeaf() == kMipmapDir) { - // We also skip the "mipmap" directory, since the point of this - // is to include all densities without stripping. If you put - // other configurations in here as well they won't be stripped - // either... So don't do that. Seriously. What is wrong with you? - continue; - } - - const size_t NG = dir->getFiles().size(); - for (size_t j=0; j<NG; j++) { - sp<AaptGroup> grp = dir->getFiles().valueAt(j); - - // First remove any configurations we know we don't need. - for (size_t k=0; k<grp->getFiles().size(); k++) { - sp<AaptFile> file = grp->getFiles().valueAt(k); - if (k == 0 && grp->getFiles().size() == 1) { - // If this is the only file left, we need to keep it. - // Otherwise the resource IDs we are using will be inconsistent - // with what we get when not stripping. Sucky, but at least - // for now we can rely on the back-end doing another filtering - // pass to take this out and leave us with this resource name - // containing no entries. - continue; - } - if (file->getPath().getPathExtension() == ".xml") { - // We can't remove .xml files at this point, because when - // we parse them they may add identifier resources, so - // removing them can cause our resource identifiers to - // become inconsistent. - continue; - } - const ResTable_config& config(file->getGroupEntry().toParams()); - if (!reqFilter.match(config)) { - if (bundle->getVerbose()) { - printf("Pruning unneeded resource: %s\n", - file->getPrintableSource().string()); - } - grp->removeFile(k); - k--; - } - } - - // Quick check: no preferred filters, nothing more to do. - if (prefFilter.isEmpty()) { - continue; - } - - // Now deal with preferred configurations. - for (int axis=AXIS_START; axis<=AXIS_END; axis++) { - for (size_t k=0; k<grp->getFiles().size(); k++) { - sp<AaptFile> file = grp->getFiles().valueAt(k); - if (k == 0 && grp->getFiles().size() == 1) { - // If this is the only file left, we need to keep it. - // Otherwise the resource IDs we are using will be inconsistent - // with what we get when not stripping. Sucky, but at least - // for now we can rely on the back-end doing another filtering - // pass to take this out and leave us with this resource name - // containing no entries. - continue; - } - if (file->getPath().getPathExtension() == ".xml") { - // We can't remove .xml files at this point, because when - // we parse them they may add identifier resources, so - // removing them can cause our resource identifiers to - // become inconsistent. - continue; - } - const ResTable_config& config(file->getGroupEntry().toParams()); - if (!prefFilter.match(axis, config)) { - // This is a resource we would prefer not to have. Check - // to see if have a similar variation that we would like - // to have and, if so, we can drop it. - for (size_t m=0; m<grp->getFiles().size(); m++) { - if (m == k) continue; - sp<AaptFile> mfile = grp->getFiles().valueAt(m); - const ResTable_config& mconfig(mfile->getGroupEntry().toParams()); - if (AaptGroupEntry::configSameExcept(config, mconfig, axis)) { - if (prefFilter.match(axis, mconfig)) { - if (bundle->getVerbose()) { - printf("Pruning unneeded resource: %s\n", - file->getPrintableSource().string()); - } - grp->removeFile(k); - k--; - break; - } - } - } - } - } - } - } - } - - return NO_ERROR; -} - -sp<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name) -{ - sp<AaptSymbols> sym = mSymbols.valueFor(name); - if (sym == NULL) { - sym = new AaptSymbols(); - mSymbols.add(name, sym); - } - return sym; -} - -sp<AaptSymbols> AaptAssets::getJavaSymbolsFor(const String8& name) -{ - sp<AaptSymbols> sym = mJavaSymbols.valueFor(name); - if (sym == NULL) { - sym = new AaptSymbols(); - mJavaSymbols.add(name, sym); - } - return sym; -} - -status_t AaptAssets::applyJavaSymbols() -{ - size_t N = mJavaSymbols.size(); - for (size_t i=0; i<N; i++) { - const String8& name = mJavaSymbols.keyAt(i); - const sp<AaptSymbols>& symbols = mJavaSymbols.valueAt(i); - ssize_t pos = mSymbols.indexOfKey(name); - if (pos < 0) { - SourcePos pos; - pos.error("Java symbol dir %s not defined\n", name.string()); - return UNKNOWN_ERROR; - } - //printf("**** applying java symbols in dir %s\n", name.string()); - status_t err = mSymbols.valueAt(pos)->applyJavaSymbols(symbols); - if (err != NO_ERROR) { - return err; - } - } - - return NO_ERROR; -} - -bool AaptAssets::isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const { - //printf("isJavaSymbol %s: public=%d, includePrivate=%d, isJavaSymbol=%d\n", - // sym.name.string(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0, - // sym.isJavaSymbol ? 1 : 0); - if (!mHavePrivateSymbols) return true; - if (sym.isPublic) return true; - if (includePrivate && sym.isJavaSymbol) return true; - return false; -} - -status_t AaptAssets::buildIncludedResources(Bundle* bundle) -{ - if (!mHaveIncludedAssets) { - // Add in all includes. - const Vector<const char*>& incl = bundle->getPackageIncludes(); - const size_t N=incl.size(); - for (size_t i=0; i<N; i++) { - if (bundle->getVerbose()) - printf("Including resources from package: %s\n", incl[i]); - if (!mIncludedAssets.addAssetPath(String8(incl[i]), NULL)) { - fprintf(stderr, "ERROR: Asset package include '%s' not found.\n", - incl[i]); - return UNKNOWN_ERROR; - } - } - mHaveIncludedAssets = true; - } - - return NO_ERROR; -} - -status_t AaptAssets::addIncludedResources(const sp<AaptFile>& file) -{ - const ResTable& res = getIncludedResources(); - // XXX dirty! - return const_cast<ResTable&>(res).add(file->getData(), file->getSize(), NULL); -} - -const ResTable& AaptAssets::getIncludedResources() const -{ - return mIncludedAssets.getResources(false); -} - -void AaptAssets::print(const String8& prefix) const -{ - String8 innerPrefix(prefix); - innerPrefix.append(" "); - String8 innerInnerPrefix(innerPrefix); - innerInnerPrefix.append(" "); - printf("%sConfigurations:\n", prefix.string()); - const size_t N=mGroupEntries.size(); - for (size_t i=0; i<N; i++) { - String8 cname = mGroupEntries.itemAt(i).toDirName(String8()); - printf("%s %s\n", prefix.string(), - cname != "" ? cname.string() : "(default)"); - } - - printf("\n%sFiles:\n", prefix.string()); - AaptDir::print(innerPrefix); - - printf("\n%sResource Dirs:\n", prefix.string()); - const Vector<sp<AaptDir> >& resdirs = mResDirs; - const size_t NR = resdirs.size(); - for (size_t i=0; i<NR; i++) { - const sp<AaptDir>& d = resdirs.itemAt(i); - printf("%s Type %s\n", prefix.string(), d->getLeaf().string()); - d->print(innerInnerPrefix); - } -} - -sp<AaptDir> AaptAssets::resDir(const String8& name) const -{ - const Vector<sp<AaptDir> >& resdirs = mResDirs; - const size_t N = resdirs.size(); - for (size_t i=0; i<N; i++) { - const sp<AaptDir>& d = resdirs.itemAt(i); - if (d->getLeaf() == name) { - return d; - } - } - return NULL; -} - -bool -valid_symbol_name(const String8& symbol) -{ - static char const * const KEYWORDS[] = { - "abstract", "assert", "boolean", "break", - "byte", "case", "catch", "char", "class", "const", "continue", - "default", "do", "double", "else", "enum", "extends", "final", - "finally", "float", "for", "goto", "if", "implements", "import", - "instanceof", "int", "interface", "long", "native", "new", "package", - "private", "protected", "public", "return", "short", "static", - "strictfp", "super", "switch", "synchronized", "this", "throw", - "throws", "transient", "try", "void", "volatile", "while", - "true", "false", "null", - NULL - }; - const char*const* k = KEYWORDS; - const char*const s = symbol.string(); - while (*k) { - if (0 == strcmp(s, *k)) { - return false; - } - k++; - } - return true; -} diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h deleted file mode 100644 index 5cfa913..0000000 --- a/tools/aapt/AaptAssets.h +++ /dev/null @@ -1,633 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Information about assets being operated on. -// -#ifndef __AAPT_ASSETS_H -#define __AAPT_ASSETS_H - -#include <stdlib.h> -#include <androidfw/AssetManager.h> -#include <androidfw/ResourceTypes.h> -#include <utils/KeyedVector.h> -#include <utils/RefBase.h> -#include <utils/SortedVector.h> -#include <utils/String8.h> -#include <utils/String8.h> -#include <utils/Vector.h> -#include "ZipFile.h" - -#include "Bundle.h" -#include "SourcePos.h" - -using namespace android; - - -extern const char * const gDefaultIgnoreAssets; -extern const char * gUserIgnoreAssets; - -bool valid_symbol_name(const String8& str); - -class AaptAssets; - -enum { - AXIS_NONE = 0, - AXIS_MCC = 1, - AXIS_MNC, - AXIS_LANGUAGE, - AXIS_REGION, - AXIS_SCREENLAYOUTSIZE, - AXIS_SCREENLAYOUTLONG, - AXIS_ORIENTATION, - AXIS_UIMODETYPE, - AXIS_UIMODENIGHT, - AXIS_DENSITY, - AXIS_TOUCHSCREEN, - AXIS_KEYSHIDDEN, - AXIS_KEYBOARD, - AXIS_NAVHIDDEN, - AXIS_NAVIGATION, - AXIS_SCREENSIZE, - AXIS_SMALLESTSCREENWIDTHDP, - AXIS_SCREENWIDTHDP, - AXIS_SCREENHEIGHTDP, - AXIS_LAYOUTDIR, - AXIS_VERSION, - - AXIS_START = AXIS_MCC, - AXIS_END = AXIS_VERSION, -}; - -/** - * This structure contains a specific variation of a single file out - * of all the variations it can have that we can have. - */ -struct AaptGroupEntry -{ -public: - AaptGroupEntry() : mParamsChanged(true) { } - AaptGroupEntry(const String8& _locale, const String8& _vendor) - : locale(_locale), vendor(_vendor), mParamsChanged(true) { } - - bool initFromDirName(const char* dir, String8* resType); - - static status_t parseNamePart(const String8& part, int* axis, uint32_t* value); - - static uint32_t getConfigValueForAxis(const ResTable_config& config, int axis); - - static bool configSameExcept(const ResTable_config& config, - const ResTable_config& otherConfig, int axis); - - static bool getMccName(const char* name, ResTable_config* out = NULL); - static bool getMncName(const char* name, ResTable_config* out = NULL); - static bool getLocaleName(const char* name, ResTable_config* out = NULL); - static bool getScreenLayoutSizeName(const char* name, ResTable_config* out = NULL); - static bool getScreenLayoutLongName(const char* name, ResTable_config* out = NULL); - static bool getOrientationName(const char* name, ResTable_config* out = NULL); - static bool getUiModeTypeName(const char* name, ResTable_config* out = NULL); - static bool getUiModeNightName(const char* name, ResTable_config* out = NULL); - static bool getDensityName(const char* name, ResTable_config* out = NULL); - static bool getTouchscreenName(const char* name, ResTable_config* out = NULL); - static bool getKeysHiddenName(const char* name, ResTable_config* out = NULL); - static bool getKeyboardName(const char* name, ResTable_config* out = NULL); - static bool getNavigationName(const char* name, ResTable_config* out = NULL); - static bool getNavHiddenName(const char* name, ResTable_config* out = NULL); - static bool getScreenSizeName(const char* name, ResTable_config* out = NULL); - static bool getSmallestScreenWidthDpName(const char* name, ResTable_config* out = NULL); - static bool getScreenWidthDpName(const char* name, ResTable_config* out = NULL); - static bool getScreenHeightDpName(const char* name, ResTable_config* out = NULL); - static bool getLayoutDirectionName(const char* name, ResTable_config* out = NULL); - static bool getVersionName(const char* name, ResTable_config* out = NULL); - - int compare(const AaptGroupEntry& o) const; - - const ResTable_config& toParams() const; - - inline bool operator<(const AaptGroupEntry& o) const { return compare(o) < 0; } - inline bool operator<=(const AaptGroupEntry& o) const { return compare(o) <= 0; } - inline bool operator==(const AaptGroupEntry& o) const { return compare(o) == 0; } - inline bool operator!=(const AaptGroupEntry& o) const { return compare(o) != 0; } - inline bool operator>=(const AaptGroupEntry& o) const { return compare(o) >= 0; } - inline bool operator>(const AaptGroupEntry& o) const { return compare(o) > 0; } - - String8 toString() const; - String8 toDirName(const String8& resType) const; - - const String8& getVersionString() const { return version; } - -private: - String8 mcc; - String8 mnc; - String8 locale; - String8 vendor; - String8 smallestScreenWidthDp; - String8 screenWidthDp; - String8 screenHeightDp; - String8 screenLayoutSize; - String8 screenLayoutLong; - String8 orientation; - String8 uiModeType; - String8 uiModeNight; - String8 density; - String8 touchscreen; - String8 keysHidden; - String8 keyboard; - String8 navHidden; - String8 navigation; - String8 screenSize; - String8 layoutDirection; - String8 version; - - mutable bool mParamsChanged; - mutable ResTable_config mParams; -}; - -inline int compare_type(const AaptGroupEntry& lhs, const AaptGroupEntry& rhs) -{ - return lhs.compare(rhs); -} - -inline int strictly_order_type(const AaptGroupEntry& lhs, const AaptGroupEntry& rhs) -{ - return compare_type(lhs, rhs) < 0; -} - -class AaptGroup; -class FilePathStore; - -/** - * A single asset file we know about. - */ -class AaptFile : public RefBase -{ -public: - AaptFile(const String8& sourceFile, const AaptGroupEntry& groupEntry, - const String8& resType) - : mGroupEntry(groupEntry) - , mResourceType(resType) - , mSourceFile(sourceFile) - , mData(NULL) - , mDataSize(0) - , mBufferSize(0) - , mCompression(ZipEntry::kCompressStored) - { - //printf("new AaptFile created %s\n", (const char*)sourceFile); - } - virtual ~AaptFile() { - free(mData); - } - - const String8& getPath() const { return mPath; } - const AaptGroupEntry& getGroupEntry() const { return mGroupEntry; } - - // Data API. If there is data attached to the file, - // getSourceFile() is not used. - bool hasData() const { return mData != NULL; } - const void* getData() const { return mData; } - size_t getSize() const { return mDataSize; } - void* editData(size_t size); - void* editData(size_t* outSize = NULL); - void* padData(size_t wordSize); - status_t writeData(const void* data, size_t size); - void clearData(); - - const String8& getResourceType() const { return mResourceType; } - - // File API. If the file does not hold raw data, this is - // a full path to a file on the filesystem that holds its data. - const String8& getSourceFile() const { return mSourceFile; } - - String8 getPrintableSource() const; - - // Desired compression method, as per utils/ZipEntry.h. For example, - // no compression is ZipEntry::kCompressStored. - int getCompressionMethod() const { return mCompression; } - void setCompressionMethod(int c) { mCompression = c; } -private: - friend class AaptGroup; - - String8 mPath; - AaptGroupEntry mGroupEntry; - String8 mResourceType; - String8 mSourceFile; - void* mData; - size_t mDataSize; - size_t mBufferSize; - int mCompression; -}; - -/** - * A group of related files (the same file, with different - * vendor/locale variations). - */ -class AaptGroup : public RefBase -{ -public: - AaptGroup(const String8& leaf, const String8& path) - : mLeaf(leaf), mPath(path) { } - virtual ~AaptGroup() { } - - const String8& getLeaf() const { return mLeaf; } - - // Returns the relative path after the AaptGroupEntry dirs. - const String8& getPath() const { return mPath; } - - const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& getFiles() const - { return mFiles; } - - status_t addFile(const sp<AaptFile>& file); - void removeFile(size_t index); - - void print(const String8& prefix) const; - - String8 getPrintableSource() const; - -private: - String8 mLeaf; - String8 mPath; - - DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > mFiles; -}; - -/** - * A single directory of assets, which can contain files and other - * sub-directories. - */ -class AaptDir : public RefBase -{ -public: - AaptDir(const String8& leaf, const String8& path) - : mLeaf(leaf), mPath(path) { } - virtual ~AaptDir() { } - - const String8& getLeaf() const { return mLeaf; } - - const String8& getPath() const { return mPath; } - - const DefaultKeyedVector<String8, sp<AaptGroup> >& getFiles() const { return mFiles; } - const DefaultKeyedVector<String8, sp<AaptDir> >& getDirs() const { return mDirs; } - - virtual status_t addFile(const String8& name, const sp<AaptGroup>& file); - - void removeFile(const String8& name); - void removeDir(const String8& name); - - /* - * Perform some sanity checks on the names of files and directories here. - * In particular: - * - Check for illegal chars in filenames. - * - Check filename length. - * - Check for presence of ".gz" and non-".gz" copies of same file. - * - Check for multiple files whose names match in a case-insensitive - * fashion (problematic for some systems). - * - * Comparing names against all other names is O(n^2). We could speed - * it up some by sorting the entries and being smarter about what we - * compare against, but I'm not expecting to have enough files in a - * single directory to make a noticeable difference in speed. - * - * Note that sorting here is not enough to guarantee that the package - * contents are sorted -- subsequent updates can rearrange things. - */ - status_t validate() const; - - void print(const String8& prefix) const; - - String8 getPrintableSource() const; - -private: - friend class AaptAssets; - - status_t addDir(const String8& name, const sp<AaptDir>& dir); - sp<AaptDir> makeDir(const String8& name); - status_t addLeafFile(const String8& leafName, - const sp<AaptFile>& file); - virtual ssize_t slurpFullTree(Bundle* bundle, - const String8& srcDir, - const AaptGroupEntry& kind, - const String8& resType, - sp<FilePathStore>& fullResPaths); - - String8 mLeaf; - String8 mPath; - - DefaultKeyedVector<String8, sp<AaptGroup> > mFiles; - DefaultKeyedVector<String8, sp<AaptDir> > mDirs; -}; - -/** - * All information we know about a particular symbol. - */ -class AaptSymbolEntry -{ -public: - AaptSymbolEntry() - : isPublic(false), isJavaSymbol(false), typeCode(TYPE_UNKNOWN) - { - } - AaptSymbolEntry(const String8& _name) - : name(_name), isPublic(false), isJavaSymbol(false), typeCode(TYPE_UNKNOWN) - { - } - AaptSymbolEntry(const AaptSymbolEntry& o) - : name(o.name), sourcePos(o.sourcePos), isPublic(o.isPublic) - , isJavaSymbol(o.isJavaSymbol), comment(o.comment), typeComment(o.typeComment) - , typeCode(o.typeCode), int32Val(o.int32Val), stringVal(o.stringVal) - { - } - AaptSymbolEntry operator=(const AaptSymbolEntry& o) - { - sourcePos = o.sourcePos; - isPublic = o.isPublic; - isJavaSymbol = o.isJavaSymbol; - comment = o.comment; - typeComment = o.typeComment; - typeCode = o.typeCode; - int32Val = o.int32Val; - stringVal = o.stringVal; - return *this; - } - - const String8 name; - - SourcePos sourcePos; - bool isPublic; - bool isJavaSymbol; - - String16 comment; - String16 typeComment; - - enum { - TYPE_UNKNOWN = 0, - TYPE_INT32, - TYPE_STRING - }; - - int typeCode; - - // Value. May be one of these. - int32_t int32Val; - String8 stringVal; -}; - -/** - * A group of related symbols (such as indices into a string block) - * that have been generated from the assets. - */ -class AaptSymbols : public RefBase -{ -public: - AaptSymbols() { } - virtual ~AaptSymbols() { } - - status_t addSymbol(const String8& name, int32_t value, const SourcePos& pos) { - if (!check_valid_symbol_name(name, pos, "symbol")) { - return BAD_VALUE; - } - AaptSymbolEntry& sym = edit_symbol(name, &pos); - sym.typeCode = AaptSymbolEntry::TYPE_INT32; - sym.int32Val = value; - return NO_ERROR; - } - - status_t addStringSymbol(const String8& name, const String8& value, - const SourcePos& pos) { - if (!check_valid_symbol_name(name, pos, "symbol")) { - return BAD_VALUE; - } - AaptSymbolEntry& sym = edit_symbol(name, &pos); - sym.typeCode = AaptSymbolEntry::TYPE_STRING; - sym.stringVal = value; - return NO_ERROR; - } - - status_t makeSymbolPublic(const String8& name, const SourcePos& pos) { - if (!check_valid_symbol_name(name, pos, "symbol")) { - return BAD_VALUE; - } - AaptSymbolEntry& sym = edit_symbol(name, &pos); - sym.isPublic = true; - return NO_ERROR; - } - - status_t makeSymbolJavaSymbol(const String8& name, const SourcePos& pos) { - if (!check_valid_symbol_name(name, pos, "symbol")) { - return BAD_VALUE; - } - AaptSymbolEntry& sym = edit_symbol(name, &pos); - sym.isJavaSymbol = true; - return NO_ERROR; - } - - void appendComment(const String8& name, const String16& comment, const SourcePos& pos) { - if (comment.size() <= 0) { - return; - } - AaptSymbolEntry& sym = edit_symbol(name, &pos); - if (sym.comment.size() == 0) { - sym.comment = comment; - } else { - sym.comment.append(String16("\n")); - sym.comment.append(comment); - } - } - - void appendTypeComment(const String8& name, const String16& comment) { - if (comment.size() <= 0) { - return; - } - AaptSymbolEntry& sym = edit_symbol(name, NULL); - if (sym.typeComment.size() == 0) { - sym.typeComment = comment; - } else { - sym.typeComment.append(String16("\n")); - sym.typeComment.append(comment); - } - } - - sp<AaptSymbols> addNestedSymbol(const String8& name, const SourcePos& pos) { - if (!check_valid_symbol_name(name, pos, "nested symbol")) { - return NULL; - } - - sp<AaptSymbols> sym = mNestedSymbols.valueFor(name); - if (sym == NULL) { - sym = new AaptSymbols(); - mNestedSymbols.add(name, sym); - } - - return sym; - } - - status_t applyJavaSymbols(const sp<AaptSymbols>& javaSymbols); - - const KeyedVector<String8, AaptSymbolEntry>& getSymbols() const - { return mSymbols; } - const DefaultKeyedVector<String8, sp<AaptSymbols> >& getNestedSymbols() const - { return mNestedSymbols; } - - const String16& getComment(const String8& name) const - { return get_symbol(name).comment; } - const String16& getTypeComment(const String8& name) const - { return get_symbol(name).typeComment; } - -private: - bool check_valid_symbol_name(const String8& symbol, const SourcePos& pos, const char* label) { - if (valid_symbol_name(symbol)) { - return true; - } - pos.error("invalid %s: '%s'\n", label, symbol.string()); - return false; - } - AaptSymbolEntry& edit_symbol(const String8& symbol, const SourcePos* pos) { - ssize_t i = mSymbols.indexOfKey(symbol); - if (i < 0) { - i = mSymbols.add(symbol, AaptSymbolEntry(symbol)); - } - AaptSymbolEntry& sym = mSymbols.editValueAt(i); - if (pos != NULL && sym.sourcePos.line < 0) { - sym.sourcePos = *pos; - } - return sym; - } - const AaptSymbolEntry& get_symbol(const String8& symbol) const { - ssize_t i = mSymbols.indexOfKey(symbol); - if (i >= 0) { - return mSymbols.valueAt(i); - } - return mDefSymbol; - } - - KeyedVector<String8, AaptSymbolEntry> mSymbols; - DefaultKeyedVector<String8, sp<AaptSymbols> > mNestedSymbols; - AaptSymbolEntry mDefSymbol; -}; - -class ResourceTypeSet : public RefBase, - public KeyedVector<String8,sp<AaptGroup> > -{ -public: - ResourceTypeSet(); -}; - -// Storage for lists of fully qualified paths for -// resources encountered during slurping. -class FilePathStore : public RefBase, - public Vector<String8> -{ -public: - FilePathStore(); -}; - -/** - * Asset hierarchy being operated on. - */ -class AaptAssets : public AaptDir -{ -public: - AaptAssets(); - virtual ~AaptAssets() { delete mRes; } - - const String8& getPackage() const { return mPackage; } - void setPackage(const String8& package) { - mPackage = package; - mSymbolsPrivatePackage = package; - mHavePrivateSymbols = false; - } - - const SortedVector<AaptGroupEntry>& getGroupEntries() const; - - virtual status_t addFile(const String8& name, const sp<AaptGroup>& file); - - sp<AaptFile> addFile(const String8& filePath, - const AaptGroupEntry& entry, - const String8& srcDir, - sp<AaptGroup>* outGroup, - const String8& resType); - - void addResource(const String8& leafName, - const String8& path, - const sp<AaptFile>& file, - const String8& resType); - - void addGroupEntry(const AaptGroupEntry& entry) { mGroupEntries.add(entry); } - - ssize_t slurpFromArgs(Bundle* bundle); - - sp<AaptSymbols> getSymbolsFor(const String8& name); - - sp<AaptSymbols> getJavaSymbolsFor(const String8& name); - - status_t applyJavaSymbols(); - - const DefaultKeyedVector<String8, sp<AaptSymbols> >& getSymbols() const { return mSymbols; } - - String8 getSymbolsPrivatePackage() const { return mSymbolsPrivatePackage; } - void setSymbolsPrivatePackage(const String8& pkg) { - mSymbolsPrivatePackage = pkg; - mHavePrivateSymbols = mSymbolsPrivatePackage != mPackage; - } - - bool havePrivateSymbols() const { return mHavePrivateSymbols; } - - bool isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const; - - status_t buildIncludedResources(Bundle* bundle); - status_t addIncludedResources(const sp<AaptFile>& file); - const ResTable& getIncludedResources() const; - - void print(const String8& prefix) const; - - inline const Vector<sp<AaptDir> >& resDirs() const { return mResDirs; } - sp<AaptDir> resDir(const String8& name) const; - - inline sp<AaptAssets> getOverlay() { return mOverlay; } - inline void setOverlay(sp<AaptAssets>& overlay) { mOverlay = overlay; } - - inline KeyedVector<String8, sp<ResourceTypeSet> >* getResources() { return mRes; } - inline void - setResources(KeyedVector<String8, sp<ResourceTypeSet> >* res) { delete mRes; mRes = res; } - - inline sp<FilePathStore>& getFullResPaths() { return mFullResPaths; } - inline void - setFullResPaths(sp<FilePathStore>& res) { mFullResPaths = res; } - - inline sp<FilePathStore>& getFullAssetPaths() { return mFullAssetPaths; } - inline void - setFullAssetPaths(sp<FilePathStore>& res) { mFullAssetPaths = res; } - -private: - virtual ssize_t slurpFullTree(Bundle* bundle, - const String8& srcDir, - const AaptGroupEntry& kind, - const String8& resType, - sp<FilePathStore>& fullResPaths); - - ssize_t slurpResourceTree(Bundle* bundle, const String8& srcDir); - ssize_t slurpResourceZip(Bundle* bundle, const char* filename); - - status_t filter(Bundle* bundle); - - String8 mPackage; - SortedVector<AaptGroupEntry> mGroupEntries; - DefaultKeyedVector<String8, sp<AaptSymbols> > mSymbols; - DefaultKeyedVector<String8, sp<AaptSymbols> > mJavaSymbols; - String8 mSymbolsPrivatePackage; - bool mHavePrivateSymbols; - - Vector<sp<AaptDir> > mResDirs; - - bool mChanged; - - bool mHaveIncludedAssets; - AssetManager mIncludedAssets; - - sp<AaptAssets> mOverlay; - KeyedVector<String8, sp<ResourceTypeSet> >* mRes; - - sp<FilePathStore> mFullResPaths; - sp<FilePathStore> mFullAssetPaths; -}; - -#endif // __AAPT_ASSETS_H - diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk deleted file mode 100644 index 452c60a..0000000 --- a/tools/aapt/Android.mk +++ /dev/null @@ -1,103 +0,0 @@ -# -# Copyright 2006 The Android Open Source Project -# -# Android Asset Packaging Tool -# - -# This tool is prebuilt if we're doing an app-only build. -ifeq ($(TARGET_BUILD_APPS),) - - -aapt_src_files := \ - AaptAssets.cpp \ - Command.cpp \ - CrunchCache.cpp \ - FileFinder.cpp \ - Main.cpp \ - Package.cpp \ - StringPool.cpp \ - XMLNode.cpp \ - ResourceFilter.cpp \ - ResourceIdCache.cpp \ - ResourceTable.cpp \ - Images.cpp \ - Resource.cpp \ - pseudolocalize.cpp \ - SourcePos.cpp \ - WorkQueue.cpp \ - ZipEntry.cpp \ - ZipFile.cpp \ - qsort_r_compat.c - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(aapt_src_files) - -LOCAL_CFLAGS += -Wno-format-y2k -ifeq (darwin,$(HOST_OS)) -LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS -endif - -LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS - -LOCAL_C_INCLUDES += external/libpng -LOCAL_C_INCLUDES += external/zlib - -LOCAL_STATIC_LIBRARIES := \ - libandroidfw \ - libutils \ - libcutils \ - libexpat \ - libpng \ - liblog - -ifeq ($(HOST_OS),linux) -LOCAL_LDLIBS += -lrt -ldl -lpthread -endif - -# Statically link libz for MinGW (Win SDK under Linux), -# and dynamically link for all others. -ifneq ($(strip $(USE_MINGW)),) - LOCAL_STATIC_LIBRARIES += libz -else - LOCAL_LDLIBS += -lz -endif - -LOCAL_MODULE := aapt - -include $(BUILD_HOST_EXECUTABLE) - -# aapt for running on the device -# ========================================================= -ifneq ($(SDK_ONLY),true) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(aapt_src_files) - -LOCAL_MODULE := aapt - -LOCAL_C_INCLUDES += bionic -LOCAL_C_INCLUDES += bionic/libstdc++/include -LOCAL_C_INCLUDES += external/stlport/stlport -LOCAL_C_INCLUDES += external/libpng -LOCAL_C_INCLUDES += external/zlib - -LOCAL_CFLAGS += -Wno-non-virtual-dtor - -LOCAL_SHARED_LIBRARIES := \ - libandroidfw \ - libutils \ - libcutils \ - libpng \ - liblog \ - libz - -LOCAL_STATIC_LIBRARIES := \ - libstlport_static \ - libexpat_static - -include $(BUILD_EXECUTABLE) -endif - -endif # TARGET_BUILD_APPS diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h deleted file mode 100644 index b67ca09..0000000 --- a/tools/aapt/Bundle.h +++ /dev/null @@ -1,309 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// State bundle. Used to pass around stuff like command-line args. -// -#ifndef __BUNDLE_H -#define __BUNDLE_H - -#include <stdlib.h> -#include <utils/Log.h> -#include <utils/threads.h> -#include <utils/List.h> -#include <utils/Errors.h> -#include <utils/String8.h> -#include <utils/Vector.h> - -enum { - SDK_CUPCAKE = 3, - SDK_DONUT = 4, - SDK_ECLAIR = 5, - SDK_ECLAIR_0_1 = 6, - SDK_MR1 = 7, - SDK_FROYO = 8, - SDK_HONEYCOMB_MR2 = 13, - SDK_ICE_CREAM_SANDWICH = 14, - SDK_ICE_CREAM_SANDWICH_MR1 = 15, -}; - -/* - * Things we can do. - */ -typedef enum Command { - kCommandUnknown = 0, - kCommandVersion, - kCommandList, - kCommandDump, - kCommandAdd, - kCommandRemove, - kCommandPackage, - kCommandCrunch, - kCommandSingleCrunch, -} Command; - -/* - * Bundle of goodies, including everything specified on the command line. - */ -class Bundle { -public: - Bundle(void) - : mCmd(kCommandUnknown), mVerbose(false), mAndroidList(false), - mForce(false), mGrayscaleTolerance(0), mMakePackageDirs(false), - mUpdate(false), mExtending(false), - mRequireLocalization(false), mPseudolocalize(false), - mWantUTF16(false), mValues(false), mIncludeMetaData(false), - mCompressionMethod(0), mJunkPath(false), mOutputAPKFile(NULL), - mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL), - mAutoAddOverlay(false), mGenDependencies(false), - mAssetSourceDir(NULL), - mCrunchedOutputDir(NULL), mProguardFile(NULL), - mAndroidManifestFile(NULL), mPublicOutputFile(NULL), - mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL), - mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL), - mVersionCode(NULL), mVersionName(NULL), mCustomPackage(NULL), mExtraPackages(NULL), - mMaxResVersion(NULL), mDebugMode(false), mNonConstantId(false), mProduct(NULL), - mUseCrunchCache(false), mErrorOnFailedInsert(false), mOutputTextSymbols(NULL), - mSingleCrunchInputFile(NULL), mSingleCrunchOutputFile(NULL), - mArgc(0), mArgv(NULL) - {} - ~Bundle(void) {} - - /* - * Set the command value. Returns "false" if it was previously set. - */ - Command getCommand(void) const { return mCmd; } - void setCommand(Command cmd) { mCmd = cmd; } - - /* - * Command modifiers. Not all modifiers are appropriate for all - * commands. - */ - bool getVerbose(void) const { return mVerbose; } - void setVerbose(bool val) { mVerbose = val; } - bool getAndroidList(void) const { return mAndroidList; } - void setAndroidList(bool val) { mAndroidList = val; } - bool getForce(void) const { return mForce; } - void setForce(bool val) { mForce = val; } - void setGrayscaleTolerance(int val) { mGrayscaleTolerance = val; } - int getGrayscaleTolerance() const { return mGrayscaleTolerance; } - bool getMakePackageDirs(void) const { return mMakePackageDirs; } - void setMakePackageDirs(bool val) { mMakePackageDirs = val; } - bool getUpdate(void) const { return mUpdate; } - void setUpdate(bool val) { mUpdate = val; } - bool getExtending(void) const { return mExtending; } - void setExtending(bool val) { mExtending = val; } - bool getRequireLocalization(void) const { return mRequireLocalization; } - void setRequireLocalization(bool val) { mRequireLocalization = val; } - bool getPseudolocalize(void) const { return mPseudolocalize; } - void setPseudolocalize(bool val) { mPseudolocalize = val; } - void setWantUTF16(bool val) { mWantUTF16 = val; } - bool getValues(void) const { return mValues; } - void setValues(bool val) { mValues = val; } - bool getIncludeMetaData(void) const { return mIncludeMetaData; } - void setIncludeMetaData(bool val) { mIncludeMetaData = val; } - int getCompressionMethod(void) const { return mCompressionMethod; } - void setCompressionMethod(int val) { mCompressionMethod = val; } - bool getJunkPath(void) const { return mJunkPath; } - void setJunkPath(bool val) { mJunkPath = val; } - const char* getOutputAPKFile() const { return mOutputAPKFile; } - void setOutputAPKFile(const char* val) { mOutputAPKFile = val; } - const char* getManifestPackageNameOverride() const { return mManifestPackageNameOverride; } - void setManifestPackageNameOverride(const char * val) { mManifestPackageNameOverride = val; } - const char* getInstrumentationPackageNameOverride() const { return mInstrumentationPackageNameOverride; } - void setInstrumentationPackageNameOverride(const char * val) { mInstrumentationPackageNameOverride = val; } - bool getAutoAddOverlay() { return mAutoAddOverlay; } - void setAutoAddOverlay(bool val) { mAutoAddOverlay = val; } - bool getGenDependencies() { return mGenDependencies; } - void setGenDependencies(bool val) { mGenDependencies = val; } - bool getErrorOnFailedInsert() { return mErrorOnFailedInsert; } - void setErrorOnFailedInsert(bool val) { mErrorOnFailedInsert = val; } - - bool getUTF16StringsOption() { - return mWantUTF16 || !isMinSdkAtLeast(SDK_FROYO); - } - - /* - * Input options. - */ - const char* getAssetSourceDir() const { return mAssetSourceDir; } - void setAssetSourceDir(const char* dir) { mAssetSourceDir = dir; } - const char* getCrunchedOutputDir() const { return mCrunchedOutputDir; } - void setCrunchedOutputDir(const char* dir) { mCrunchedOutputDir = dir; } - const char* getProguardFile() const { return mProguardFile; } - void setProguardFile(const char* file) { mProguardFile = file; } - const android::Vector<const char*>& getResourceSourceDirs() const { return mResourceSourceDirs; } - void addResourceSourceDir(const char* dir) { mResourceSourceDirs.insertAt(dir,0); } - const char* getAndroidManifestFile() const { return mAndroidManifestFile; } - void setAndroidManifestFile(const char* file) { mAndroidManifestFile = file; } - const char* getPublicOutputFile() const { return mPublicOutputFile; } - void setPublicOutputFile(const char* file) { mPublicOutputFile = file; } - const char* getRClassDir() const { return mRClassDir; } - void setRClassDir(const char* dir) { mRClassDir = dir; } - const char* getConfigurations() const { return mConfigurations.size() > 0 ? mConfigurations.string() : NULL; } - void addConfigurations(const char* val) { if (mConfigurations.size() > 0) { mConfigurations.append(","); mConfigurations.append(val); } else { mConfigurations = val; } } - const char* getPreferredConfigurations() const { return mPreferredConfigurations.size() > 0 ? mPreferredConfigurations.string() : NULL; } - void addPreferredConfigurations(const char* val) { if (mPreferredConfigurations.size() > 0) { mPreferredConfigurations.append(","); mPreferredConfigurations.append(val); } else { mPreferredConfigurations = val; } } - const char* getResourceIntermediatesDir() const { return mResourceIntermediatesDir; } - void setResourceIntermediatesDir(const char* dir) { mResourceIntermediatesDir = dir; } - const android::Vector<const char*>& getPackageIncludes() const { return mPackageIncludes; } - void addPackageInclude(const char* file) { mPackageIncludes.add(file); } - const android::Vector<const char*>& getJarFiles() const { return mJarFiles; } - void addJarFile(const char* file) { mJarFiles.add(file); } - const android::Vector<const char*>& getNoCompressExtensions() const { return mNoCompressExtensions; } - void addNoCompressExtension(const char* ext) { mNoCompressExtensions.add(ext); } - - const char* getManifestMinSdkVersion() const { return mManifestMinSdkVersion; } - void setManifestMinSdkVersion(const char* val) { mManifestMinSdkVersion = val; } - const char* getMinSdkVersion() const { return mMinSdkVersion; } - void setMinSdkVersion(const char* val) { mMinSdkVersion = val; } - const char* getTargetSdkVersion() const { return mTargetSdkVersion; } - void setTargetSdkVersion(const char* val) { mTargetSdkVersion = val; } - const char* getMaxSdkVersion() const { return mMaxSdkVersion; } - void setMaxSdkVersion(const char* val) { mMaxSdkVersion = val; } - const char* getVersionCode() const { return mVersionCode; } - void setVersionCode(const char* val) { mVersionCode = val; } - const char* getVersionName() const { return mVersionName; } - void setVersionName(const char* val) { mVersionName = val; } - const char* getCustomPackage() const { return mCustomPackage; } - void setCustomPackage(const char* val) { mCustomPackage = val; } - const char* getExtraPackages() const { return mExtraPackages; } - void setExtraPackages(const char* val) { mExtraPackages = val; } - const char* getMaxResVersion() const { return mMaxResVersion; } - void setMaxResVersion(const char * val) { mMaxResVersion = val; } - bool getDebugMode() const { return mDebugMode; } - void setDebugMode(bool val) { mDebugMode = val; } - bool getNonConstantId() const { return mNonConstantId; } - void setNonConstantId(bool val) { mNonConstantId = val; } - const char* getProduct() const { return mProduct; } - void setProduct(const char * val) { mProduct = val; } - void setUseCrunchCache(bool val) { mUseCrunchCache = val; } - bool getUseCrunchCache() const { return mUseCrunchCache; } - const char* getOutputTextSymbols() const { return mOutputTextSymbols; } - void setOutputTextSymbols(const char* val) { mOutputTextSymbols = val; } - const char* getSingleCrunchInputFile() const { return mSingleCrunchInputFile; } - void setSingleCrunchInputFile(const char* val) { mSingleCrunchInputFile = val; } - const char* getSingleCrunchOutputFile() const { return mSingleCrunchOutputFile; } - void setSingleCrunchOutputFile(const char* val) { mSingleCrunchOutputFile = val; } - - /* - * Set and get the file specification. - * - * Note this does NOT make a copy of argv. - */ - void setFileSpec(char* const argv[], int argc) { - mArgc = argc; - mArgv = argv; - } - int getFileSpecCount(void) const { return mArgc; } - const char* getFileSpecEntry(int idx) const { return mArgv[idx]; } - void eatArgs(int n) { - if (n > mArgc) n = mArgc; - mArgv += n; - mArgc -= n; - } - -#if 0 - /* - * Package count. Nothing to do with anything else here; this is - * just a convenient place to stuff it so we don't have to pass it - * around everywhere. - */ - int getPackageCount(void) const { return mPackageCount; } - void setPackageCount(int val) { mPackageCount = val; } -#endif - - /* Certain features may only be available on a specific SDK level or - * above. SDK levels that have a non-numeric identifier are assumed - * to be newer than any SDK level that has a number designated. - */ - bool isMinSdkAtLeast(int desired) { - /* If the application specifies a minSdkVersion in the manifest - * then use that. Otherwise, check what the user specified on - * the command line. If neither, it's not available since - * the minimum SDK version is assumed to be 1. - */ - const char *minVer; - if (mManifestMinSdkVersion != NULL) { - minVer = mManifestMinSdkVersion; - } else if (mMinSdkVersion != NULL) { - minVer = mMinSdkVersion; - } else { - return false; - } - - char *end; - int minSdkNum = (int)strtol(minVer, &end, 0); - if (*end == '\0') { - if (minSdkNum < desired) { - return false; - } - } - return true; - } - -private: - /* commands & modifiers */ - Command mCmd; - bool mVerbose; - bool mAndroidList; - bool mForce; - int mGrayscaleTolerance; - bool mMakePackageDirs; - bool mUpdate; - bool mExtending; - bool mRequireLocalization; - bool mPseudolocalize; - bool mWantUTF16; - bool mValues; - bool mIncludeMetaData; - int mCompressionMethod; - bool mJunkPath; - const char* mOutputAPKFile; - const char* mManifestPackageNameOverride; - const char* mInstrumentationPackageNameOverride; - bool mAutoAddOverlay; - bool mGenDependencies; - const char* mAssetSourceDir; - const char* mCrunchedOutputDir; - const char* mProguardFile; - const char* mAndroidManifestFile; - const char* mPublicOutputFile; - const char* mRClassDir; - const char* mResourceIntermediatesDir; - android::String8 mConfigurations; - android::String8 mPreferredConfigurations; - android::Vector<const char*> mPackageIncludes; - android::Vector<const char*> mJarFiles; - android::Vector<const char*> mNoCompressExtensions; - android::Vector<const char*> mResourceSourceDirs; - - const char* mManifestMinSdkVersion; - const char* mMinSdkVersion; - const char* mTargetSdkVersion; - const char* mMaxSdkVersion; - const char* mVersionCode; - const char* mVersionName; - const char* mCustomPackage; - const char* mExtraPackages; - const char* mMaxResVersion; - bool mDebugMode; - bool mNonConstantId; - const char* mProduct; - bool mUseCrunchCache; - bool mErrorOnFailedInsert; - const char* mOutputTextSymbols; - const char* mSingleCrunchInputFile; - const char* mSingleCrunchOutputFile; - - /* file specification */ - int mArgc; - char* const* mArgv; - -#if 0 - /* misc stuff */ - int mPackageCount; -#endif - -}; - -#endif // __BUNDLE_H diff --git a/tools/aapt/CacheUpdater.h b/tools/aapt/CacheUpdater.h deleted file mode 100644 index 0e65589..0000000 --- a/tools/aapt/CacheUpdater.h +++ /dev/null @@ -1,107 +0,0 @@ -// -// Copyright 2011 The Android Open Source Project -// -// Abstraction of calls to system to make directories and delete files and -// wrapper to image processing. - -#ifndef CACHE_UPDATER_H -#define CACHE_UPDATER_H - -#include <utils/String8.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <stdio.h> -#include "Images.h" - -using namespace android; - -/** CacheUpdater - * This is a pure virtual class that declares abstractions of functions useful - * for managing a cache files. This manager is set up to be used in a - * mirror cache where the source tree is duplicated and filled with processed - * images. This class is abstracted to allow for dependency injection during - * unit testing. - * Usage: - * To update/add a file to the cache, call processImage - * To remove a file from the cache, call deleteFile - */ -class CacheUpdater { -public: - // Make sure all the directories along this path exist - virtual void ensureDirectoriesExist(String8 path) = 0; - - // Delete a file - virtual void deleteFile(String8 path) = 0; - - // Process an image from source out to dest - virtual void processImage(String8 source, String8 dest) = 0; -private: -}; - -/** SystemCacheUpdater - * This is an implementation of the above virtual cache updater specification. - * This implementations hits the filesystem to manage a cache and calls out to - * the PNG crunching in images.h to process images out to its cache components. - */ -class SystemCacheUpdater : public CacheUpdater { -public: - // Constructor to set bundle to pass to preProcessImage - SystemCacheUpdater (Bundle* b) - : bundle(b) { }; - - // Make sure all the directories along this path exist - virtual void ensureDirectoriesExist(String8 path) - { - // Check to see if we're dealing with a fully qualified path - String8 existsPath; - String8 toCreate; - String8 remains; - struct stat s; - - // Check optomistically to see if all directories exist. - // If something in the path doesn't exist, then walk the path backwards - // and find the place to start creating directories forward. - if (stat(path.string(),&s) == -1) { - // Walk backwards to find place to start creating directories - existsPath = path; - do { - // As we remove the end of existsPath add it to - // the string of paths to create. - toCreate = existsPath.getPathLeaf().appendPath(toCreate); - existsPath = existsPath.getPathDir(); - } while (stat(existsPath.string(),&s) == -1); - - // Walk forwards and build directories as we go - do { - // Advance to the next segment of the path - existsPath.appendPath(toCreate.walkPath(&remains)); - toCreate = remains; -#ifdef HAVE_MS_C_RUNTIME - _mkdir(existsPath.string()); -#else - mkdir(existsPath.string(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP); -#endif - } while (remains.length() > 0); - } //if - }; - - // Delete a file - virtual void deleteFile(String8 path) - { - if (remove(path.string()) != 0) - fprintf(stderr,"ERROR DELETING %s\n",path.string()); - }; - - // Process an image from source out to dest - virtual void processImage(String8 source, String8 dest) - { - // Make sure we're trying to write to a directory that is extant - ensureDirectoriesExist(dest.getPathDir()); - - preProcessImageToCache(bundle, source, dest); - }; -private: - Bundle* bundle; -}; - -#endif // CACHE_UPDATER_H
\ No newline at end of file diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp deleted file mode 100644 index 7fa8c9d..0000000 --- a/tools/aapt/Command.cpp +++ /dev/null @@ -1,2121 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Android Asset Packaging Tool main entry point. -// -#include "Main.h" -#include "Bundle.h" -#include "ResourceFilter.h" -#include "ResourceTable.h" -#include "Images.h" -#include "XMLNode.h" - -#include <utils/Log.h> -#include <utils/threads.h> -#include <utils/List.h> -#include <utils/Errors.h> - -#include <fcntl.h> -#include <errno.h> - -using namespace android; - -/* - * Show version info. All the cool kids do it. - */ -int doVersion(Bundle* bundle) -{ - if (bundle->getFileSpecCount() != 0) { - printf("(ignoring extra arguments)\n"); - } - printf("Android Asset Packaging Tool, v0.2\n"); - - return 0; -} - - -/* - * Open the file read only. The call fails if the file doesn't exist. - * - * Returns NULL on failure. - */ -ZipFile* openReadOnly(const char* fileName) -{ - ZipFile* zip; - status_t result; - - zip = new ZipFile; - result = zip->open(fileName, ZipFile::kOpenReadOnly); - if (result != NO_ERROR) { - if (result == NAME_NOT_FOUND) { - fprintf(stderr, "ERROR: '%s' not found\n", fileName); - } else if (result == PERMISSION_DENIED) { - fprintf(stderr, "ERROR: '%s' access denied\n", fileName); - } else { - fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n", - fileName); - } - delete zip; - return NULL; - } - - return zip; -} - -/* - * Open the file read-write. The file will be created if it doesn't - * already exist and "okayToCreate" is set. - * - * Returns NULL on failure. - */ -ZipFile* openReadWrite(const char* fileName, bool okayToCreate) -{ - ZipFile* zip = NULL; - status_t result; - int flags; - - flags = ZipFile::kOpenReadWrite; - if (okayToCreate) { - flags |= ZipFile::kOpenCreate; - } - - zip = new ZipFile; - result = zip->open(fileName, flags); - if (result != NO_ERROR) { - delete zip; - zip = NULL; - goto bail; - } - -bail: - return zip; -} - - -/* - * Return a short string describing the compression method. - */ -const char* compressionName(int method) -{ - if (method == ZipEntry::kCompressStored) { - return "Stored"; - } else if (method == ZipEntry::kCompressDeflated) { - return "Deflated"; - } else { - return "Unknown"; - } -} - -/* - * Return the percent reduction in size (0% == no compression). - */ -int calcPercent(long uncompressedLen, long compressedLen) -{ - if (!uncompressedLen) { - return 0; - } else { - return (int) (100.0 - (compressedLen * 100.0) / uncompressedLen + 0.5); - } -} - -/* - * Handle the "list" command, which can be a simple file dump or - * a verbose listing. - * - * The verbose listing closely matches the output of the Info-ZIP "unzip" - * command. - */ -int doList(Bundle* bundle) -{ - int result = 1; - ZipFile* zip = NULL; - const ZipEntry* entry; - long totalUncLen, totalCompLen; - const char* zipFileName; - - if (bundle->getFileSpecCount() != 1) { - fprintf(stderr, "ERROR: specify zip file name (only)\n"); - goto bail; - } - zipFileName = bundle->getFileSpecEntry(0); - - zip = openReadOnly(zipFileName); - if (zip == NULL) { - goto bail; - } - - int count, i; - - if (bundle->getVerbose()) { - printf("Archive: %s\n", zipFileName); - printf( - " Length Method Size Ratio Offset Date Time CRC-32 Name\n"); - printf( - "-------- ------ ------- ----- ------- ---- ---- ------ ----\n"); - } - - totalUncLen = totalCompLen = 0; - - count = zip->getNumEntries(); - for (i = 0; i < count; i++) { - entry = zip->getEntryByIndex(i); - if (bundle->getVerbose()) { - char dateBuf[32]; - time_t when; - - when = entry->getModWhen(); - strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M", - localtime(&when)); - - printf("%8ld %-7.7s %7ld %3d%% %8zd %s %08lx %s\n", - (long) entry->getUncompressedLen(), - compressionName(entry->getCompressionMethod()), - (long) entry->getCompressedLen(), - calcPercent(entry->getUncompressedLen(), - entry->getCompressedLen()), - (size_t) entry->getLFHOffset(), - dateBuf, - entry->getCRC32(), - entry->getFileName()); - } else { - printf("%s\n", entry->getFileName()); - } - - totalUncLen += entry->getUncompressedLen(); - totalCompLen += entry->getCompressedLen(); - } - - if (bundle->getVerbose()) { - printf( - "-------- ------- --- -------\n"); - printf("%8ld %7ld %2d%% %d files\n", - totalUncLen, - totalCompLen, - calcPercent(totalUncLen, totalCompLen), - zip->getNumEntries()); - } - - if (bundle->getAndroidList()) { - AssetManager assets; - if (!assets.addAssetPath(String8(zipFileName), NULL)) { - fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n"); - goto bail; - } - - const ResTable& res = assets.getResources(false); - if (&res == NULL) { - printf("\nNo resource table found.\n"); - } else { -#ifndef HAVE_ANDROID_OS - printf("\nResource table:\n"); - res.print(false); -#endif - } - - Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml", - Asset::ACCESS_BUFFER); - if (manifestAsset == NULL) { - printf("\nNo AndroidManifest.xml found.\n"); - } else { - printf("\nAndroid manifest:\n"); - ResXMLTree tree; - tree.setTo(manifestAsset->getBuffer(true), - manifestAsset->getLength()); - printXMLBlock(&tree); - } - delete manifestAsset; - } - - result = 0; - -bail: - delete zip; - return result; -} - -static ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes) -{ - size_t N = tree.getAttributeCount(); - for (size_t i=0; i<N; i++) { - if (tree.getAttributeNameResID(i) == attrRes) { - return (ssize_t)i; - } - } - return -1; -} - -String8 getAttribute(const ResXMLTree& tree, const char* ns, - const char* attr, String8* outError) -{ - ssize_t idx = tree.indexOfAttribute(ns, attr); - if (idx < 0) { - return String8(); - } - Res_value value; - if (tree.getAttributeValue(idx, &value) != NO_ERROR) { - if (value.dataType != Res_value::TYPE_STRING) { - if (outError != NULL) { - *outError = "attribute is not a string value"; - } - return String8(); - } - } - size_t len; - const uint16_t* str = tree.getAttributeStringValue(idx, &len); - return str ? String8(str, len) : String8(); -} - -static String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError) -{ - ssize_t idx = indexOfAttribute(tree, attrRes); - if (idx < 0) { - return String8(); - } - Res_value value; - if (tree.getAttributeValue(idx, &value) != NO_ERROR) { - if (value.dataType != Res_value::TYPE_STRING) { - if (outError != NULL) { - *outError = "attribute is not a string value"; - } - return String8(); - } - } - size_t len; - const uint16_t* str = tree.getAttributeStringValue(idx, &len); - return str ? String8(str, len) : String8(); -} - -static int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes, - String8* outError, int32_t defValue = -1) -{ - ssize_t idx = indexOfAttribute(tree, attrRes); - if (idx < 0) { - return defValue; - } - Res_value value; - if (tree.getAttributeValue(idx, &value) != NO_ERROR) { - if (value.dataType < Res_value::TYPE_FIRST_INT - || value.dataType > Res_value::TYPE_LAST_INT) { - if (outError != NULL) { - *outError = "attribute is not an integer value"; - } - return defValue; - } - } - return value.data; -} - -static int32_t getResolvedIntegerAttribute(const ResTable* resTable, const ResXMLTree& tree, - uint32_t attrRes, String8* outError, int32_t defValue = -1) -{ - ssize_t idx = indexOfAttribute(tree, attrRes); - if (idx < 0) { - return defValue; - } - Res_value value; - if (tree.getAttributeValue(idx, &value) != NO_ERROR) { - if (value.dataType == Res_value::TYPE_REFERENCE) { - resTable->resolveReference(&value, 0); - } - if (value.dataType < Res_value::TYPE_FIRST_INT - || value.dataType > Res_value::TYPE_LAST_INT) { - if (outError != NULL) { - *outError = "attribute is not an integer value"; - } - return defValue; - } - } - return value.data; -} - -static String8 getResolvedAttribute(const ResTable* resTable, const ResXMLTree& tree, - uint32_t attrRes, String8* outError) -{ - ssize_t idx = indexOfAttribute(tree, attrRes); - if (idx < 0) { - return String8(); - } - Res_value value; - if (tree.getAttributeValue(idx, &value) != NO_ERROR) { - if (value.dataType == Res_value::TYPE_STRING) { - size_t len; - const uint16_t* str = tree.getAttributeStringValue(idx, &len); - return str ? String8(str, len) : String8(); - } - resTable->resolveReference(&value, 0); - if (value.dataType != Res_value::TYPE_STRING) { - if (outError != NULL) { - *outError = "attribute is not a string value"; - } - return String8(); - } - } - size_t len; - const Res_value* value2 = &value; - const char16_t* str = const_cast<ResTable*>(resTable)->valueToString(value2, 0, NULL, &len); - return str ? String8(str, len) : String8(); -} - -static void getResolvedResourceAttribute(Res_value* value, const ResTable* resTable, - const ResXMLTree& tree, uint32_t attrRes, String8* outError) -{ - ssize_t idx = indexOfAttribute(tree, attrRes); - if (idx < 0) { - if (outError != NULL) { - *outError = "attribute could not be found"; - } - return; - } - if (tree.getAttributeValue(idx, value) != NO_ERROR) { - if (value->dataType == Res_value::TYPE_REFERENCE) { - resTable->resolveReference(value, 0); - } - // The attribute was found and was resolved if need be. - return; - } - if (outError != NULL) { - *outError = "error getting resolved resource attribute"; - } -} - -// These are attribute resource constants for the platform, as found -// in android.R.attr -enum { - LABEL_ATTR = 0x01010001, - ICON_ATTR = 0x01010002, - NAME_ATTR = 0x01010003, - DEBUGGABLE_ATTR = 0x0101000f, - VALUE_ATTR = 0x01010024, - VERSION_CODE_ATTR = 0x0101021b, - VERSION_NAME_ATTR = 0x0101021c, - SCREEN_ORIENTATION_ATTR = 0x0101001e, - MIN_SDK_VERSION_ATTR = 0x0101020c, - MAX_SDK_VERSION_ATTR = 0x01010271, - REQ_TOUCH_SCREEN_ATTR = 0x01010227, - REQ_KEYBOARD_TYPE_ATTR = 0x01010228, - REQ_HARD_KEYBOARD_ATTR = 0x01010229, - REQ_NAVIGATION_ATTR = 0x0101022a, - REQ_FIVE_WAY_NAV_ATTR = 0x01010232, - TARGET_SDK_VERSION_ATTR = 0x01010270, - TEST_ONLY_ATTR = 0x01010272, - ANY_DENSITY_ATTR = 0x0101026c, - GL_ES_VERSION_ATTR = 0x01010281, - SMALL_SCREEN_ATTR = 0x01010284, - NORMAL_SCREEN_ATTR = 0x01010285, - LARGE_SCREEN_ATTR = 0x01010286, - XLARGE_SCREEN_ATTR = 0x010102bf, - REQUIRED_ATTR = 0x0101028e, - SCREEN_SIZE_ATTR = 0x010102ca, - SCREEN_DENSITY_ATTR = 0x010102cb, - REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364, - COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365, - LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366, - PUBLIC_KEY_ATTR = 0x010103a6, -}; - -const char *getComponentName(String8 &pkgName, String8 &componentName) { - ssize_t idx = componentName.find("."); - String8 retStr(pkgName); - if (idx == 0) { - retStr += componentName; - } else if (idx < 0) { - retStr += "."; - retStr += componentName; - } else { - return componentName.string(); - } - return retStr.string(); -} - -static void printCompatibleScreens(ResXMLTree& tree) { - size_t len; - ResXMLTree::event_code_t code; - int depth = 0; - bool first = true; - printf("compatible-screens:"); - while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::END_TAG) { - depth--; - if (depth < 0) { - break; - } - continue; - } - if (code != ResXMLTree::START_TAG) { - continue; - } - depth++; - String8 tag(tree.getElementName(&len)); - if (tag == "screen") { - int32_t screenSize = getIntegerAttribute(tree, - SCREEN_SIZE_ATTR, NULL, -1); - int32_t screenDensity = getIntegerAttribute(tree, - SCREEN_DENSITY_ATTR, NULL, -1); - if (screenSize > 0 && screenDensity > 0) { - if (!first) { - printf(","); - } - first = false; - printf("'%d/%d'", screenSize, screenDensity); - } - } - } - printf("\n"); -} - -/* - * Handle the "dump" command, to extract select data from an archive. - */ -extern char CONSOLE_DATA[2925]; // see EOF -int doDump(Bundle* bundle) -{ - status_t result = UNKNOWN_ERROR; - Asset* asset = NULL; - - if (bundle->getFileSpecCount() < 1) { - fprintf(stderr, "ERROR: no dump option specified\n"); - return 1; - } - - if (bundle->getFileSpecCount() < 2) { - fprintf(stderr, "ERROR: no dump file specified\n"); - return 1; - } - - const char* option = bundle->getFileSpecEntry(0); - const char* filename = bundle->getFileSpecEntry(1); - - AssetManager assets; - void* assetsCookie; - if (!assets.addAssetPath(String8(filename), &assetsCookie)) { - fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n"); - return 1; - } - - // Make a dummy config for retrieving resources... we need to supply - // non-default values for some configs so that we can retrieve resources - // in the app that don't have a default. The most important of these is - // the API version because key resources like icons will have an implicit - // version if they are using newer config types like density. - ResTable_config config; - config.language[0] = 'e'; - config.language[1] = 'n'; - config.country[0] = 'U'; - config.country[1] = 'S'; - config.orientation = ResTable_config::ORIENTATION_PORT; - config.density = ResTable_config::DENSITY_MEDIUM; - config.sdkVersion = 10000; // Very high. - config.screenWidthDp = 320; - config.screenHeightDp = 480; - config.smallestScreenWidthDp = 320; - assets.setConfiguration(config); - - const ResTable& res = assets.getResources(false); - if (&res == NULL) { - fprintf(stderr, "ERROR: dump failed because no resource table was found\n"); - goto bail; - } - - if (strcmp("resources", option) == 0) { -#ifndef HAVE_ANDROID_OS - res.print(bundle->getValues()); -#endif - - } else if (strcmp("strings", option) == 0) { - const ResStringPool* pool = res.getTableStringBlock(0); - printStringPool(pool); - - } else if (strcmp("xmltree", option) == 0) { - if (bundle->getFileSpecCount() < 3) { - fprintf(stderr, "ERROR: no dump xmltree resource file specified\n"); - goto bail; - } - - for (int i=2; i<bundle->getFileSpecCount(); i++) { - const char* resname = bundle->getFileSpecEntry(i); - ResXMLTree tree; - asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER); - if (asset == NULL) { - fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname); - goto bail; - } - - if (tree.setTo(asset->getBuffer(true), - asset->getLength()) != NO_ERROR) { - fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname); - goto bail; - } - tree.restart(); - printXMLBlock(&tree); - tree.uninit(); - delete asset; - asset = NULL; - } - - } else if (strcmp("xmlstrings", option) == 0) { - if (bundle->getFileSpecCount() < 3) { - fprintf(stderr, "ERROR: no dump xmltree resource file specified\n"); - goto bail; - } - - for (int i=2; i<bundle->getFileSpecCount(); i++) { - const char* resname = bundle->getFileSpecEntry(i); - ResXMLTree tree; - asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER); - if (asset == NULL) { - fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname); - goto bail; - } - - if (tree.setTo(asset->getBuffer(true), - asset->getLength()) != NO_ERROR) { - fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname); - goto bail; - } - printStringPool(&tree.getStrings()); - delete asset; - asset = NULL; - } - - } else { - ResXMLTree tree; - asset = assets.openNonAsset("AndroidManifest.xml", - Asset::ACCESS_BUFFER); - if (asset == NULL) { - fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n"); - goto bail; - } - - if (tree.setTo(asset->getBuffer(true), - asset->getLength()) != NO_ERROR) { - fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n"); - goto bail; - } - tree.restart(); - - if (strcmp("permissions", option) == 0) { - size_t len; - ResXMLTree::event_code_t code; - int depth = 0; - while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::END_TAG) { - depth--; - continue; - } - if (code != ResXMLTree::START_TAG) { - continue; - } - depth++; - String8 tag(tree.getElementName(&len)); - //printf("Depth %d tag %s\n", depth, tag.string()); - if (depth == 1) { - if (tag != "manifest") { - fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n"); - goto bail; - } - String8 pkg = getAttribute(tree, NULL, "package", NULL); - printf("package: %s\n", pkg.string()); - } else if (depth == 2 && tag == "permission") { - String8 error; - String8 name = getAttribute(tree, NAME_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR: %s\n", error.string()); - goto bail; - } - printf("permission: %s\n", name.string()); - } else if (depth == 2 && tag == "uses-permission") { - String8 error; - String8 name = getAttribute(tree, NAME_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR: %s\n", error.string()); - goto bail; - } - printf("uses-permission: %s\n", name.string()); - int req = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1); - if (!req) { - printf("optional-permission: %s\n", name.string()); - } - } - } - } else if (strcmp("badging", option) == 0) { - Vector<String8> locales; - res.getLocales(&locales); - - Vector<ResTable_config> configs; - res.getConfigurations(&configs); - SortedVector<int> densities; - const size_t NC = configs.size(); - for (size_t i=0; i<NC; i++) { - int dens = configs[i].density; - if (dens == 0) { - dens = 160; - } - densities.add(dens); - } - - size_t len; - ResXMLTree::event_code_t code; - int depth = 0; - String8 error; - bool withinActivity = false; - bool isMainActivity = false; - bool isLauncherActivity = false; - bool isSearchable = false; - bool withinApplication = false; - bool withinReceiver = false; - bool withinService = false; - bool withinIntentFilter = false; - bool hasMainActivity = false; - bool hasOtherActivities = false; - bool hasOtherReceivers = false; - bool hasOtherServices = false; - bool hasWallpaperService = false; - bool hasImeService = false; - bool hasWidgetReceivers = false; - bool hasIntentFilter = false; - bool actMainActivity = false; - bool actWidgetReceivers = false; - bool actImeService = false; - bool actWallpaperService = false; - - // These two implement the implicit permissions that are granted - // to pre-1.6 applications. - bool hasWriteExternalStoragePermission = false; - bool hasReadPhoneStatePermission = false; - - // If an app requests write storage, they will also get read storage. - bool hasReadExternalStoragePermission = false; - - // Implement transition to read and write call log. - bool hasReadContactsPermission = false; - bool hasWriteContactsPermission = false; - bool hasReadCallLogPermission = false; - bool hasWriteCallLogPermission = false; - - // This next group of variables is used to implement a group of - // backward-compatibility heuristics necessitated by the addition of - // some new uses-feature constants in 2.1 and 2.2. In most cases, the - // heuristic is "if an app requests a permission but doesn't explicitly - // request the corresponding <uses-feature>, presume it's there anyway". - bool specCameraFeature = false; // camera-related - bool specCameraAutofocusFeature = false; - bool reqCameraAutofocusFeature = false; - bool reqCameraFlashFeature = false; - bool hasCameraPermission = false; - bool specLocationFeature = false; // location-related - bool specNetworkLocFeature = false; - bool reqNetworkLocFeature = false; - bool specGpsFeature = false; - bool reqGpsFeature = false; - bool hasMockLocPermission = false; - bool hasCoarseLocPermission = false; - bool hasGpsPermission = false; - bool hasGeneralLocPermission = false; - bool specBluetoothFeature = false; // Bluetooth API-related - bool hasBluetoothPermission = false; - bool specMicrophoneFeature = false; // microphone-related - bool hasRecordAudioPermission = false; - bool specWiFiFeature = false; - bool hasWiFiPermission = false; - bool specTelephonyFeature = false; // telephony-related - bool reqTelephonySubFeature = false; - bool hasTelephonyPermission = false; - bool specTouchscreenFeature = false; // touchscreen-related - bool specMultitouchFeature = false; - bool reqDistinctMultitouchFeature = false; - bool specScreenPortraitFeature = false; - bool specScreenLandscapeFeature = false; - bool reqScreenPortraitFeature = false; - bool reqScreenLandscapeFeature = false; - // 2.2 also added some other features that apps can request, but that - // have no corresponding permission, so we cannot implement any - // back-compatibility heuristic for them. The below are thus unnecessary - // (but are retained here for documentary purposes.) - //bool specCompassFeature = false; - //bool specAccelerometerFeature = false; - //bool specProximityFeature = false; - //bool specAmbientLightFeature = false; - //bool specLiveWallpaperFeature = false; - - int targetSdk = 0; - int smallScreen = 1; - int normalScreen = 1; - int largeScreen = 1; - int xlargeScreen = 1; - int anyDensity = 1; - int requiresSmallestWidthDp = 0; - int compatibleWidthLimitDp = 0; - int largestWidthLimitDp = 0; - String8 pkg; - String8 activityName; - String8 activityLabel; - String8 activityIcon; - String8 receiverName; - String8 serviceName; - while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::END_TAG) { - depth--; - if (depth < 2) { - withinApplication = false; - } else if (depth < 3) { - if (withinActivity && isMainActivity && isLauncherActivity) { - const char *aName = getComponentName(pkg, activityName); - printf("launchable-activity:"); - if (aName != NULL) { - printf(" name='%s' ", aName); - } - printf(" label='%s' icon='%s'\n", - activityLabel.string(), - activityIcon.string()); - } - if (!hasIntentFilter) { - hasOtherActivities |= withinActivity; - hasOtherReceivers |= withinReceiver; - hasOtherServices |= withinService; - } - withinActivity = false; - withinService = false; - withinReceiver = false; - hasIntentFilter = false; - isMainActivity = isLauncherActivity = false; - } else if (depth < 4) { - if (withinIntentFilter) { - if (withinActivity) { - hasMainActivity |= actMainActivity; - hasOtherActivities |= !actMainActivity; - } else if (withinReceiver) { - hasWidgetReceivers |= actWidgetReceivers; - hasOtherReceivers |= !actWidgetReceivers; - } else if (withinService) { - hasImeService |= actImeService; - hasWallpaperService |= actWallpaperService; - hasOtherServices |= (!actImeService && !actWallpaperService); - } - } - withinIntentFilter = false; - } - continue; - } - if (code != ResXMLTree::START_TAG) { - continue; - } - depth++; - String8 tag(tree.getElementName(&len)); - //printf("Depth %d, %s\n", depth, tag.string()); - if (depth == 1) { - if (tag != "manifest") { - fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n"); - goto bail; - } - pkg = getAttribute(tree, NULL, "package", NULL); - printf("package: name='%s' ", pkg.string()); - int32_t versionCode = getIntegerAttribute(tree, VERSION_CODE_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string()); - goto bail; - } - if (versionCode > 0) { - printf("versionCode='%d' ", versionCode); - } else { - printf("versionCode='' "); - } - String8 versionName = getResolvedAttribute(&res, tree, VERSION_NAME_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string()); - goto bail; - } - printf("versionName='%s'\n", versionName.string()); - } else if (depth == 2) { - withinApplication = false; - if (tag == "application") { - withinApplication = true; - - String8 label; - const size_t NL = locales.size(); - for (size_t i=0; i<NL; i++) { - const char* localeStr = locales[i].string(); - assets.setLocale(localeStr != NULL ? localeStr : ""); - String8 llabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error); - if (llabel != "") { - if (localeStr == NULL || strlen(localeStr) == 0) { - label = llabel; - printf("application-label:'%s'\n", llabel.string()); - } else { - if (label == "") { - label = llabel; - } - printf("application-label-%s:'%s'\n", localeStr, - llabel.string()); - } - } - } - - ResTable_config tmpConfig = config; - const size_t ND = densities.size(); - for (size_t i=0; i<ND; i++) { - tmpConfig.density = densities[i]; - assets.setConfiguration(tmpConfig); - String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); - if (icon != "") { - printf("application-icon-%d:'%s'\n", densities[i], icon.string()); - } - } - assets.setConfiguration(config); - - String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string()); - goto bail; - } - int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string()); - goto bail; - } - printf("application: label='%s' ", label.string()); - printf("icon='%s'\n", icon.string()); - if (testOnly != 0) { - printf("testOnly='%d'\n", testOnly); - } - - int32_t debuggable = getResolvedIntegerAttribute(&res, tree, DEBUGGABLE_ATTR, &error, 0); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:debuggable' attribute: %s\n", error.string()); - goto bail; - } - if (debuggable != 0) { - printf("application-debuggable\n"); - } - } else if (tag == "uses-sdk") { - int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error); - if (error != "") { - error = ""; - String8 name = getResolvedAttribute(&res, tree, MIN_SDK_VERSION_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n", - error.string()); - goto bail; - } - if (name == "Donut") targetSdk = 4; - printf("sdkVersion:'%s'\n", name.string()); - } else if (code != -1) { - targetSdk = code; - printf("sdkVersion:'%d'\n", code); - } - code = getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1); - if (code != -1) { - printf("maxSdkVersion:'%d'\n", code); - } - code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error); - if (error != "") { - error = ""; - String8 name = getResolvedAttribute(&res, tree, TARGET_SDK_VERSION_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n", - error.string()); - goto bail; - } - if (name == "Donut" && targetSdk < 4) targetSdk = 4; - printf("targetSdkVersion:'%s'\n", name.string()); - } else if (code != -1) { - if (targetSdk < code) { - targetSdk = code; - } - printf("targetSdkVersion:'%d'\n", code); - } - } else if (tag == "uses-configuration") { - int32_t reqTouchScreen = getIntegerAttribute(tree, - REQ_TOUCH_SCREEN_ATTR, NULL, 0); - int32_t reqKeyboardType = getIntegerAttribute(tree, - REQ_KEYBOARD_TYPE_ATTR, NULL, 0); - int32_t reqHardKeyboard = getIntegerAttribute(tree, - REQ_HARD_KEYBOARD_ATTR, NULL, 0); - int32_t reqNavigation = getIntegerAttribute(tree, - REQ_NAVIGATION_ATTR, NULL, 0); - int32_t reqFiveWayNav = getIntegerAttribute(tree, - REQ_FIVE_WAY_NAV_ATTR, NULL, 0); - printf("uses-configuration:"); - if (reqTouchScreen != 0) { - printf(" reqTouchScreen='%d'", reqTouchScreen); - } - if (reqKeyboardType != 0) { - printf(" reqKeyboardType='%d'", reqKeyboardType); - } - if (reqHardKeyboard != 0) { - printf(" reqHardKeyboard='%d'", reqHardKeyboard); - } - if (reqNavigation != 0) { - printf(" reqNavigation='%d'", reqNavigation); - } - if (reqFiveWayNav != 0) { - printf(" reqFiveWayNav='%d'", reqFiveWayNav); - } - printf("\n"); - } else if (tag == "supports-screens") { - smallScreen = getIntegerAttribute(tree, - SMALL_SCREEN_ATTR, NULL, 1); - normalScreen = getIntegerAttribute(tree, - NORMAL_SCREEN_ATTR, NULL, 1); - largeScreen = getIntegerAttribute(tree, - LARGE_SCREEN_ATTR, NULL, 1); - xlargeScreen = getIntegerAttribute(tree, - XLARGE_SCREEN_ATTR, NULL, 1); - anyDensity = getIntegerAttribute(tree, - ANY_DENSITY_ATTR, NULL, 1); - requiresSmallestWidthDp = getIntegerAttribute(tree, - REQUIRES_SMALLEST_WIDTH_DP_ATTR, NULL, 0); - compatibleWidthLimitDp = getIntegerAttribute(tree, - COMPATIBLE_WIDTH_LIMIT_DP_ATTR, NULL, 0); - largestWidthLimitDp = getIntegerAttribute(tree, - LARGEST_WIDTH_LIMIT_DP_ATTR, NULL, 0); - } else if (tag == "uses-feature") { - String8 name = getAttribute(tree, NAME_ATTR, &error); - - if (name != "" && error == "") { - int req = getIntegerAttribute(tree, - REQUIRED_ATTR, NULL, 1); - - if (name == "android.hardware.camera") { - specCameraFeature = true; - } else if (name == "android.hardware.camera.autofocus") { - // these have no corresponding permission to check for, - // but should imply the foundational camera permission - reqCameraAutofocusFeature = reqCameraAutofocusFeature || req; - specCameraAutofocusFeature = true; - } else if (req && (name == "android.hardware.camera.flash")) { - // these have no corresponding permission to check for, - // but should imply the foundational camera permission - reqCameraFlashFeature = true; - } else if (name == "android.hardware.location") { - specLocationFeature = true; - } else if (name == "android.hardware.location.network") { - specNetworkLocFeature = true; - reqNetworkLocFeature = reqNetworkLocFeature || req; - } else if (name == "android.hardware.location.gps") { - specGpsFeature = true; - reqGpsFeature = reqGpsFeature || req; - } else if (name == "android.hardware.bluetooth") { - specBluetoothFeature = true; - } else if (name == "android.hardware.touchscreen") { - specTouchscreenFeature = true; - } else if (name == "android.hardware.touchscreen.multitouch") { - specMultitouchFeature = true; - } else if (name == "android.hardware.touchscreen.multitouch.distinct") { - reqDistinctMultitouchFeature = reqDistinctMultitouchFeature || req; - } else if (name == "android.hardware.microphone") { - specMicrophoneFeature = true; - } else if (name == "android.hardware.wifi") { - specWiFiFeature = true; - } else if (name == "android.hardware.telephony") { - specTelephonyFeature = true; - } else if (req && (name == "android.hardware.telephony.gsm" || - name == "android.hardware.telephony.cdma")) { - // these have no corresponding permission to check for, - // but should imply the foundational telephony permission - reqTelephonySubFeature = true; - } else if (name == "android.hardware.screen.portrait") { - specScreenPortraitFeature = true; - } else if (name == "android.hardware.screen.landscape") { - specScreenLandscapeFeature = true; - } - printf("uses-feature%s:'%s'\n", - req ? "" : "-not-required", name.string()); - } else { - int vers = getIntegerAttribute(tree, - GL_ES_VERSION_ATTR, &error); - if (error == "") { - printf("uses-gl-es:'0x%x'\n", vers); - } - } - } else if (tag == "uses-permission") { - String8 name = getAttribute(tree, NAME_ATTR, &error); - if (name != "" && error == "") { - if (name == "android.permission.CAMERA") { - hasCameraPermission = true; - } else if (name == "android.permission.ACCESS_FINE_LOCATION") { - hasGpsPermission = true; - } else if (name == "android.permission.ACCESS_MOCK_LOCATION") { - hasMockLocPermission = true; - } else if (name == "android.permission.ACCESS_COARSE_LOCATION") { - hasCoarseLocPermission = true; - } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" || - name == "android.permission.INSTALL_LOCATION_PROVIDER") { - hasGeneralLocPermission = true; - } else if (name == "android.permission.BLUETOOTH" || - name == "android.permission.BLUETOOTH_ADMIN") { - hasBluetoothPermission = true; - } else if (name == "android.permission.RECORD_AUDIO") { - hasRecordAudioPermission = true; - } else if (name == "android.permission.ACCESS_WIFI_STATE" || - name == "android.permission.CHANGE_WIFI_STATE" || - name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") { - hasWiFiPermission = true; - } else if (name == "android.permission.CALL_PHONE" || - name == "android.permission.CALL_PRIVILEGED" || - name == "android.permission.MODIFY_PHONE_STATE" || - name == "android.permission.PROCESS_OUTGOING_CALLS" || - name == "android.permission.READ_SMS" || - name == "android.permission.RECEIVE_SMS" || - name == "android.permission.RECEIVE_MMS" || - name == "android.permission.RECEIVE_WAP_PUSH" || - name == "android.permission.SEND_SMS" || - name == "android.permission.WRITE_APN_SETTINGS" || - name == "android.permission.WRITE_SMS") { - hasTelephonyPermission = true; - } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") { - hasWriteExternalStoragePermission = true; - } else if (name == "android.permission.READ_EXTERNAL_STORAGE") { - hasReadExternalStoragePermission = true; - } else if (name == "android.permission.READ_PHONE_STATE") { - hasReadPhoneStatePermission = true; - } else if (name == "android.permission.READ_CONTACTS") { - hasReadContactsPermission = true; - } else if (name == "android.permission.WRITE_CONTACTS") { - hasWriteContactsPermission = true; - } else if (name == "android.permission.READ_CALL_LOG") { - hasReadCallLogPermission = true; - } else if (name == "android.permission.WRITE_CALL_LOG") { - hasWriteCallLogPermission = true; - } - printf("uses-permission:'%s'\n", name.string()); - int req = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1); - if (!req) { - printf("optional-permission:'%s'\n", name.string()); - } - } else { - fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", - error.string()); - goto bail; - } - } else if (tag == "uses-package") { - String8 name = getAttribute(tree, NAME_ATTR, &error); - if (name != "" && error == "") { - printf("uses-package:'%s'\n", name.string()); - } else { - fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", - error.string()); - goto bail; - } - } else if (tag == "original-package") { - String8 name = getAttribute(tree, NAME_ATTR, &error); - if (name != "" && error == "") { - printf("original-package:'%s'\n", name.string()); - } else { - fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", - error.string()); - goto bail; - } - } else if (tag == "supports-gl-texture") { - String8 name = getAttribute(tree, NAME_ATTR, &error); - if (name != "" && error == "") { - printf("supports-gl-texture:'%s'\n", name.string()); - } else { - fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", - error.string()); - goto bail; - } - } else if (tag == "compatible-screens") { - printCompatibleScreens(tree); - depth--; - } else if (tag == "package-verifier") { - String8 name = getAttribute(tree, NAME_ATTR, &error); - if (name != "" && error == "") { - String8 publicKey = getAttribute(tree, PUBLIC_KEY_ATTR, &error); - if (publicKey != "" && error == "") { - printf("package-verifier: name='%s' publicKey='%s'\n", - name.string(), publicKey.string()); - } - } - } - } else if (depth == 3 && withinApplication) { - withinActivity = false; - withinReceiver = false; - withinService = false; - hasIntentFilter = false; - if(tag == "activity") { - withinActivity = true; - activityName = getAttribute(tree, NAME_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string()); - goto bail; - } - - activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n", error.string()); - goto bail; - } - - activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string()); - goto bail; - } - - int32_t orien = getResolvedIntegerAttribute(&res, tree, - SCREEN_ORIENTATION_ATTR, &error); - if (error == "") { - if (orien == 0 || orien == 6 || orien == 8) { - // Requests landscape, sensorLandscape, or reverseLandscape. - reqScreenLandscapeFeature = true; - } else if (orien == 1 || orien == 7 || orien == 9) { - // Requests portrait, sensorPortrait, or reversePortrait. - reqScreenPortraitFeature = true; - } - } - } else if (tag == "uses-library") { - String8 libraryName = getAttribute(tree, NAME_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:name' attribute for uses-library: %s\n", error.string()); - goto bail; - } - int req = getIntegerAttribute(tree, - REQUIRED_ATTR, NULL, 1); - printf("uses-library%s:'%s'\n", - req ? "" : "-not-required", libraryName.string()); - } else if (tag == "receiver") { - withinReceiver = true; - receiverName = getAttribute(tree, NAME_ATTR, &error); - - if (error != "") { - fprintf(stderr, "ERROR getting 'android:name' attribute for " - "receiver:%s\n", error.string()); - goto bail; - } - } else if (tag == "service") { - withinService = true; - serviceName = getAttribute(tree, NAME_ATTR, &error); - - if (error != "") { - fprintf(stderr, "ERROR getting 'android:name' attribute for " - "service:%s\n", error.string()); - goto bail; - } - } else if (bundle->getIncludeMetaData() && tag == "meta-data") { - String8 metaDataName = getAttribute(tree, NAME_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:name' attribute for " - "meta-data:%s\n", error.string()); - goto bail; - } - printf("meta-data: name='%s' ", metaDataName.string()); - Res_value value; - getResolvedResourceAttribute(&value, &res, tree, VALUE_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:value' attribute for " - "meta-data:%s\n", error.string()); - goto bail; - } - if (value.dataType == Res_value::TYPE_STRING) { - String8 metaDataValue = getAttribute(tree, value.data, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:value' attribute for " - "meta-data: %s\n", error.string()); - goto bail; - } - printf("value='%s'\n", metaDataValue.string()); - } else if (Res_value::TYPE_FIRST_INT <= value.dataType && - value.dataType <= Res_value::TYPE_LAST_INT) { - printf("value='%d'\n", value.data); - } else { - printf("value=(type 0x%x)0x%x", (int)value.dataType, (int)value.data); - } - } - } else if ((depth == 4) && (tag == "intent-filter")) { - hasIntentFilter = true; - withinIntentFilter = true; - actMainActivity = actWidgetReceivers = actImeService = actWallpaperService = - false; - } else if ((depth == 5) && withinIntentFilter) { - String8 action; - if (tag == "action") { - action = getAttribute(tree, NAME_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", - error.string()); - goto bail; - } - if (withinActivity) { - if (action == "android.intent.action.MAIN") { - isMainActivity = true; - actMainActivity = true; - } - } else if (withinReceiver) { - if (action == "android.appwidget.action.APPWIDGET_UPDATE") { - actWidgetReceivers = true; - } - } else if (withinService) { - if (action == "android.view.InputMethod") { - actImeService = true; - } else if (action == "android.service.wallpaper.WallpaperService") { - actWallpaperService = true; - } - } - if (action == "android.intent.action.SEARCH") { - isSearchable = true; - } - } - - if (tag == "category") { - String8 category = getAttribute(tree, NAME_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'name' attribute: %s\n", error.string()); - goto bail; - } - if (withinActivity) { - if (category == "android.intent.category.LAUNCHER") { - isLauncherActivity = true; - } - } - } - } - } - - // Pre-1.6 implicitly granted permission compatibility logic - if (targetSdk < 4) { - if (!hasWriteExternalStoragePermission) { - printf("uses-permission:'android.permission.WRITE_EXTERNAL_STORAGE'\n"); - printf("uses-implied-permission:'android.permission.WRITE_EXTERNAL_STORAGE'," \ - "'targetSdkVersion < 4'\n"); - hasWriteExternalStoragePermission = true; - } - if (!hasReadPhoneStatePermission) { - printf("uses-permission:'android.permission.READ_PHONE_STATE'\n"); - printf("uses-implied-permission:'android.permission.READ_PHONE_STATE'," \ - "'targetSdkVersion < 4'\n"); - } - } - - // If the application has requested WRITE_EXTERNAL_STORAGE, we will - // force them to always take READ_EXTERNAL_STORAGE as well. We always - // do this (regardless of target API version) because we can't have - // an app with write permission but not read permission. - if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) { - printf("uses-permission:'android.permission.READ_EXTERNAL_STORAGE'\n"); - printf("uses-implied-permission:'android.permission.READ_EXTERNAL_STORAGE'," \ - "'requested WRITE_EXTERNAL_STORAGE'\n"); - } - - // Pre-JellyBean call log permission compatibility. - if (targetSdk < 16) { - if (!hasReadCallLogPermission && hasReadContactsPermission) { - printf("uses-permission:'android.permission.READ_CALL_LOG'\n"); - printf("uses-implied-permission:'android.permission.READ_CALL_LOG'," \ - "'targetSdkVersion < 16 and requested READ_CONTACTS'\n"); - } - if (!hasWriteCallLogPermission && hasWriteContactsPermission) { - printf("uses-permission:'android.permission.WRITE_CALL_LOG'\n"); - printf("uses-implied-permission:'android.permission.WRITE_CALL_LOG'," \ - "'targetSdkVersion < 16 and requested WRITE_CONTACTS'\n"); - } - } - - /* The following blocks handle printing "inferred" uses-features, based - * on whether related features or permissions are used by the app. - * Note that the various spec*Feature variables denote whether the - * relevant tag was *present* in the AndroidManfest, not that it was - * present and set to true. - */ - // Camera-related back-compatibility logic - if (!specCameraFeature) { - if (reqCameraFlashFeature) { - // if app requested a sub-feature (autofocus or flash) and didn't - // request the base camera feature, we infer that it meant to - printf("uses-feature:'android.hardware.camera'\n"); - printf("uses-implied-feature:'android.hardware.camera'," \ - "'requested android.hardware.camera.flash feature'\n"); - } else if (reqCameraAutofocusFeature) { - // if app requested a sub-feature (autofocus or flash) and didn't - // request the base camera feature, we infer that it meant to - printf("uses-feature:'android.hardware.camera'\n"); - printf("uses-implied-feature:'android.hardware.camera'," \ - "'requested android.hardware.camera.autofocus feature'\n"); - } else if (hasCameraPermission) { - // if app wants to use camera but didn't request the feature, we infer - // that it meant to, and further that it wants autofocus - // (which was the 1.0 - 1.5 behavior) - printf("uses-feature:'android.hardware.camera'\n"); - if (!specCameraAutofocusFeature) { - printf("uses-feature:'android.hardware.camera.autofocus'\n"); - printf("uses-implied-feature:'android.hardware.camera.autofocus'," \ - "'requested android.permission.CAMERA permission'\n"); - } - } - } - - // Location-related back-compatibility logic - if (!specLocationFeature && - (hasMockLocPermission || hasCoarseLocPermission || hasGpsPermission || - hasGeneralLocPermission || reqNetworkLocFeature || reqGpsFeature)) { - // if app either takes a location-related permission or requests one of the - // sub-features, we infer that it also meant to request the base location feature - printf("uses-feature:'android.hardware.location'\n"); - printf("uses-implied-feature:'android.hardware.location'," \ - "'requested a location access permission'\n"); - } - if (!specGpsFeature && hasGpsPermission) { - // if app takes GPS (FINE location) perm but does not request the GPS - // feature, we infer that it meant to - printf("uses-feature:'android.hardware.location.gps'\n"); - printf("uses-implied-feature:'android.hardware.location.gps'," \ - "'requested android.permission.ACCESS_FINE_LOCATION permission'\n"); - } - if (!specNetworkLocFeature && hasCoarseLocPermission) { - // if app takes Network location (COARSE location) perm but does not request the - // network location feature, we infer that it meant to - printf("uses-feature:'android.hardware.location.network'\n"); - printf("uses-implied-feature:'android.hardware.location.network'," \ - "'requested android.permission.ACCESS_COARSE_LOCATION permission'\n"); - } - - // Bluetooth-related compatibility logic - if (!specBluetoothFeature && hasBluetoothPermission && (targetSdk > 4)) { - // if app takes a Bluetooth permission but does not request the Bluetooth - // feature, we infer that it meant to - printf("uses-feature:'android.hardware.bluetooth'\n"); - printf("uses-implied-feature:'android.hardware.bluetooth'," \ - "'requested android.permission.BLUETOOTH or android.permission.BLUETOOTH_ADMIN " \ - "permission and targetSdkVersion > 4'\n"); - } - - // Microphone-related compatibility logic - if (!specMicrophoneFeature && hasRecordAudioPermission) { - // if app takes the record-audio permission but does not request the microphone - // feature, we infer that it meant to - printf("uses-feature:'android.hardware.microphone'\n"); - printf("uses-implied-feature:'android.hardware.microphone'," \ - "'requested android.permission.RECORD_AUDIO permission'\n"); - } - - // WiFi-related compatibility logic - if (!specWiFiFeature && hasWiFiPermission) { - // if app takes one of the WiFi permissions but does not request the WiFi - // feature, we infer that it meant to - printf("uses-feature:'android.hardware.wifi'\n"); - printf("uses-implied-feature:'android.hardware.wifi'," \ - "'requested android.permission.ACCESS_WIFI_STATE, " \ - "android.permission.CHANGE_WIFI_STATE, or " \ - "android.permission.CHANGE_WIFI_MULTICAST_STATE permission'\n"); - } - - // Telephony-related compatibility logic - if (!specTelephonyFeature && (hasTelephonyPermission || reqTelephonySubFeature)) { - // if app takes one of the telephony permissions or requests a sub-feature but - // does not request the base telephony feature, we infer that it meant to - printf("uses-feature:'android.hardware.telephony'\n"); - printf("uses-implied-feature:'android.hardware.telephony'," \ - "'requested a telephony-related permission or feature'\n"); - } - - // Touchscreen-related back-compatibility logic - if (!specTouchscreenFeature) { // not a typo! - // all apps are presumed to require a touchscreen, unless they explicitly say - // <uses-feature android:name="android.hardware.touchscreen" android:required="false"/> - // Note that specTouchscreenFeature is true if the tag is present, regardless - // of whether its value is true or false, so this is safe - printf("uses-feature:'android.hardware.touchscreen'\n"); - printf("uses-implied-feature:'android.hardware.touchscreen'," \ - "'assumed you require a touch screen unless explicitly made optional'\n"); - } - if (!specMultitouchFeature && reqDistinctMultitouchFeature) { - // if app takes one of the telephony permissions or requests a sub-feature but - // does not request the base telephony feature, we infer that it meant to - printf("uses-feature:'android.hardware.touchscreen.multitouch'\n"); - printf("uses-implied-feature:'android.hardware.touchscreen.multitouch'," \ - "'requested android.hardware.touchscreen.multitouch.distinct feature'\n"); - } - - // Landscape/portrait-related compatibility logic - if (!specScreenLandscapeFeature && !specScreenPortraitFeature) { - // If the app has specified any activities in its manifest - // that request a specific orientation, then assume that - // orientation is required. - if (reqScreenLandscapeFeature) { - printf("uses-feature:'android.hardware.screen.landscape'\n"); - printf("uses-implied-feature:'android.hardware.screen.landscape'," \ - "'one or more activities have specified a landscape orientation'\n"); - } - if (reqScreenPortraitFeature) { - printf("uses-feature:'android.hardware.screen.portrait'\n"); - printf("uses-implied-feature:'android.hardware.screen.portrait'," \ - "'one or more activities have specified a portrait orientation'\n"); - } - } - - if (hasMainActivity) { - printf("main\n"); - } - if (hasWidgetReceivers) { - printf("app-widget\n"); - } - if (hasImeService) { - printf("ime\n"); - } - if (hasWallpaperService) { - printf("wallpaper\n"); - } - if (hasOtherActivities) { - printf("other-activities\n"); - } - if (isSearchable) { - printf("search\n"); - } - if (hasOtherReceivers) { - printf("other-receivers\n"); - } - if (hasOtherServices) { - printf("other-services\n"); - } - - // For modern apps, if screen size buckets haven't been specified - // but the new width ranges have, then infer the buckets from them. - if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0 - && requiresSmallestWidthDp > 0) { - int compatWidth = compatibleWidthLimitDp; - if (compatWidth <= 0) { - compatWidth = requiresSmallestWidthDp; - } - if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) { - smallScreen = -1; - } else { - smallScreen = 0; - } - if (requiresSmallestWidthDp <= 320 && compatWidth >= 320) { - normalScreen = -1; - } else { - normalScreen = 0; - } - if (requiresSmallestWidthDp <= 480 && compatWidth >= 480) { - largeScreen = -1; - } else { - largeScreen = 0; - } - if (requiresSmallestWidthDp <= 720 && compatWidth >= 720) { - xlargeScreen = -1; - } else { - xlargeScreen = 0; - } - } - - // Determine default values for any unspecified screen sizes, - // based on the target SDK of the package. As of 4 (donut) - // the screen size support was introduced, so all default to - // enabled. - if (smallScreen > 0) { - smallScreen = targetSdk >= 4 ? -1 : 0; - } - if (normalScreen > 0) { - normalScreen = -1; - } - if (largeScreen > 0) { - largeScreen = targetSdk >= 4 ? -1 : 0; - } - if (xlargeScreen > 0) { - // Introduced in Gingerbread. - xlargeScreen = targetSdk >= 9 ? -1 : 0; - } - if (anyDensity > 0) { - anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0 - || compatibleWidthLimitDp > 0) ? -1 : 0; - } - printf("supports-screens:"); - if (smallScreen != 0) { - printf(" 'small'"); - } - if (normalScreen != 0) { - printf(" 'normal'"); - } - if (largeScreen != 0) { - printf(" 'large'"); - } - if (xlargeScreen != 0) { - printf(" 'xlarge'"); - } - printf("\n"); - printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false"); - if (requiresSmallestWidthDp > 0) { - printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp); - } - if (compatibleWidthLimitDp > 0) { - printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp); - } - if (largestWidthLimitDp > 0) { - printf("largest-width-limit:'%d'\n", largestWidthLimitDp); - } - - printf("locales:"); - const size_t NL = locales.size(); - for (size_t i=0; i<NL; i++) { - const char* localeStr = locales[i].string(); - if (localeStr == NULL || strlen(localeStr) == 0) { - localeStr = "--_--"; - } - printf(" '%s'", localeStr); - } - printf("\n"); - - printf("densities:"); - const size_t ND = densities.size(); - for (size_t i=0; i<ND; i++) { - printf(" '%d'", densities[i]); - } - printf("\n"); - - AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib"); - if (dir != NULL) { - if (dir->getFileCount() > 0) { - printf("native-code:"); - for (size_t i=0; i<dir->getFileCount(); i++) { - printf(" '%s'", dir->getFileName(i).string()); - } - printf("\n"); - } - delete dir; - } - } else if (strcmp("badger", option) == 0) { - printf("%s", CONSOLE_DATA); - } else if (strcmp("configurations", option) == 0) { - Vector<ResTable_config> configs; - res.getConfigurations(&configs); - const size_t N = configs.size(); - for (size_t i=0; i<N; i++) { - printf("%s\n", configs[i].toString().string()); - } - } else { - fprintf(stderr, "ERROR: unknown dump option '%s'\n", option); - goto bail; - } - } - - result = NO_ERROR; - -bail: - if (asset) { - delete asset; - } - return (result != NO_ERROR); -} - - -/* - * Handle the "add" command, which wants to add files to a new or - * pre-existing archive. - */ -int doAdd(Bundle* bundle) -{ - ZipFile* zip = NULL; - status_t result = UNKNOWN_ERROR; - const char* zipFileName; - - if (bundle->getUpdate()) { - /* avoid confusion */ - fprintf(stderr, "ERROR: can't use '-u' with add\n"); - goto bail; - } - - if (bundle->getFileSpecCount() < 1) { - fprintf(stderr, "ERROR: must specify zip file name\n"); - goto bail; - } - zipFileName = bundle->getFileSpecEntry(0); - - if (bundle->getFileSpecCount() < 2) { - fprintf(stderr, "NOTE: nothing to do\n"); - goto bail; - } - - zip = openReadWrite(zipFileName, true); - if (zip == NULL) { - fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName); - goto bail; - } - - for (int i = 1; i < bundle->getFileSpecCount(); i++) { - const char* fileName = bundle->getFileSpecEntry(i); - - if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) { - printf(" '%s'... (from gzip)\n", fileName); - result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL); - } else { - if (bundle->getJunkPath()) { - String8 storageName = String8(fileName).getPathLeaf(); - printf(" '%s' as '%s'...\n", fileName, storageName.string()); - result = zip->add(fileName, storageName.string(), - bundle->getCompressionMethod(), NULL); - } else { - printf(" '%s'...\n", fileName); - result = zip->add(fileName, bundle->getCompressionMethod(), NULL); - } - } - if (result != NO_ERROR) { - fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName); - if (result == NAME_NOT_FOUND) { - fprintf(stderr, ": file not found\n"); - } else if (result == ALREADY_EXISTS) { - fprintf(stderr, ": already exists in archive\n"); - } else { - fprintf(stderr, "\n"); - } - goto bail; - } - } - - result = NO_ERROR; - -bail: - delete zip; - return (result != NO_ERROR); -} - - -/* - * Delete files from an existing archive. - */ -int doRemove(Bundle* bundle) -{ - ZipFile* zip = NULL; - status_t result = UNKNOWN_ERROR; - const char* zipFileName; - - if (bundle->getFileSpecCount() < 1) { - fprintf(stderr, "ERROR: must specify zip file name\n"); - goto bail; - } - zipFileName = bundle->getFileSpecEntry(0); - - if (bundle->getFileSpecCount() < 2) { - fprintf(stderr, "NOTE: nothing to do\n"); - goto bail; - } - - zip = openReadWrite(zipFileName, false); - if (zip == NULL) { - fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n", - zipFileName); - goto bail; - } - - for (int i = 1; i < bundle->getFileSpecCount(); i++) { - const char* fileName = bundle->getFileSpecEntry(i); - ZipEntry* entry; - - entry = zip->getEntryByName(fileName); - if (entry == NULL) { - printf(" '%s' NOT FOUND\n", fileName); - continue; - } - - result = zip->remove(entry); - - if (result != NO_ERROR) { - fprintf(stderr, "Unable to delete '%s' from '%s'\n", - bundle->getFileSpecEntry(i), zipFileName); - goto bail; - } - } - - /* update the archive */ - zip->flush(); - -bail: - delete zip; - return (result != NO_ERROR); -} - - -/* - * Package up an asset directory and associated application files. - */ -int doPackage(Bundle* bundle) -{ - const char* outputAPKFile; - int retVal = 1; - status_t err; - sp<AaptAssets> assets; - int N; - FILE* fp; - String8 dependencyFile; - - // -c zz_ZZ means do pseudolocalization - ResourceFilter filter; - err = filter.parse(bundle->getConfigurations()); - if (err != NO_ERROR) { - goto bail; - } - if (filter.containsPseudo()) { - bundle->setPseudolocalize(true); - } - - N = bundle->getFileSpecCount(); - if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0 - && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDir() == NULL) { - fprintf(stderr, "ERROR: no input files\n"); - goto bail; - } - - outputAPKFile = bundle->getOutputAPKFile(); - - // Make sure the filenames provided exist and are of the appropriate type. - if (outputAPKFile) { - FileType type; - type = getFileType(outputAPKFile); - if (type != kFileTypeNonexistent && type != kFileTypeRegular) { - fprintf(stderr, - "ERROR: output file '%s' exists but is not regular file\n", - outputAPKFile); - goto bail; - } - } - - // Load the assets. - assets = new AaptAssets(); - - // Set up the resource gathering in assets if we're going to generate - // dependency files. Every time we encounter a resource while slurping - // the tree, we'll add it to these stores so we have full resource paths - // to write to a dependency file. - if (bundle->getGenDependencies()) { - sp<FilePathStore> resPathStore = new FilePathStore; - assets->setFullResPaths(resPathStore); - sp<FilePathStore> assetPathStore = new FilePathStore; - assets->setFullAssetPaths(assetPathStore); - } - - err = assets->slurpFromArgs(bundle); - if (err < 0) { - goto bail; - } - - if (bundle->getVerbose()) { - assets->print(String8()); - } - - // If they asked for any fileAs that need to be compiled, do so. - if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) { - err = buildResources(bundle, assets); - if (err != 0) { - goto bail; - } - } - - // At this point we've read everything and processed everything. From here - // on out it's just writing output files. - if (SourcePos::hasErrors()) { - goto bail; - } - - // Update symbols with information about which ones are needed as Java symbols. - assets->applyJavaSymbols(); - if (SourcePos::hasErrors()) { - goto bail; - } - - // If we've been asked to generate a dependency file, do that here - if (bundle->getGenDependencies()) { - // If this is the packaging step, generate the dependency file next to - // the output apk (e.g. bin/resources.ap_.d) - if (outputAPKFile) { - dependencyFile = String8(outputAPKFile); - // Add the .d extension to the dependency file. - dependencyFile.append(".d"); - } else { - // Else if this is the R.java dependency generation step, - // generate the dependency file in the R.java package subdirectory - // e.g. gen/com/foo/app/R.java.d - dependencyFile = String8(bundle->getRClassDir()); - dependencyFile.appendPath("R.java.d"); - } - // Make sure we have a clean dependency file to start with - fp = fopen(dependencyFile, "w"); - fclose(fp); - } - - // Write out R.java constants - if (!assets->havePrivateSymbols()) { - if (bundle->getCustomPackage() == NULL) { - // Write the R.java file into the appropriate class directory - // e.g. gen/com/foo/app/R.java - err = writeResourceSymbols(bundle, assets, assets->getPackage(), true); - } else { - const String8 customPkg(bundle->getCustomPackage()); - err = writeResourceSymbols(bundle, assets, customPkg, true); - } - if (err < 0) { - goto bail; - } - // If we have library files, we're going to write our R.java file into - // the appropriate class directory for those libraries as well. - // e.g. gen/com/foo/app/lib/R.java - if (bundle->getExtraPackages() != NULL) { - // Split on colon - String8 libs(bundle->getExtraPackages()); - char* packageString = strtok(libs.lockBuffer(libs.length()), ":"); - while (packageString != NULL) { - // Write the R.java file out with the correct package name - err = writeResourceSymbols(bundle, assets, String8(packageString), true); - if (err < 0) { - goto bail; - } - packageString = strtok(NULL, ":"); - } - libs.unlockBuffer(); - } - } else { - err = writeResourceSymbols(bundle, assets, assets->getPackage(), false); - if (err < 0) { - goto bail; - } - err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true); - if (err < 0) { - goto bail; - } - } - - // Write out the ProGuard file - err = writeProguardFile(bundle, assets); - if (err < 0) { - goto bail; - } - - // Write the apk - if (outputAPKFile) { - err = writeAPK(bundle, assets, String8(outputAPKFile)); - if (err != NO_ERROR) { - fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputAPKFile); - goto bail; - } - } - - // If we've been asked to generate a dependency file, we need to finish up here. - // the writeResourceSymbols and writeAPK functions have already written the target - // half of the dependency file, now we need to write the prerequisites. (files that - // the R.java file or .ap_ file depend on) - if (bundle->getGenDependencies()) { - // Now that writeResourceSymbols or writeAPK has taken care of writing - // the targets to our dependency file, we'll write the prereqs - fp = fopen(dependencyFile, "a+"); - fprintf(fp, " : "); - bool includeRaw = (outputAPKFile != NULL); - err = writeDependencyPreReqs(bundle, assets, fp, includeRaw); - // Also manually add the AndroidManifeset since it's not under res/ or assets/ - // and therefore was not added to our pathstores during slurping - fprintf(fp, "%s \\\n", bundle->getAndroidManifestFile()); - fclose(fp); - } - - retVal = 0; -bail: - if (SourcePos::hasErrors()) { - SourcePos::printErrors(stderr); - } - return retVal; -} - -/* - * Do PNG Crunching - * PRECONDITIONS - * -S flag points to a source directory containing drawable* folders - * -C flag points to destination directory. The folder structure in the - * source directory will be mirrored to the destination (cache) directory - * - * POSTCONDITIONS - * Destination directory will be updated to match the PNG files in - * the source directory. - */ -int doCrunch(Bundle* bundle) -{ - fprintf(stdout, "Crunching PNG Files in "); - fprintf(stdout, "source dir: %s\n", bundle->getResourceSourceDirs()[0]); - fprintf(stdout, "To destination dir: %s\n", bundle->getCrunchedOutputDir()); - - updatePreProcessedCache(bundle); - - return NO_ERROR; -} - -/* - * Do PNG Crunching on a single flag - * -i points to a single png file - * -o points to a single png output file - */ -int doSingleCrunch(Bundle* bundle) -{ - fprintf(stdout, "Crunching single PNG file: %s\n", bundle->getSingleCrunchInputFile()); - fprintf(stdout, "\tOutput file: %s\n", bundle->getSingleCrunchOutputFile()); - - String8 input(bundle->getSingleCrunchInputFile()); - String8 output(bundle->getSingleCrunchOutputFile()); - - if (preProcessImageToCache(bundle, input, output) != NO_ERROR) { - // we can't return the status_t as it gets truncate to the lower 8 bits. - return 42; - } - - return NO_ERROR; -} - -char CONSOLE_DATA[2925] = { - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63, - 86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83, - 62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81, - 81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59, - 59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, - 59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87, - 58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, - 47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58, - 121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81, - 81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59, - 59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59, - 59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81, - 70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81, - 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109, - 81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, - 32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59, - 59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59, - 60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59, - 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46, - 61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32, - 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81, - 109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81, - 67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58, - 61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37, - 73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59, - 59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, - 32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96, - 46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, - 97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32, - 46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61, - 119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32, - 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119, - 119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81, - 81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41, - 87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, - 45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, - 59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, - 59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59, - 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59, - 61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, - 59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59, - 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33, - 58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, - 61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95, - 32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59, - 61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45, - 59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59, - 59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61, - 46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, - 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59, - 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32, - 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61, - 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, - 59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10 - }; diff --git a/tools/aapt/CrunchCache.cpp b/tools/aapt/CrunchCache.cpp deleted file mode 100644 index c4cf6bc..0000000 --- a/tools/aapt/CrunchCache.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// -// Copyright 2011 The Android Open Source Project -// -// Implementation file for CrunchCache -// This file defines functions laid out and documented in -// CrunchCache.h - -#include <utils/Vector.h> -#include <utils/String8.h> - -#include "DirectoryWalker.h" -#include "FileFinder.h" -#include "CacheUpdater.h" -#include "CrunchCache.h" - -using namespace android; - -CrunchCache::CrunchCache(String8 sourcePath, String8 destPath, FileFinder* ff) - : mSourcePath(sourcePath), mDestPath(destPath), mSourceFiles(0), mDestFiles(0), mFileFinder(ff) -{ - // We initialize the default value to return to 0 so if a file doesn't exist - // then all files are automatically "newer" than it. - - // Set file extensions to look for. Right now just pngs. - mExtensions.push(String8(".png")); - - // Load files into our data members - loadFiles(); -} - -size_t CrunchCache::crunch(CacheUpdater* cu, bool forceOverwrite) -{ - size_t numFilesUpdated = 0; - - // Iterate through the source files and compare to cache. - // After processing a file, remove it from the source files and - // from the dest files. - // We're done when we're out of files in source. - String8 relativePath; - while (mSourceFiles.size() > 0) { - // Get the full path to the source file, then convert to a c-string - // and offset our beginning pointer to the length of the sourcePath - // This efficiently strips the source directory prefix from our path. - // Also, String8 doesn't have a substring method so this is what we've - // got to work with. - const char* rPathPtr = mSourceFiles.keyAt(0).string()+mSourcePath.length(); - // Strip leading slash if present - int offset = 0; - if (rPathPtr[0] == OS_PATH_SEPARATOR) - offset = 1; - relativePath = String8(rPathPtr + offset); - - if (forceOverwrite || needsUpdating(relativePath)) { - cu->processImage(mSourcePath.appendPathCopy(relativePath), - mDestPath.appendPathCopy(relativePath)); - numFilesUpdated++; - // crunchFile(relativePath); - } - // Delete this file from the source files and (if it exists) from the - // dest files. - mSourceFiles.removeItemsAt(0); - mDestFiles.removeItem(mDestPath.appendPathCopy(relativePath)); - } - - // Iterate through what's left of destFiles and delete leftovers - while (mDestFiles.size() > 0) { - cu->deleteFile(mDestFiles.keyAt(0)); - mDestFiles.removeItemsAt(0); - } - - // Update our knowledge of the files cache - // both source and dest should be empty by now. - loadFiles(); - - return numFilesUpdated; -} - -void CrunchCache::loadFiles() -{ - // Clear out our data structures to avoid putting in duplicates - mSourceFiles.clear(); - mDestFiles.clear(); - - // Make a directory walker that points to the system. - DirectoryWalker* dw = new SystemDirectoryWalker(); - - // Load files in the source directory - mFileFinder->findFiles(mSourcePath, mExtensions, mSourceFiles,dw); - - // Load files in the destination directory - mFileFinder->findFiles(mDestPath,mExtensions,mDestFiles,dw); - - delete dw; -} - -bool CrunchCache::needsUpdating(String8 relativePath) const -{ - // Retrieve modification dates for this file entry under the source and - // cache directory trees. The vectors will return a modification date of 0 - // if the file doesn't exist. - time_t sourceDate = mSourceFiles.valueFor(mSourcePath.appendPathCopy(relativePath)); - time_t destDate = mDestFiles.valueFor(mDestPath.appendPathCopy(relativePath)); - return sourceDate > destDate; -}
\ No newline at end of file diff --git a/tools/aapt/CrunchCache.h b/tools/aapt/CrunchCache.h deleted file mode 100644 index be3da5c..0000000 --- a/tools/aapt/CrunchCache.h +++ /dev/null @@ -1,102 +0,0 @@ -// -// Copyright 2011 The Android Open Source Project -// -// Cache manager for pre-processed PNG files. -// Contains code for managing which PNG files get processed -// at build time. -// - -#ifndef CRUNCHCACHE_H -#define CRUNCHCACHE_H - -#include <utils/KeyedVector.h> -#include <utils/String8.h> -#include "FileFinder.h" -#include "CacheUpdater.h" - -using namespace android; - -/** CrunchCache - * This class is a cache manager which can pre-process PNG files and store - * them in a mirror-cache. It's capable of doing incremental updates to its - * cache. - * - * Usage: - * Create an instance initialized with the root of the source tree, the - * root location to store the cache files, and an instance of a file finder. - * Then update the cache by calling crunch. - */ -class CrunchCache { -public: - // Constructor - CrunchCache(String8 sourcePath, String8 destPath, FileFinder* ff); - - // Nobody should be calling the default constructor - // So this space is intentionally left blank - - // Default Copy Constructor and Destructor are fine - - /** crunch is the workhorse of this class. - * It goes through all the files found in the sourcePath and compares - * them to the cached versions in the destPath. If the optional - * argument forceOverwrite is set to true, then all source files are - * re-crunched even if they have not been modified recently. Otherwise, - * source files are only crunched when they needUpdating. Afterwards, - * we delete any leftover files in the cache that are no longer present - * in source. - * - * PRECONDITIONS: - * No setup besides construction is needed - * POSTCONDITIONS: - * The cache is updated to fully reflect all changes in source. - * The function then returns the number of files changed in cache - * (counting deletions). - */ - size_t crunch(CacheUpdater* cu, bool forceOverwrite=false); - -private: - /** loadFiles is a wrapper to the FileFinder that places matching - * files into mSourceFiles and mDestFiles. - * - * POSTCONDITIONS - * mDestFiles and mSourceFiles are refreshed to reflect the current - * state of the files in the source and dest directories. - * Any previous contents of mSourceFiles and mDestFiles are cleared. - */ - void loadFiles(); - - /** needsUpdating takes a file path - * and returns true if the file represented by this path is newer in the - * sourceFiles than in the cache (mDestFiles). - * - * PRECONDITIONS: - * mSourceFiles and mDestFiles must be initialized and filled. - * POSTCONDITIONS: - * returns true if and only if source file's modification time - * is greater than the cached file's mod-time. Otherwise returns false. - * - * USAGE: - * Should be used something like the following: - * if (needsUpdating(filePath)) - * // Recrunch sourceFile out to destFile. - * - */ - bool needsUpdating(String8 relativePath) const; - - // DATA MEMBERS ==================================================== - - String8 mSourcePath; - String8 mDestPath; - - Vector<String8> mExtensions; - - // Each vector of paths contains one entry per PNG file encountered. - // Each entry consists of a path pointing to that PNG. - DefaultKeyedVector<String8,time_t> mSourceFiles; - DefaultKeyedVector<String8,time_t> mDestFiles; - - // Pointer to a FileFinder to use - FileFinder* mFileFinder; -}; - -#endif // CRUNCHCACHE_H diff --git a/tools/aapt/DirectoryWalker.h b/tools/aapt/DirectoryWalker.h deleted file mode 100644 index 88031d0..0000000 --- a/tools/aapt/DirectoryWalker.h +++ /dev/null @@ -1,98 +0,0 @@ -// -// Copyright 2011 The Android Open Source Project -// -// Defines an abstraction for opening a directory on the filesystem and -// iterating through it. - -#ifndef DIRECTORYWALKER_H -#define DIRECTORYWALKER_H - -#include <dirent.h> -#include <sys/types.h> -#include <sys/param.h> -#include <sys/stat.h> -#include <unistd.h> -#include <utils/String8.h> - -#include <stdio.h> - -using namespace android; - -// Directory Walker -// This is an abstraction for walking through a directory and getting files -// and descriptions. - -class DirectoryWalker { -public: - virtual ~DirectoryWalker() {}; - virtual bool openDir(String8 path) = 0; - virtual bool openDir(const char* path) = 0; - // Advance to next directory entry - virtual struct dirent* nextEntry() = 0; - // Get the stats for the current entry - virtual struct stat* entryStats() = 0; - // Clean Up - virtual void closeDir() = 0; - // This class is able to replicate itself on the heap - virtual DirectoryWalker* clone() = 0; - - // DATA MEMBERS - // Current directory entry - struct dirent mEntry; - // Stats for that directory entry - struct stat mStats; - // Base path - String8 mBasePath; -}; - -// System Directory Walker -// This is an implementation of the above abstraction that calls -// real system calls and is fully functional. -// functions are inlined since they're very short and simple - -class SystemDirectoryWalker : public DirectoryWalker { - - // Default constructor, copy constructor, and destructor are fine -public: - virtual bool openDir(String8 path) { - mBasePath = path; - dir = NULL; - dir = opendir(mBasePath.string() ); - - if (dir == NULL) - return false; - - return true; - }; - virtual bool openDir(const char* path) { - String8 p(path); - openDir(p); - return true; - }; - // Advance to next directory entry - virtual struct dirent* nextEntry() { - struct dirent* entryPtr = readdir(dir); - if (entryPtr == NULL) - return NULL; - - mEntry = *entryPtr; - // Get stats - String8 fullPath = mBasePath.appendPathCopy(mEntry.d_name); - stat(fullPath.string(),&mStats); - return &mEntry; - }; - // Get the stats for the current entry - virtual struct stat* entryStats() { - return &mStats; - }; - virtual void closeDir() { - closedir(dir); - }; - virtual DirectoryWalker* clone() { - return new SystemDirectoryWalker(*this); - }; -private: - DIR* dir; -}; - -#endif // DIRECTORYWALKER_H diff --git a/tools/aapt/FileFinder.cpp b/tools/aapt/FileFinder.cpp deleted file mode 100644 index 18775c0..0000000 --- a/tools/aapt/FileFinder.cpp +++ /dev/null @@ -1,98 +0,0 @@ -// -// Copyright 2011 The Android Open Source Project -// - -// File Finder implementation. -// Implementation for the functions declared and documented in FileFinder.h - -#include <utils/Vector.h> -#include <utils/String8.h> -#include <utils/KeyedVector.h> - -#include <dirent.h> -#include <sys/stat.h> - -#include "DirectoryWalker.h" -#include "FileFinder.h" - -//#define DEBUG - -using android::String8; - -// Private function to check whether a file is a directory or not -bool isDirectory(const char* filename) { - struct stat fileStat; - if (stat(filename, &fileStat) == -1) { - return false; - } - return(S_ISDIR(fileStat.st_mode)); -} - - -// Private function to check whether a file is a regular file or not -bool isFile(const char* filename) { - struct stat fileStat; - if (stat(filename, &fileStat) == -1) { - return false; - } - return(S_ISREG(fileStat.st_mode)); -} - -bool SystemFileFinder::findFiles(String8 basePath, Vector<String8>& extensions, - KeyedVector<String8,time_t>& fileStore, - DirectoryWalker* dw) -{ - // Scan the directory pointed to by basePath - // check files and recurse into subdirectories. - if (!dw->openDir(basePath)) { - return false; - } - /* - * Go through all directory entries. Check each file using checkAndAddFile - * and recurse into sub-directories. - */ - struct dirent* entry; - while ((entry = dw->nextEntry()) != NULL) { - String8 entryName(entry->d_name); - if (entry->d_name[0] == '.') // Skip hidden files and directories - continue; - - String8 fullPath = basePath.appendPathCopy(entryName); - // If this entry is a directory we'll recurse into it - if (isDirectory(fullPath.string()) ) { - DirectoryWalker* copy = dw->clone(); - findFiles(fullPath, extensions, fileStore,copy); - delete copy; - } - - // If this entry is a file, we'll pass it over to checkAndAddFile - if (isFile(fullPath.string()) ) { - checkAndAddFile(fullPath,dw->entryStats(),extensions,fileStore); - } - } - - // Clean up - dw->closeDir(); - - return true; -} - -void SystemFileFinder::checkAndAddFile(String8 path, const struct stat* stats, - Vector<String8>& extensions, - KeyedVector<String8,time_t>& fileStore) -{ - // Loop over the extensions, checking for a match - bool done = false; - String8 ext(path.getPathExtension()); - ext.toLower(); - for (size_t i = 0; i < extensions.size() && !done; ++i) { - String8 ext2 = extensions[i].getPathExtension(); - ext2.toLower(); - // Compare the extensions. If a match is found, add to storage. - if (ext == ext2) { - done = true; - fileStore.add(path,stats->st_mtime); - } - } -} - diff --git a/tools/aapt/FileFinder.h b/tools/aapt/FileFinder.h deleted file mode 100644 index 6974aee..0000000 --- a/tools/aapt/FileFinder.h +++ /dev/null @@ -1,80 +0,0 @@ -// -// Copyright 2011 The Android Open Source Project -// - -// File Finder. -// This is a collection of useful functions for finding paths and modification -// times of files that match an extension pattern in a directory tree. -// and finding files in it. - -#ifndef FILEFINDER_H -#define FILEFINDER_H - -#include <utils/Vector.h> -#include <utils/KeyedVector.h> -#include <utils/String8.h> - -#include "DirectoryWalker.h" - -using namespace android; - -// Abstraction to allow for dependency injection. See MockFileFinder.h -// for the testing implementation. -class FileFinder { -public: - virtual bool findFiles(String8 basePath, Vector<String8>& extensions, - KeyedVector<String8,time_t>& fileStore, - DirectoryWalker* dw) = 0; - - virtual ~FileFinder() {}; -}; - -class SystemFileFinder : public FileFinder { -public: - - /* findFiles takes a path, a Vector of extensions, and a destination KeyedVector - * and places path/modification date key/values pointing to - * all files with matching extensions found into the KeyedVector - * PRECONDITIONS - * path is a valid system path - * extensions should include leading "." - * This is not necessary, but the comparison directly - * compares the end of the path string so if the "." - * is excluded there is a small chance you could have - * a false positive match. (For example: extension "png" - * would match a file called "blahblahpng") - * - * POSTCONDITIONS - * fileStore contains (in no guaranteed order) paths to all - * matching files encountered in subdirectories of path - * as keys in the KeyedVector. Each key has the modification time - * of the file as its value. - * - * Calls checkAndAddFile on each file encountered in the directory tree - * Recursively descends into subdirectories. - */ - virtual bool findFiles(String8 basePath, Vector<String8>& extensions, - KeyedVector<String8,time_t>& fileStore, - DirectoryWalker* dw); - -private: - /** - * checkAndAddFile looks at a single file path and stat combo - * to determine whether it is a matching file (by looking at - * the extension) - * - * PRECONDITIONS - * no setup is needed - * - * POSTCONDITIONS - * If the given file has a matching extension then a new entry - * is added to the KeyedVector with the path as the key and the modification - * time as the value. - * - */ - static void checkAndAddFile(String8 path, const struct stat* stats, - Vector<String8>& extensions, - KeyedVector<String8,time_t>& fileStore); - -}; -#endif // FILEFINDER_H diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp deleted file mode 100644 index b2cbf49..0000000 --- a/tools/aapt/Images.cpp +++ /dev/null @@ -1,1387 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Build resource files from raw assets. -// - -#define PNG_INTERNAL - -#include "Images.h" - -#include <androidfw/ResourceTypes.h> -#include <utils/ByteOrder.h> - -#include <png.h> -#include <zlib.h> - -#define NOISY(x) //x - -static void -png_write_aapt_file(png_structp png_ptr, png_bytep data, png_size_t length) -{ - AaptFile* aaptfile = (AaptFile*) png_get_io_ptr(png_ptr); - status_t err = aaptfile->writeData(data, length); - if (err != NO_ERROR) { - png_error(png_ptr, "Write Error"); - } -} - - -static void -png_flush_aapt_file(png_structp png_ptr) -{ -} - -// This holds an image as 8bpp RGBA. -struct image_info -{ - image_info() : rows(NULL), is9Patch(false), allocRows(NULL) { } - ~image_info() { - if (rows && rows != allocRows) { - free(rows); - } - if (allocRows) { - for (int i=0; i<(int)allocHeight; i++) { - free(allocRows[i]); - } - free(allocRows); - } - free(info9Patch.xDivs); - free(info9Patch.yDivs); - free(info9Patch.colors); - } - - png_uint_32 width; - png_uint_32 height; - png_bytepp rows; - - // 9-patch info. - bool is9Patch; - Res_png_9patch info9Patch; - - // Layout padding, if relevant - bool haveLayoutBounds; - int32_t layoutBoundsLeft; - int32_t layoutBoundsTop; - int32_t layoutBoundsRight; - int32_t layoutBoundsBottom; - - png_uint_32 allocHeight; - png_bytepp allocRows; -}; - -static void read_png(const char* imageName, - png_structp read_ptr, png_infop read_info, - image_info* outImageInfo) -{ - int color_type; - int bit_depth, interlace_type, compression_type; - int i; - - png_read_info(read_ptr, read_info); - - png_get_IHDR(read_ptr, read_info, &outImageInfo->width, - &outImageInfo->height, &bit_depth, &color_type, - &interlace_type, &compression_type, NULL); - - //printf("Image %s:\n", imageName); - //printf("color_type=%d, bit_depth=%d, interlace_type=%d, compression_type=%d\n", - // color_type, bit_depth, interlace_type, compression_type); - - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_palette_to_rgb(read_ptr); - - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) - png_set_expand_gray_1_2_4_to_8(read_ptr); - - if (png_get_valid(read_ptr, read_info, PNG_INFO_tRNS)) { - //printf("Has PNG_INFO_tRNS!\n"); - png_set_tRNS_to_alpha(read_ptr); - } - - if (bit_depth == 16) - png_set_strip_16(read_ptr); - - if ((color_type&PNG_COLOR_MASK_ALPHA) == 0) - png_set_add_alpha(read_ptr, 0xFF, PNG_FILLER_AFTER); - - if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(read_ptr); - - png_read_update_info(read_ptr, read_info); - - outImageInfo->rows = (png_bytepp)malloc( - outImageInfo->height * sizeof(png_bytep)); - outImageInfo->allocHeight = outImageInfo->height; - outImageInfo->allocRows = outImageInfo->rows; - - png_set_rows(read_ptr, read_info, outImageInfo->rows); - - for (i = 0; i < (int)outImageInfo->height; i++) - { - outImageInfo->rows[i] = (png_bytep) - malloc(png_get_rowbytes(read_ptr, read_info)); - } - - png_read_image(read_ptr, outImageInfo->rows); - - png_read_end(read_ptr, read_info); - - NOISY(printf("Image %s: w=%d, h=%d, d=%d, colors=%d, inter=%d, comp=%d\n", - imageName, - (int)outImageInfo->width, (int)outImageInfo->height, - bit_depth, color_type, - interlace_type, compression_type)); - - png_get_IHDR(read_ptr, read_info, &outImageInfo->width, - &outImageInfo->height, &bit_depth, &color_type, - &interlace_type, &compression_type, NULL); -} - -#define COLOR_TRANSPARENT 0 -#define COLOR_WHITE 0xFFFFFFFF -#define COLOR_TICK 0xFF000000 -#define COLOR_LAYOUT_BOUNDS_TICK 0xFF0000FF - -enum { - TICK_TYPE_NONE, - TICK_TYPE_TICK, - TICK_TYPE_LAYOUT_BOUNDS, - TICK_TYPE_BOTH -}; - -static int tick_type(png_bytep p, bool transparent, const char** outError) -{ - png_uint_32 color = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); - - if (transparent) { - if (p[3] == 0) { - return TICK_TYPE_NONE; - } - if (color == COLOR_LAYOUT_BOUNDS_TICK) { - return TICK_TYPE_LAYOUT_BOUNDS; - } - if (color == COLOR_TICK) { - return TICK_TYPE_TICK; - } - - // Error cases - if (p[3] != 0xff) { - *outError = "Frame pixels must be either solid or transparent (not intermediate alphas)"; - return TICK_TYPE_NONE; - } - if (p[0] != 0 || p[1] != 0 || p[2] != 0) { - *outError = "Ticks in transparent frame must be black or red"; - } - return TICK_TYPE_TICK; - } - - if (p[3] != 0xFF) { - *outError = "White frame must be a solid color (no alpha)"; - } - if (color == COLOR_WHITE) { - return TICK_TYPE_NONE; - } - if (color == COLOR_TICK) { - return TICK_TYPE_TICK; - } - if (color == COLOR_LAYOUT_BOUNDS_TICK) { - return TICK_TYPE_LAYOUT_BOUNDS; - } - - if (p[0] != 0 || p[1] != 0 || p[2] != 0) { - *outError = "Ticks in white frame must be black or red"; - return TICK_TYPE_NONE; - } - return TICK_TYPE_TICK; -} - -enum { - TICK_START, - TICK_INSIDE_1, - TICK_OUTSIDE_1 -}; - -static status_t get_horizontal_ticks( - png_bytep row, int width, bool transparent, bool required, - int32_t* outLeft, int32_t* outRight, const char** outError, - uint8_t* outDivs, bool multipleAllowed) -{ - int i; - *outLeft = *outRight = -1; - int state = TICK_START; - bool found = false; - - for (i=1; i<width-1; i++) { - if (TICK_TYPE_TICK == tick_type(row+i*4, transparent, outError)) { - if (state == TICK_START || - (state == TICK_OUTSIDE_1 && multipleAllowed)) { - *outLeft = i-1; - *outRight = width-2; - found = true; - if (outDivs != NULL) { - *outDivs += 2; - } - state = TICK_INSIDE_1; - } else if (state == TICK_OUTSIDE_1) { - *outError = "Can't have more than one marked region along edge"; - *outLeft = i; - return UNKNOWN_ERROR; - } - } else if (*outError == NULL) { - if (state == TICK_INSIDE_1) { - // We're done with this div. Move on to the next. - *outRight = i-1; - outRight += 2; - outLeft += 2; - state = TICK_OUTSIDE_1; - } - } else { - *outLeft = i; - return UNKNOWN_ERROR; - } - } - - if (required && !found) { - *outError = "No marked region found along edge"; - *outLeft = -1; - return UNKNOWN_ERROR; - } - - return NO_ERROR; -} - -static status_t get_vertical_ticks( - png_bytepp rows, int offset, int height, bool transparent, bool required, - int32_t* outTop, int32_t* outBottom, const char** outError, - uint8_t* outDivs, bool multipleAllowed) -{ - int i; - *outTop = *outBottom = -1; - int state = TICK_START; - bool found = false; - - for (i=1; i<height-1; i++) { - if (TICK_TYPE_TICK == tick_type(rows[i]+offset, transparent, outError)) { - if (state == TICK_START || - (state == TICK_OUTSIDE_1 && multipleAllowed)) { - *outTop = i-1; - *outBottom = height-2; - found = true; - if (outDivs != NULL) { - *outDivs += 2; - } - state = TICK_INSIDE_1; - } else if (state == TICK_OUTSIDE_1) { - *outError = "Can't have more than one marked region along edge"; - *outTop = i; - return UNKNOWN_ERROR; - } - } else if (*outError == NULL) { - if (state == TICK_INSIDE_1) { - // We're done with this div. Move on to the next. - *outBottom = i-1; - outTop += 2; - outBottom += 2; - state = TICK_OUTSIDE_1; - } - } else { - *outTop = i; - return UNKNOWN_ERROR; - } - } - - if (required && !found) { - *outError = "No marked region found along edge"; - *outTop = -1; - return UNKNOWN_ERROR; - } - - return NO_ERROR; -} - -static status_t get_horizontal_layout_bounds_ticks( - png_bytep row, int width, bool transparent, bool required, - int32_t* outLeft, int32_t* outRight, const char** outError) -{ - int i; - *outLeft = *outRight = 0; - - // Look for left tick - if (TICK_TYPE_LAYOUT_BOUNDS == tick_type(row + 4, transparent, outError)) { - // Starting with a layout padding tick - i = 1; - while (i < width - 1) { - (*outLeft)++; - i++; - int tick = tick_type(row + i * 4, transparent, outError); - if (tick != TICK_TYPE_LAYOUT_BOUNDS) { - break; - } - } - } - - // Look for right tick - if (TICK_TYPE_LAYOUT_BOUNDS == tick_type(row + (width - 2) * 4, transparent, outError)) { - // Ending with a layout padding tick - i = width - 2; - while (i > 1) { - (*outRight)++; - i--; - int tick = tick_type(row+i*4, transparent, outError); - if (tick != TICK_TYPE_LAYOUT_BOUNDS) { - break; - } - } - } - - return NO_ERROR; -} - -static status_t get_vertical_layout_bounds_ticks( - png_bytepp rows, int offset, int height, bool transparent, bool required, - int32_t* outTop, int32_t* outBottom, const char** outError) -{ - int i; - *outTop = *outBottom = 0; - - // Look for top tick - if (TICK_TYPE_LAYOUT_BOUNDS == tick_type(rows[1] + offset, transparent, outError)) { - // Starting with a layout padding tick - i = 1; - while (i < height - 1) { - (*outTop)++; - i++; - int tick = tick_type(rows[i] + offset, transparent, outError); - if (tick != TICK_TYPE_LAYOUT_BOUNDS) { - break; - } - } - } - - // Look for bottom tick - if (TICK_TYPE_LAYOUT_BOUNDS == tick_type(rows[height - 2] + offset, transparent, outError)) { - // Ending with a layout padding tick - i = height - 2; - while (i > 1) { - (*outBottom)++; - i--; - int tick = tick_type(rows[i] + offset, transparent, outError); - if (tick != TICK_TYPE_LAYOUT_BOUNDS) { - break; - } - } - } - - return NO_ERROR; -} - - -static uint32_t get_color( - png_bytepp rows, int left, int top, int right, int bottom) -{ - png_bytep color = rows[top] + left*4; - - if (left > right || top > bottom) { - return Res_png_9patch::TRANSPARENT_COLOR; - } - - while (top <= bottom) { - for (int i = left; i <= right; i++) { - png_bytep p = rows[top]+i*4; - if (color[3] == 0) { - if (p[3] != 0) { - return Res_png_9patch::NO_COLOR; - } - } else if (p[0] != color[0] || p[1] != color[1] - || p[2] != color[2] || p[3] != color[3]) { - return Res_png_9patch::NO_COLOR; - } - } - top++; - } - - if (color[3] == 0) { - return Res_png_9patch::TRANSPARENT_COLOR; - } - return (color[3]<<24) | (color[0]<<16) | (color[1]<<8) | color[2]; -} - -static void select_patch( - int which, int front, int back, int size, int* start, int* end) -{ - switch (which) { - case 0: - *start = 0; - *end = front-1; - break; - case 1: - *start = front; - *end = back-1; - break; - case 2: - *start = back; - *end = size-1; - break; - } -} - -static uint32_t get_color(image_info* image, int hpatch, int vpatch) -{ - int left, right, top, bottom; - select_patch( - hpatch, image->info9Patch.xDivs[0], image->info9Patch.xDivs[1], - image->width, &left, &right); - select_patch( - vpatch, image->info9Patch.yDivs[0], image->info9Patch.yDivs[1], - image->height, &top, &bottom); - //printf("Selecting h=%d v=%d: (%d,%d)-(%d,%d)\n", - // hpatch, vpatch, left, top, right, bottom); - const uint32_t c = get_color(image->rows, left, top, right, bottom); - NOISY(printf("Color in (%d,%d)-(%d,%d): #%08x\n", left, top, right, bottom, c)); - return c; -} - -static status_t do_9patch(const char* imageName, image_info* image) -{ - image->is9Patch = true; - - int W = image->width; - int H = image->height; - int i, j; - - int maxSizeXDivs = W * sizeof(int32_t); - int maxSizeYDivs = H * sizeof(int32_t); - int32_t* xDivs = (int32_t*) malloc(maxSizeXDivs); - int32_t* yDivs = (int32_t*) malloc(maxSizeYDivs); - uint8_t numXDivs = 0; - uint8_t numYDivs = 0; - int8_t numColors; - int numRows; - int numCols; - int top; - int left; - int right; - int bottom; - memset(xDivs, -1, maxSizeXDivs); - memset(yDivs, -1, maxSizeYDivs); - image->info9Patch.paddingLeft = image->info9Patch.paddingRight = - image->info9Patch.paddingTop = image->info9Patch.paddingBottom = -1; - - image->layoutBoundsLeft = image->layoutBoundsRight = - image->layoutBoundsTop = image->layoutBoundsBottom = 0; - - png_bytep p = image->rows[0]; - bool transparent = p[3] == 0; - bool hasColor = false; - - const char* errorMsg = NULL; - int errorPixel = -1; - const char* errorEdge = NULL; - - int colorIndex = 0; - - // Validate size... - if (W < 3 || H < 3) { - errorMsg = "Image must be at least 3x3 (1x1 without frame) pixels"; - goto getout; - } - - // Validate frame... - if (!transparent && - (p[0] != 0xFF || p[1] != 0xFF || p[2] != 0xFF || p[3] != 0xFF)) { - errorMsg = "Must have one-pixel frame that is either transparent or white"; - goto getout; - } - - // Find left and right of sizing areas... - if (get_horizontal_ticks(p, W, transparent, true, &xDivs[0], - &xDivs[1], &errorMsg, &numXDivs, true) != NO_ERROR) { - errorPixel = xDivs[0]; - errorEdge = "top"; - goto getout; - } - - // Find top and bottom of sizing areas... - if (get_vertical_ticks(image->rows, 0, H, transparent, true, &yDivs[0], - &yDivs[1], &errorMsg, &numYDivs, true) != NO_ERROR) { - errorPixel = yDivs[0]; - errorEdge = "left"; - goto getout; - } - - // Find left and right of padding area... - if (get_horizontal_ticks(image->rows[H-1], W, transparent, false, &image->info9Patch.paddingLeft, - &image->info9Patch.paddingRight, &errorMsg, NULL, false) != NO_ERROR) { - errorPixel = image->info9Patch.paddingLeft; - errorEdge = "bottom"; - goto getout; - } - - // Find top and bottom of padding area... - if (get_vertical_ticks(image->rows, (W-1)*4, H, transparent, false, &image->info9Patch.paddingTop, - &image->info9Patch.paddingBottom, &errorMsg, NULL, false) != NO_ERROR) { - errorPixel = image->info9Patch.paddingTop; - errorEdge = "right"; - goto getout; - } - - // Find left and right of layout padding... - get_horizontal_layout_bounds_ticks(image->rows[H-1], W, transparent, false, - &image->layoutBoundsLeft, - &image->layoutBoundsRight, &errorMsg); - - get_vertical_layout_bounds_ticks(image->rows, (W-1)*4, H, transparent, false, - &image->layoutBoundsTop, - &image->layoutBoundsBottom, &errorMsg); - - image->haveLayoutBounds = image->layoutBoundsLeft != 0 - || image->layoutBoundsRight != 0 - || image->layoutBoundsTop != 0 - || image->layoutBoundsBottom != 0; - - if (image->haveLayoutBounds) { - NOISY(printf("layoutBounds=%d %d %d %d\n", image->layoutBoundsLeft, image->layoutBoundsTop, - image->layoutBoundsRight, image->layoutBoundsBottom)); - } - - // Copy patch data into image - image->info9Patch.numXDivs = numXDivs; - image->info9Patch.numYDivs = numYDivs; - image->info9Patch.xDivs = xDivs; - image->info9Patch.yDivs = yDivs; - - // If padding is not yet specified, take values from size. - if (image->info9Patch.paddingLeft < 0) { - image->info9Patch.paddingLeft = xDivs[0]; - image->info9Patch.paddingRight = W - 2 - xDivs[1]; - } else { - // Adjust value to be correct! - image->info9Patch.paddingRight = W - 2 - image->info9Patch.paddingRight; - } - if (image->info9Patch.paddingTop < 0) { - image->info9Patch.paddingTop = yDivs[0]; - image->info9Patch.paddingBottom = H - 2 - yDivs[1]; - } else { - // Adjust value to be correct! - image->info9Patch.paddingBottom = H - 2 - image->info9Patch.paddingBottom; - } - - NOISY(printf("Size ticks for %s: x0=%d, x1=%d, y0=%d, y1=%d\n", imageName, - image->info9Patch.xDivs[0], image->info9Patch.xDivs[1], - image->info9Patch.yDivs[0], image->info9Patch.yDivs[1])); - NOISY(printf("padding ticks for %s: l=%d, r=%d, t=%d, b=%d\n", imageName, - image->info9Patch.paddingLeft, image->info9Patch.paddingRight, - image->info9Patch.paddingTop, image->info9Patch.paddingBottom)); - - // Remove frame from image. - image->rows = (png_bytepp)malloc((H-2) * sizeof(png_bytep)); - for (i=0; i<(H-2); i++) { - image->rows[i] = image->allocRows[i+1]; - memmove(image->rows[i], image->rows[i]+4, (W-2)*4); - } - image->width -= 2; - W = image->width; - image->height -= 2; - H = image->height; - - // Figure out the number of rows and columns in the N-patch - numCols = numXDivs + 1; - if (xDivs[0] == 0) { // Column 1 is strechable - numCols--; - } - if (xDivs[numXDivs - 1] == W) { - numCols--; - } - numRows = numYDivs + 1; - if (yDivs[0] == 0) { // Row 1 is strechable - numRows--; - } - if (yDivs[numYDivs - 1] == H) { - numRows--; - } - - // Make sure the amount of rows and columns will fit in the number of - // colors we can use in the 9-patch format. - if (numRows * numCols > 0x7F) { - errorMsg = "Too many rows and columns in 9-patch perimeter"; - goto getout; - } - - numColors = numRows * numCols; - image->info9Patch.numColors = numColors; - image->info9Patch.colors = (uint32_t*)malloc(numColors * sizeof(uint32_t)); - - // Fill in color information for each patch. - - uint32_t c; - top = 0; - - // The first row always starts with the top being at y=0 and the bottom - // being either yDivs[1] (if yDivs[0]=0) of yDivs[0]. In the former case - // the first row is stretchable along the Y axis, otherwise it is fixed. - // The last row always ends with the bottom being bitmap.height and the top - // being either yDivs[numYDivs-2] (if yDivs[numYDivs-1]=bitmap.height) or - // yDivs[numYDivs-1]. In the former case the last row is stretchable along - // the Y axis, otherwise it is fixed. - // - // The first and last columns are similarly treated with respect to the X - // axis. - // - // The above is to help explain some of the special casing that goes on the - // code below. - - // The initial yDiv and whether the first row is considered stretchable or - // not depends on whether yDiv[0] was zero or not. - for (j = (yDivs[0] == 0 ? 1 : 0); - j <= numYDivs && top < H; - j++) { - if (j == numYDivs) { - bottom = H; - } else { - bottom = yDivs[j]; - } - left = 0; - // The initial xDiv and whether the first column is considered - // stretchable or not depends on whether xDiv[0] was zero or not. - for (i = xDivs[0] == 0 ? 1 : 0; - i <= numXDivs && left < W; - i++) { - if (i == numXDivs) { - right = W; - } else { - right = xDivs[i]; - } - c = get_color(image->rows, left, top, right - 1, bottom - 1); - image->info9Patch.colors[colorIndex++] = c; - NOISY(if (c != Res_png_9patch::NO_COLOR) hasColor = true); - left = right; - } - top = bottom; - } - - assert(colorIndex == numColors); - - for (i=0; i<numColors; i++) { - if (hasColor) { - if (i == 0) printf("Colors in %s:\n ", imageName); - printf(" #%08x", image->info9Patch.colors[i]); - if (i == numColors - 1) printf("\n"); - } - } - - image->is9Patch = true; - image->info9Patch.deviceToFile(); - -getout: - if (errorMsg) { - fprintf(stderr, - "ERROR: 9-patch image %s malformed.\n" - " %s.\n", imageName, errorMsg); - if (errorEdge != NULL) { - if (errorPixel >= 0) { - fprintf(stderr, - " Found at pixel #%d along %s edge.\n", errorPixel, errorEdge); - } else { - fprintf(stderr, - " Found along %s edge.\n", errorEdge); - } - } - return UNKNOWN_ERROR; - } - return NO_ERROR; -} - -static void checkNinePatchSerialization(Res_png_9patch* inPatch, void * data) -{ - if (sizeof(void*) != sizeof(int32_t)) { - // can't deserialize on a non-32 bit system - return; - } - size_t patchSize = inPatch->serializedSize(); - void * newData = malloc(patchSize); - memcpy(newData, data, patchSize); - Res_png_9patch* outPatch = inPatch->deserialize(newData); - // deserialization is done in place, so outPatch == newData - assert(outPatch == newData); - assert(outPatch->numXDivs == inPatch->numXDivs); - assert(outPatch->numYDivs == inPatch->numYDivs); - assert(outPatch->paddingLeft == inPatch->paddingLeft); - assert(outPatch->paddingRight == inPatch->paddingRight); - assert(outPatch->paddingTop == inPatch->paddingTop); - assert(outPatch->paddingBottom == inPatch->paddingBottom); - for (int i = 0; i < outPatch->numXDivs; i++) { - assert(outPatch->xDivs[i] == inPatch->xDivs[i]); - } - for (int i = 0; i < outPatch->numYDivs; i++) { - assert(outPatch->yDivs[i] == inPatch->yDivs[i]); - } - for (int i = 0; i < outPatch->numColors; i++) { - assert(outPatch->colors[i] == inPatch->colors[i]); - } - free(newData); -} - -static bool patch_equals(Res_png_9patch& patch1, Res_png_9patch& patch2) { - if (!(patch1.numXDivs == patch2.numXDivs && - patch1.numYDivs == patch2.numYDivs && - patch1.numColors == patch2.numColors && - patch1.paddingLeft == patch2.paddingLeft && - patch1.paddingRight == patch2.paddingRight && - patch1.paddingTop == patch2.paddingTop && - patch1.paddingBottom == patch2.paddingBottom)) { - return false; - } - for (int i = 0; i < patch1.numColors; i++) { - if (patch1.colors[i] != patch2.colors[i]) { - return false; - } - } - for (int i = 0; i < patch1.numXDivs; i++) { - if (patch1.xDivs[i] != patch2.xDivs[i]) { - return false; - } - } - for (int i = 0; i < patch1.numYDivs; i++) { - if (patch1.yDivs[i] != patch2.yDivs[i]) { - return false; - } - } - return true; -} - -static void dump_image(int w, int h, png_bytepp rows, int color_type) -{ - int i, j, rr, gg, bb, aa; - - int bpp; - if (color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_TYPE_GRAY) { - bpp = 1; - } else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { - bpp = 2; - } else if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) { - // We use a padding byte even when there is no alpha - bpp = 4; - } else { - printf("Unknown color type %d.\n", color_type); - } - - for (j = 0; j < h; j++) { - png_bytep row = rows[j]; - for (i = 0; i < w; i++) { - rr = row[0]; - gg = row[1]; - bb = row[2]; - aa = row[3]; - row += bpp; - - if (i == 0) { - printf("Row %d:", j); - } - switch (bpp) { - case 1: - printf(" (%d)", rr); - break; - case 2: - printf(" (%d %d", rr, gg); - break; - case 3: - printf(" (%d %d %d)", rr, gg, bb); - break; - case 4: - printf(" (%d %d %d %d)", rr, gg, bb, aa); - break; - } - if (i == (w - 1)) { - NOISY(printf("\n")); - } - } - } -} - -#define MAX(a,b) ((a)>(b)?(a):(b)) -#define ABS(a) ((a)<0?-(a):(a)) - -static void analyze_image(const char *imageName, image_info &imageInfo, int grayscaleTolerance, - png_colorp rgbPalette, png_bytep alphaPalette, - int *paletteEntries, bool *hasTransparency, int *colorType, - png_bytepp outRows) -{ - int w = imageInfo.width; - int h = imageInfo.height; - int i, j, rr, gg, bb, aa, idx; - uint32_t colors[256], col; - int num_colors = 0; - int maxGrayDeviation = 0; - - bool isOpaque = true; - bool isPalette = true; - bool isGrayscale = true; - - // Scan the entire image and determine if: - // 1. Every pixel has R == G == B (grayscale) - // 2. Every pixel has A == 255 (opaque) - // 3. There are no more than 256 distinct RGBA colors - - // NOISY(printf("Initial image data:\n")); - // dump_image(w, h, imageInfo.rows, PNG_COLOR_TYPE_RGB_ALPHA); - - for (j = 0; j < h; j++) { - png_bytep row = imageInfo.rows[j]; - png_bytep out = outRows[j]; - for (i = 0; i < w; i++) { - rr = *row++; - gg = *row++; - bb = *row++; - aa = *row++; - - int odev = maxGrayDeviation; - maxGrayDeviation = MAX(ABS(rr - gg), maxGrayDeviation); - maxGrayDeviation = MAX(ABS(gg - bb), maxGrayDeviation); - maxGrayDeviation = MAX(ABS(bb - rr), maxGrayDeviation); - if (maxGrayDeviation > odev) { - NOISY(printf("New max dev. = %d at pixel (%d, %d) = (%d %d %d %d)\n", - maxGrayDeviation, i, j, rr, gg, bb, aa)); - } - - // Check if image is really grayscale - if (isGrayscale) { - if (rr != gg || rr != bb) { - NOISY(printf("Found a non-gray pixel at %d, %d = (%d %d %d %d)\n", - i, j, rr, gg, bb, aa)); - isGrayscale = false; - } - } - - // Check if image is really opaque - if (isOpaque) { - if (aa != 0xff) { - NOISY(printf("Found a non-opaque pixel at %d, %d = (%d %d %d %d)\n", - i, j, rr, gg, bb, aa)); - isOpaque = false; - } - } - - // Check if image is really <= 256 colors - if (isPalette) { - col = (uint32_t) ((rr << 24) | (gg << 16) | (bb << 8) | aa); - bool match = false; - for (idx = 0; idx < num_colors; idx++) { - if (colors[idx] == col) { - match = true; - break; - } - } - - // Write the palette index for the pixel to outRows optimistically - // We might overwrite it later if we decide to encode as gray or - // gray + alpha - *out++ = idx; - if (!match) { - if (num_colors == 256) { - NOISY(printf("Found 257th color at %d, %d\n", i, j)); - isPalette = false; - } else { - colors[num_colors++] = col; - } - } - } - } - } - - *paletteEntries = 0; - *hasTransparency = !isOpaque; - int bpp = isOpaque ? 3 : 4; - int paletteSize = w * h + bpp * num_colors; - - NOISY(printf("isGrayscale = %s\n", isGrayscale ? "true" : "false")); - NOISY(printf("isOpaque = %s\n", isOpaque ? "true" : "false")); - NOISY(printf("isPalette = %s\n", isPalette ? "true" : "false")); - NOISY(printf("Size w/ palette = %d, gray+alpha = %d, rgb(a) = %d\n", - paletteSize, 2 * w * h, bpp * w * h)); - NOISY(printf("Max gray deviation = %d, tolerance = %d\n", maxGrayDeviation, grayscaleTolerance)); - - // Choose the best color type for the image. - // 1. Opaque gray - use COLOR_TYPE_GRAY at 1 byte/pixel - // 2. Gray + alpha - use COLOR_TYPE_PALETTE if the number of distinct combinations - // is sufficiently small, otherwise use COLOR_TYPE_GRAY_ALPHA - // 3. RGB(A) - use COLOR_TYPE_PALETTE if the number of distinct colors is sufficiently - // small, otherwise use COLOR_TYPE_RGB{_ALPHA} - if (isGrayscale) { - if (isOpaque) { - *colorType = PNG_COLOR_TYPE_GRAY; // 1 byte/pixel - } else { - // Use a simple heuristic to determine whether using a palette will - // save space versus using gray + alpha for each pixel. - // This doesn't take into account chunk overhead, filtering, LZ - // compression, etc. - if (isPalette && (paletteSize < 2 * w * h)) { - *colorType = PNG_COLOR_TYPE_PALETTE; // 1 byte/pixel + 4 bytes/color - } else { - *colorType = PNG_COLOR_TYPE_GRAY_ALPHA; // 2 bytes per pixel - } - } - } else if (isPalette && (paletteSize < bpp * w * h)) { - *colorType = PNG_COLOR_TYPE_PALETTE; - } else { - if (maxGrayDeviation <= grayscaleTolerance) { - printf("%s: forcing image to gray (max deviation = %d)\n", imageName, maxGrayDeviation); - *colorType = isOpaque ? PNG_COLOR_TYPE_GRAY : PNG_COLOR_TYPE_GRAY_ALPHA; - } else { - *colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; - } - } - - // Perform postprocessing of the image or palette data based on the final - // color type chosen - - if (*colorType == PNG_COLOR_TYPE_PALETTE) { - // Create separate RGB and Alpha palettes and set the number of colors - *paletteEntries = num_colors; - - // Create the RGB and alpha palettes - for (int idx = 0; idx < num_colors; idx++) { - col = colors[idx]; - rgbPalette[idx].red = (png_byte) ((col >> 24) & 0xff); - rgbPalette[idx].green = (png_byte) ((col >> 16) & 0xff); - rgbPalette[idx].blue = (png_byte) ((col >> 8) & 0xff); - alphaPalette[idx] = (png_byte) (col & 0xff); - } - } else if (*colorType == PNG_COLOR_TYPE_GRAY || *colorType == PNG_COLOR_TYPE_GRAY_ALPHA) { - // If the image is gray or gray + alpha, compact the pixels into outRows - for (j = 0; j < h; j++) { - png_bytep row = imageInfo.rows[j]; - png_bytep out = outRows[j]; - for (i = 0; i < w; i++) { - rr = *row++; - gg = *row++; - bb = *row++; - aa = *row++; - - if (isGrayscale) { - *out++ = rr; - } else { - *out++ = (png_byte) (rr * 0.2126f + gg * 0.7152f + bb * 0.0722f); - } - if (!isOpaque) { - *out++ = aa; - } - } - } - } -} - - -static void write_png(const char* imageName, - png_structp write_ptr, png_infop write_info, - image_info& imageInfo, int grayscaleTolerance) -{ - bool optimize = true; - png_uint_32 width, height; - int color_type; - int bit_depth, interlace_type, compression_type; - int i; - - png_unknown_chunk unknowns[2]; - unknowns[0].data = NULL; - unknowns[1].data = NULL; - - png_bytepp outRows = (png_bytepp) malloc((int) imageInfo.height * sizeof(png_bytep)); - if (outRows == (png_bytepp) 0) { - printf("Can't allocate output buffer!\n"); - exit(1); - } - for (i = 0; i < (int) imageInfo.height; i++) { - outRows[i] = (png_bytep) malloc(2 * (int) imageInfo.width); - if (outRows[i] == (png_bytep) 0) { - printf("Can't allocate output buffer!\n"); - exit(1); - } - } - - png_set_compression_level(write_ptr, Z_BEST_COMPRESSION); - - NOISY(printf("Writing image %s: w = %d, h = %d\n", imageName, - (int) imageInfo.width, (int) imageInfo.height)); - - png_color rgbPalette[256]; - png_byte alphaPalette[256]; - bool hasTransparency; - int paletteEntries; - - analyze_image(imageName, imageInfo, grayscaleTolerance, rgbPalette, alphaPalette, - &paletteEntries, &hasTransparency, &color_type, outRows); - - // If the image is a 9-patch, we need to preserve it as a ARGB file to make - // sure the pixels will not be pre-dithered/clamped until we decide they are - if (imageInfo.is9Patch && (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE)) { - color_type = PNG_COLOR_TYPE_RGB_ALPHA; - } - - switch (color_type) { - case PNG_COLOR_TYPE_PALETTE: - NOISY(printf("Image %s has %d colors%s, using PNG_COLOR_TYPE_PALETTE\n", - imageName, paletteEntries, - hasTransparency ? " (with alpha)" : "")); - break; - case PNG_COLOR_TYPE_GRAY: - NOISY(printf("Image %s is opaque gray, using PNG_COLOR_TYPE_GRAY\n", imageName)); - break; - case PNG_COLOR_TYPE_GRAY_ALPHA: - NOISY(printf("Image %s is gray + alpha, using PNG_COLOR_TYPE_GRAY_ALPHA\n", imageName)); - break; - case PNG_COLOR_TYPE_RGB: - NOISY(printf("Image %s is opaque RGB, using PNG_COLOR_TYPE_RGB\n", imageName)); - break; - case PNG_COLOR_TYPE_RGB_ALPHA: - NOISY(printf("Image %s is RGB + alpha, using PNG_COLOR_TYPE_RGB_ALPHA\n", imageName)); - break; - } - - png_set_IHDR(write_ptr, write_info, imageInfo.width, imageInfo.height, - 8, color_type, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - if (color_type == PNG_COLOR_TYPE_PALETTE) { - png_set_PLTE(write_ptr, write_info, rgbPalette, paletteEntries); - if (hasTransparency) { - png_set_tRNS(write_ptr, write_info, alphaPalette, paletteEntries, (png_color_16p) 0); - } - png_set_filter(write_ptr, 0, PNG_NO_FILTERS); - } else { - png_set_filter(write_ptr, 0, PNG_ALL_FILTERS); - } - - if (imageInfo.is9Patch) { - int chunk_count = 1 + (imageInfo.haveLayoutBounds ? 1 : 0); - int p_index = imageInfo.haveLayoutBounds ? 1 : 0; - int b_index = 0; - png_byte *chunk_names = imageInfo.haveLayoutBounds - ? (png_byte*)"npLb\0npTc\0" - : (png_byte*)"npTc"; - NOISY(printf("Adding 9-patch info...\n")); - strcpy((char*)unknowns[p_index].name, "npTc"); - unknowns[p_index].data = (png_byte*)imageInfo.info9Patch.serialize(); - unknowns[p_index].size = imageInfo.info9Patch.serializedSize(); - // TODO: remove the check below when everything works - checkNinePatchSerialization(&imageInfo.info9Patch, unknowns[p_index].data); - - if (imageInfo.haveLayoutBounds) { - int chunk_size = sizeof(png_uint_32) * 4; - strcpy((char*)unknowns[b_index].name, "npLb"); - unknowns[b_index].data = (png_byte*) calloc(chunk_size, 1); - memcpy(unknowns[b_index].data, &imageInfo.layoutBoundsLeft, chunk_size); - unknowns[b_index].size = chunk_size; - } - - for (int i = 0; i < chunk_count; i++) { - unknowns[i].location = PNG_HAVE_PLTE; - } - png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS, - chunk_names, chunk_count); - png_set_unknown_chunks(write_ptr, write_info, unknowns, chunk_count); -#if PNG_LIBPNG_VER < 10600 - /* Deal with unknown chunk location bug in 1.5.x and earlier */ - png_set_unknown_chunk_location(write_ptr, write_info, 0, PNG_HAVE_PLTE); - if (imageInfo.haveLayoutBounds) { - png_set_unknown_chunk_location(write_ptr, write_info, 1, PNG_HAVE_PLTE); - } -#endif - } - - - png_write_info(write_ptr, write_info); - - png_bytepp rows; - if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) { - if (color_type == PNG_COLOR_TYPE_RGB) { - png_set_filler(write_ptr, 0, PNG_FILLER_AFTER); - } - rows = imageInfo.rows; - } else { - rows = outRows; - } - png_write_image(write_ptr, rows); - -// NOISY(printf("Final image data:\n")); -// dump_image(imageInfo.width, imageInfo.height, rows, color_type); - - png_write_end(write_ptr, write_info); - - for (i = 0; i < (int) imageInfo.height; i++) { - free(outRows[i]); - } - free(outRows); - free(unknowns[0].data); - free(unknowns[1].data); - - png_get_IHDR(write_ptr, write_info, &width, &height, - &bit_depth, &color_type, &interlace_type, - &compression_type, NULL); - - NOISY(printf("Image written: w=%d, h=%d, d=%d, colors=%d, inter=%d, comp=%d\n", - (int)width, (int)height, bit_depth, color_type, interlace_type, - compression_type)); -} - -status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets, - const sp<AaptFile>& file, String8* outNewLeafName) -{ - String8 ext(file->getPath().getPathExtension()); - - // We currently only process PNG images. - if (strcmp(ext.string(), ".png") != 0) { - return NO_ERROR; - } - - // Example of renaming a file: - //*outNewLeafName = file->getPath().getBasePath().getFileName(); - //outNewLeafName->append(".nupng"); - - String8 printableName(file->getPrintableSource()); - - if (bundle->getVerbose()) { - printf("Processing image: %s\n", printableName.string()); - } - - png_structp read_ptr = NULL; - png_infop read_info = NULL; - FILE* fp; - - image_info imageInfo; - - png_structp write_ptr = NULL; - png_infop write_info = NULL; - - status_t error = UNKNOWN_ERROR; - - const size_t nameLen = file->getPath().length(); - - fp = fopen(file->getSourceFile().string(), "rb"); - if (fp == NULL) { - fprintf(stderr, "%s: ERROR: Unable to open PNG file\n", printableName.string()); - goto bail; - } - - read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, (png_error_ptr)NULL, - (png_error_ptr)NULL); - if (!read_ptr) { - goto bail; - } - - read_info = png_create_info_struct(read_ptr); - if (!read_info) { - goto bail; - } - - if (setjmp(png_jmpbuf(read_ptr))) { - goto bail; - } - - png_init_io(read_ptr, fp); - - read_png(printableName.string(), read_ptr, read_info, &imageInfo); - - if (nameLen > 6) { - const char* name = file->getPath().string(); - if (name[nameLen-5] == '9' && name[nameLen-6] == '.') { - if (do_9patch(printableName.string(), &imageInfo) != NO_ERROR) { - goto bail; - } - } - } - - write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, (png_error_ptr)NULL, - (png_error_ptr)NULL); - if (!write_ptr) - { - goto bail; - } - - write_info = png_create_info_struct(write_ptr); - if (!write_info) - { - goto bail; - } - - png_set_write_fn(write_ptr, (void*)file.get(), - png_write_aapt_file, png_flush_aapt_file); - - if (setjmp(png_jmpbuf(write_ptr))) - { - goto bail; - } - - write_png(printableName.string(), write_ptr, write_info, imageInfo, - bundle->getGrayscaleTolerance()); - - error = NO_ERROR; - - if (bundle->getVerbose()) { - fseek(fp, 0, SEEK_END); - size_t oldSize = (size_t)ftell(fp); - size_t newSize = file->getSize(); - float factor = ((float)newSize)/oldSize; - int percent = (int)(factor*100); - printf(" (processed image %s: %d%% size of source)\n", printableName.string(), percent); - } - -bail: - if (read_ptr) { - png_destroy_read_struct(&read_ptr, &read_info, (png_infopp)NULL); - } - if (fp) { - fclose(fp); - } - if (write_ptr) { - png_destroy_write_struct(&write_ptr, &write_info); - } - - if (error != NO_ERROR) { - fprintf(stderr, "ERROR: Failure processing PNG image %s\n", - file->getPrintableSource().string()); - } - return error; -} - -status_t preProcessImageToCache(const Bundle* bundle, const String8& source, const String8& dest) -{ - png_structp read_ptr = NULL; - png_infop read_info = NULL; - - FILE* fp; - - image_info imageInfo; - - png_structp write_ptr = NULL; - png_infop write_info = NULL; - - status_t error = UNKNOWN_ERROR; - - if (bundle->getVerbose()) { - printf("Processing image to cache: %s => %s\n", source.string(), dest.string()); - } - - // Get a file handler to read from - fp = fopen(source.string(),"rb"); - if (fp == NULL) { - fprintf(stderr, "%s ERROR: Unable to open PNG file\n", source.string()); - return error; - } - - // Call libpng to get a struct to read image data into - read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!read_ptr) { - fclose(fp); - png_destroy_read_struct(&read_ptr, &read_info,NULL); - return error; - } - - // Call libpng to get a struct to read image info into - read_info = png_create_info_struct(read_ptr); - if (!read_info) { - fclose(fp); - png_destroy_read_struct(&read_ptr, &read_info,NULL); - return error; - } - - // Set a jump point for libpng to long jump back to on error - if (setjmp(png_jmpbuf(read_ptr))) { - fclose(fp); - png_destroy_read_struct(&read_ptr, &read_info,NULL); - return error; - } - - // Set up libpng to read from our file. - png_init_io(read_ptr,fp); - - // Actually read data from the file - read_png(source.string(), read_ptr, read_info, &imageInfo); - - // We're done reading so we can clean up - // Find old file size before releasing handle - fseek(fp, 0, SEEK_END); - size_t oldSize = (size_t)ftell(fp); - fclose(fp); - png_destroy_read_struct(&read_ptr, &read_info,NULL); - - // Check to see if we're dealing with a 9-patch - // If we are, process appropriately - if (source.getBasePath().getPathExtension() == ".9") { - if (do_9patch(source.string(), &imageInfo) != NO_ERROR) { - return error; - } - } - - // Call libpng to create a structure to hold the processed image data - // that can be written to disk - write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!write_ptr) { - png_destroy_write_struct(&write_ptr, &write_info); - return error; - } - - // Call libpng to create a structure to hold processed image info that can - // be written to disk - write_info = png_create_info_struct(write_ptr); - if (!write_info) { - png_destroy_write_struct(&write_ptr, &write_info); - return error; - } - - // Open up our destination file for writing - fp = fopen(dest.string(), "wb"); - if (!fp) { - fprintf(stderr, "%s ERROR: Unable to open PNG file\n", dest.string()); - png_destroy_write_struct(&write_ptr, &write_info); - return error; - } - - // Set up libpng to write to our file - png_init_io(write_ptr, fp); - - // Set up a jump for libpng to long jump back on on errors - if (setjmp(png_jmpbuf(write_ptr))) { - fclose(fp); - png_destroy_write_struct(&write_ptr, &write_info); - return error; - } - - // Actually write out to the new png - write_png(dest.string(), write_ptr, write_info, imageInfo, - bundle->getGrayscaleTolerance()); - - if (bundle->getVerbose()) { - // Find the size of our new file - FILE* reader = fopen(dest.string(), "rb"); - fseek(reader, 0, SEEK_END); - size_t newSize = (size_t)ftell(reader); - fclose(reader); - - float factor = ((float)newSize)/oldSize; - int percent = (int)(factor*100); - printf(" (processed image to cache entry %s: %d%% size of source)\n", - dest.string(), percent); - } - - //Clean up - fclose(fp); - png_destroy_write_struct(&write_ptr, &write_info); - - return NO_ERROR; -} - -status_t postProcessImage(const sp<AaptAssets>& assets, - ResourceTable* table, const sp<AaptFile>& file) -{ - String8 ext(file->getPath().getPathExtension()); - - // At this point, now that we have all the resource data, all we need to - // do is compile XML files. - if (strcmp(ext.string(), ".xml") == 0) { - return compileXmlFile(assets, file, table); - } - - return NO_ERROR; -} diff --git a/tools/aapt/Images.h b/tools/aapt/Images.h deleted file mode 100644 index 91b6554..0000000 --- a/tools/aapt/Images.h +++ /dev/null @@ -1,26 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Build resource files from raw assets. -// - -#ifndef IMAGES_H -#define IMAGES_H - -#include "ResourceTable.h" -#include "Bundle.h" - -#include <utils/String8.h> -#include <utils/RefBase.h> - -using android::String8; - -status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets, - const sp<AaptFile>& file, String8* outNewLeafName); - -status_t preProcessImageToCache(const Bundle* bundle, const String8& source, const String8& dest); - -status_t postProcessImage(const sp<AaptAssets>& assets, - ResourceTable* table, const sp<AaptFile>& file); - -#endif diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp deleted file mode 100644 index 4a8aa9c..0000000 --- a/tools/aapt/Main.cpp +++ /dev/null @@ -1,655 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Android Asset Packaging Tool main entry point. -// -#include "Main.h" -#include "Bundle.h" - -#include <utils/Log.h> -#include <utils/threads.h> -#include <utils/List.h> -#include <utils/Errors.h> - -#include <stdlib.h> -#include <getopt.h> -#include <assert.h> - -using namespace android; - -static const char* gProgName = "aapt"; - -/* - * When running under Cygwin on Windows, this will convert slash-based - * paths into back-slash-based ones. Otherwise the ApptAssets file comparisons - * fail later as they use back-slash separators under Windows. - * - * This operates in-place on the path string. - */ -void convertPath(char *path) { - if (path != NULL && OS_PATH_SEPARATOR != '/') { - for (; *path; path++) { - if (*path == '/') { - *path = OS_PATH_SEPARATOR; - } - } - } -} - -/* - * Print usage info. - */ -void usage(void) -{ - fprintf(stderr, "Android Asset Packaging Tool\n\n"); - fprintf(stderr, "Usage:\n"); - fprintf(stderr, - " %s l[ist] [-v] [-a] file.{zip,jar,apk}\n" - " List contents of Zip-compatible archive.\n\n", gProgName); - fprintf(stderr, - " %s d[ump] [--values] [--include-meta-data] WHAT file.{apk} [asset [asset ...]]\n" - " strings Print the contents of the resource table string pool in the APK.\n" - " badging Print the label and icon for the app declared in APK.\n" - " permissions Print the permissions from the APK.\n" - " resources Print the resource table from the APK.\n" - " configurations Print the configurations in the APK.\n" - " xmltree Print the compiled xmls in the given assets.\n" - " xmlstrings Print the strings of the given compiled xml assets.\n\n", gProgName); - fprintf(stderr, - " %s p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \\\n" - " [-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \\\n" - " [--debug-mode] [--min-sdk-version VAL] [--target-sdk-version VAL] \\\n" - " [--app-version VAL] [--app-version-name TEXT] [--custom-package VAL] \\\n" - " [--rename-manifest-package PACKAGE] \\\n" - " [--rename-instrumentation-target-package PACKAGE] \\\n" - " [--utf16] [--auto-add-overlay] \\\n" - " [--max-res-version VAL] \\\n" - " [-I base-package [-I base-package ...]] \\\n" - " [-A asset-source-dir] [-G class-list-file] [-P public-definitions-file] \\\n" - " [-S resource-sources [-S resource-sources ...]] \\\n" - " [-F apk-file] [-J R-file-dir] \\\n" - " [--product product1,product2,...] \\\n" - " [-c CONFIGS] [--preferred-configurations CONFIGS] \\\n" - " [raw-files-dir [raw-files-dir] ...] \\\n" - " [--output-text-symbols DIR]\n" - "\n" - " Package the android resources. It will read assets and resources that are\n" - " supplied with the -M -A -S or raw-files-dir arguments. The -J -P -F and -R\n" - " options control which files are output.\n\n" - , gProgName); - fprintf(stderr, - " %s r[emove] [-v] file.{zip,jar,apk} file1 [file2 ...]\n" - " Delete specified files from Zip-compatible archive.\n\n", - gProgName); - fprintf(stderr, - " %s a[dd] [-v] file.{zip,jar,apk} file1 [file2 ...]\n" - " Add specified files to Zip-compatible archive.\n\n", gProgName); - fprintf(stderr, - " %s c[runch] [-v] -S resource-sources ... -C output-folder ...\n" - " Do PNG preprocessing on one or several resource folders\n" - " and store the results in the output folder.\n\n", gProgName); - fprintf(stderr, - " %s s[ingleCrunch] [-v] -i input-file -o outputfile\n" - " Do PNG preprocessing on a single file.\n\n", gProgName); - fprintf(stderr, - " %s v[ersion]\n" - " Print program version.\n\n", gProgName); - fprintf(stderr, - " Modifiers:\n" - " -a print Android-specific data (resources, manifest) when listing\n" - " -c specify which configurations to include. The default is all\n" - " configurations. The value of the parameter should be a comma\n" - " separated list of configuration values. Locales should be specified\n" - " as either a language or language-region pair. Some examples:\n" - " en\n" - " port,en\n" - " port,land,en_US\n" - " If you put the special locale, zz_ZZ on the list, it will perform\n" - " pseudolocalization on the default locale, modifying all of the\n" - " strings so you can look for strings that missed the\n" - " internationalization process. For example:\n" - " port,land,zz_ZZ\n" - " -d one or more device assets to include, separated by commas\n" - " -f force overwrite of existing files\n" - " -g specify a pixel tolerance to force images to grayscale, default 0\n" - " -j specify a jar or zip file containing classes to include\n" - " -k junk path of file(s) added\n" - " -m make package directories under location specified by -J\n" -#if 0 - " -p pseudolocalize the default configuration\n" -#endif - " -u update existing packages (add new, replace older, remove deleted files)\n" - " -v verbose output\n" - " -x create extending (non-application) resource IDs\n" - " -z require localization of resource attributes marked with\n" - " localization=\"suggested\"\n" - " -A additional directory in which to find raw asset files\n" - " -G A file to output proguard options into.\n" - " -F specify the apk file to output\n" - " -I add an existing package to base include set\n" - " -J specify where to output R.java resource constant definitions\n" - " -M specify full path to AndroidManifest.xml to include in zip\n" - " -P specify where to output public resource definitions\n" - " -S directory in which to find resources. Multiple directories will be scanned\n" - " and the first match found (left to right) will take precedence.\n" - " -0 specifies an additional extension for which such files will not\n" - " be stored compressed in the .apk. An empty string means to not\n" - " compress any files at all.\n" - " --debug-mode\n" - " inserts android:debuggable=\"true\" in to the application node of the\n" - " manifest, making the application debuggable even on production devices.\n" - " --include-meta-data\n" - " when used with \"dump badging\" also includes meta-data tags.\n" - " --min-sdk-version\n" - " inserts android:minSdkVersion in to manifest. If the version is 7 or\n" - " higher, the default encoding for resources will be in UTF-8.\n" - " --target-sdk-version\n" - " inserts android:targetSdkVersion in to manifest.\n" - " --max-res-version\n" - " ignores versioned resource directories above the given value.\n" - " --values\n" - " when used with \"dump resources\" also includes resource values.\n" - " --version-code\n" - " inserts android:versionCode in to manifest.\n" - " --version-name\n" - " inserts android:versionName in to manifest.\n" - " --custom-package\n" - " generates R.java into a different package.\n" - " --extra-packages\n" - " generate R.java for libraries. Separate libraries with ':'.\n" - " --generate-dependencies\n" - " generate dependency files in the same directories for R.java and resource package\n" - " --auto-add-overlay\n" - " Automatically add resources that are only in overlays.\n" - " --preferred-configurations\n" - " Like the -c option for filtering out unneeded configurations, but\n" - " only expresses a preference. If there is no resource available with\n" - " the preferred configuration then it will not be stripped.\n" - " --rename-manifest-package\n" - " Rewrite the manifest so that its package name is the package name\n" - " given here. Relative class names (for example .Foo) will be\n" - " changed to absolute names with the old package so that the code\n" - " does not need to change.\n" - " --rename-instrumentation-target-package\n" - " Rewrite the manifest so that all of its instrumentation\n" - " components target the given package. Useful when used in\n" - " conjunction with --rename-manifest-package to fix tests against\n" - " a package that has been renamed.\n" - " --product\n" - " Specifies which variant to choose for strings that have\n" - " product variants\n" - " --utf16\n" - " changes default encoding for resources to UTF-16. Only useful when API\n" - " level is set to 7 or higher where the default encoding is UTF-8.\n" - " --non-constant-id\n" - " Make the resources ID non constant. This is required to make an R java class\n" - " that does not contain the final value but is used to make reusable compiled\n" - " libraries that need to access resources.\n" - " --error-on-failed-insert\n" - " Forces aapt to return an error if it fails to insert values into the manifest\n" - " with --debug-mode, --min-sdk-version, --target-sdk-version --version-code\n" - " and --version-name.\n" - " Insertion typically fails if the manifest already defines the attribute.\n" - " --output-text-symbols\n" - " Generates a text file containing the resource symbols of the R class in the\n" - " specified folder.\n" - " --ignore-assets\n" - " Assets to be ignored. Default pattern is:\n" - " %s\n", - gDefaultIgnoreAssets); -} - -/* - * Dispatch the command. - */ -int handleCommand(Bundle* bundle) -{ - //printf("--- command %d (verbose=%d force=%d):\n", - // bundle->getCommand(), bundle->getVerbose(), bundle->getForce()); - //for (int i = 0; i < bundle->getFileSpecCount(); i++) - // printf(" %d: '%s'\n", i, bundle->getFileSpecEntry(i)); - - switch (bundle->getCommand()) { - case kCommandVersion: return doVersion(bundle); - case kCommandList: return doList(bundle); - case kCommandDump: return doDump(bundle); - case kCommandAdd: return doAdd(bundle); - case kCommandRemove: return doRemove(bundle); - case kCommandPackage: return doPackage(bundle); - case kCommandCrunch: return doCrunch(bundle); - case kCommandSingleCrunch: return doSingleCrunch(bundle); - default: - fprintf(stderr, "%s: requested command not yet supported\n", gProgName); - return 1; - } -} - -/* - * Parse args. - */ -int main(int argc, char* const argv[]) -{ - char *prog = argv[0]; - Bundle bundle; - bool wantUsage = false; - int result = 1; // pessimistically assume an error. - int tolerance = 0; - - /* default to compression */ - bundle.setCompressionMethod(ZipEntry::kCompressDeflated); - - if (argc < 2) { - wantUsage = true; - goto bail; - } - - if (argv[1][0] == 'v') - bundle.setCommand(kCommandVersion); - else if (argv[1][0] == 'd') - bundle.setCommand(kCommandDump); - else if (argv[1][0] == 'l') - bundle.setCommand(kCommandList); - else if (argv[1][0] == 'a') - bundle.setCommand(kCommandAdd); - else if (argv[1][0] == 'r') - bundle.setCommand(kCommandRemove); - else if (argv[1][0] == 'p') - bundle.setCommand(kCommandPackage); - else if (argv[1][0] == 'c') - bundle.setCommand(kCommandCrunch); - else if (argv[1][0] == 's') - bundle.setCommand(kCommandSingleCrunch); - else { - fprintf(stderr, "ERROR: Unknown command '%s'\n", argv[1]); - wantUsage = true; - goto bail; - } - argc -= 2; - argv += 2; - - /* - * Pull out flags. We support "-fv" and "-f -v". - */ - while (argc && argv[0][0] == '-') { - /* flag(s) found */ - const char* cp = argv[0] +1; - - while (*cp != '\0') { - switch (*cp) { - case 'v': - bundle.setVerbose(true); - break; - case 'a': - bundle.setAndroidList(true); - break; - case 'c': - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '-c' option\n"); - wantUsage = true; - goto bail; - } - bundle.addConfigurations(argv[0]); - break; - case 'f': - bundle.setForce(true); - break; - case 'g': - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '-g' option\n"); - wantUsage = true; - goto bail; - } - tolerance = atoi(argv[0]); - bundle.setGrayscaleTolerance(tolerance); - printf("%s: Images with deviation <= %d will be forced to grayscale.\n", prog, tolerance); - break; - case 'k': - bundle.setJunkPath(true); - break; - case 'm': - bundle.setMakePackageDirs(true); - break; -#if 0 - case 'p': - bundle.setPseudolocalize(true); - break; -#endif - case 'u': - bundle.setUpdate(true); - break; - case 'x': - bundle.setExtending(true); - break; - case 'z': - bundle.setRequireLocalization(true); - break; - case 'j': - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '-j' option\n"); - wantUsage = true; - goto bail; - } - convertPath(argv[0]); - bundle.addJarFile(argv[0]); - break; - case 'A': - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '-A' option\n"); - wantUsage = true; - goto bail; - } - convertPath(argv[0]); - bundle.setAssetSourceDir(argv[0]); - break; - case 'G': - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '-G' option\n"); - wantUsage = true; - goto bail; - } - convertPath(argv[0]); - bundle.setProguardFile(argv[0]); - break; - case 'I': - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '-I' option\n"); - wantUsage = true; - goto bail; - } - convertPath(argv[0]); - bundle.addPackageInclude(argv[0]); - break; - case 'F': - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '-F' option\n"); - wantUsage = true; - goto bail; - } - convertPath(argv[0]); - bundle.setOutputAPKFile(argv[0]); - break; - case 'J': - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '-J' option\n"); - wantUsage = true; - goto bail; - } - convertPath(argv[0]); - bundle.setRClassDir(argv[0]); - break; - case 'M': - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '-M' option\n"); - wantUsage = true; - goto bail; - } - convertPath(argv[0]); - bundle.setAndroidManifestFile(argv[0]); - break; - case 'P': - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '-P' option\n"); - wantUsage = true; - goto bail; - } - convertPath(argv[0]); - bundle.setPublicOutputFile(argv[0]); - break; - case 'S': - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '-S' option\n"); - wantUsage = true; - goto bail; - } - convertPath(argv[0]); - bundle.addResourceSourceDir(argv[0]); - break; - case 'C': - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '-C' option\n"); - wantUsage = true; - goto bail; - } - convertPath(argv[0]); - bundle.setCrunchedOutputDir(argv[0]); - break; - case 'i': - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '-i' option\n"); - wantUsage = true; - goto bail; - } - convertPath(argv[0]); - bundle.setSingleCrunchInputFile(argv[0]); - break; - case 'o': - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '-o' option\n"); - wantUsage = true; - goto bail; - } - convertPath(argv[0]); - bundle.setSingleCrunchOutputFile(argv[0]); - break; - case '0': - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '-e' option\n"); - wantUsage = true; - goto bail; - } - if (argv[0][0] != 0) { - bundle.addNoCompressExtension(argv[0]); - } else { - bundle.setCompressionMethod(ZipEntry::kCompressStored); - } - break; - case '-': - if (strcmp(cp, "-debug-mode") == 0) { - bundle.setDebugMode(true); - } else if (strcmp(cp, "-min-sdk-version") == 0) { - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '--min-sdk-version' option\n"); - wantUsage = true; - goto bail; - } - bundle.setMinSdkVersion(argv[0]); - } else if (strcmp(cp, "-target-sdk-version") == 0) { - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '--target-sdk-version' option\n"); - wantUsage = true; - goto bail; - } - bundle.setTargetSdkVersion(argv[0]); - } else if (strcmp(cp, "-max-sdk-version") == 0) { - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '--max-sdk-version' option\n"); - wantUsage = true; - goto bail; - } - bundle.setMaxSdkVersion(argv[0]); - } else if (strcmp(cp, "-max-res-version") == 0) { - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '--max-res-version' option\n"); - wantUsage = true; - goto bail; - } - bundle.setMaxResVersion(argv[0]); - } else if (strcmp(cp, "-version-code") == 0) { - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '--version-code' option\n"); - wantUsage = true; - goto bail; - } - bundle.setVersionCode(argv[0]); - } else if (strcmp(cp, "-version-name") == 0) { - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '--version-name' option\n"); - wantUsage = true; - goto bail; - } - bundle.setVersionName(argv[0]); - } else if (strcmp(cp, "-values") == 0) { - bundle.setValues(true); - } else if (strcmp(cp, "-include-meta-data") == 0) { - bundle.setIncludeMetaData(true); - } else if (strcmp(cp, "-custom-package") == 0) { - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '--custom-package' option\n"); - wantUsage = true; - goto bail; - } - bundle.setCustomPackage(argv[0]); - } else if (strcmp(cp, "-extra-packages") == 0) { - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '--extra-packages' option\n"); - wantUsage = true; - goto bail; - } - bundle.setExtraPackages(argv[0]); - } else if (strcmp(cp, "-generate-dependencies") == 0) { - bundle.setGenDependencies(true); - } else if (strcmp(cp, "-utf16") == 0) { - bundle.setWantUTF16(true); - } else if (strcmp(cp, "-preferred-configurations") == 0) { - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '--preferred-configurations' option\n"); - wantUsage = true; - goto bail; - } - bundle.addPreferredConfigurations(argv[0]); - } else if (strcmp(cp, "-rename-manifest-package") == 0) { - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '--rename-manifest-package' option\n"); - wantUsage = true; - goto bail; - } - bundle.setManifestPackageNameOverride(argv[0]); - } else if (strcmp(cp, "-rename-instrumentation-target-package") == 0) { - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '--rename-instrumentation-target-package' option\n"); - wantUsage = true; - goto bail; - } - bundle.setInstrumentationPackageNameOverride(argv[0]); - } else if (strcmp(cp, "-auto-add-overlay") == 0) { - bundle.setAutoAddOverlay(true); - } else if (strcmp(cp, "-error-on-failed-insert") == 0) { - bundle.setErrorOnFailedInsert(true); - } else if (strcmp(cp, "-output-text-symbols") == 0) { - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '-output-text-symbols' option\n"); - wantUsage = true; - goto bail; - } - bundle.setOutputTextSymbols(argv[0]); - } else if (strcmp(cp, "-product") == 0) { - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '--product' option\n"); - wantUsage = true; - goto bail; - } - bundle.setProduct(argv[0]); - } else if (strcmp(cp, "-non-constant-id") == 0) { - bundle.setNonConstantId(true); - } else if (strcmp(cp, "-no-crunch") == 0) { - bundle.setUseCrunchCache(true); - } else if (strcmp(cp, "-ignore-assets") == 0) { - argc--; - argv++; - if (!argc) { - fprintf(stderr, "ERROR: No argument supplied for '--ignore-assets' option\n"); - wantUsage = true; - goto bail; - } - gUserIgnoreAssets = argv[0]; - } else { - fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp); - wantUsage = true; - goto bail; - } - cp += strlen(cp) - 1; - break; - default: - fprintf(stderr, "ERROR: Unknown flag '-%c'\n", *cp); - wantUsage = true; - goto bail; - } - - cp++; - } - argc--; - argv++; - } - - /* - * We're past the flags. The rest all goes straight in. - */ - bundle.setFileSpec(argv, argc); - - result = handleCommand(&bundle); - -bail: - if (wantUsage) { - usage(); - result = 2; - } - - //printf("--> returning %d\n", result); - return result; -} diff --git a/tools/aapt/Main.h b/tools/aapt/Main.h deleted file mode 100644 index a6b39ac..0000000 --- a/tools/aapt/Main.h +++ /dev/null @@ -1,63 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Some global defines that don't really merit their own header. -// -#ifndef __MAIN_H -#define __MAIN_H - -#include <utils/Log.h> -#include <utils/threads.h> -#include <utils/List.h> -#include <utils/Errors.h> -#include "Bundle.h" -#include "AaptAssets.h" -#include "ZipFile.h" - - -/* Benchmarking Flag */ -//#define BENCHMARK 1 - -#if BENCHMARK - #include <time.h> -#endif /* BENCHMARK */ - -extern int doVersion(Bundle* bundle); -extern int doList(Bundle* bundle); -extern int doDump(Bundle* bundle); -extern int doAdd(Bundle* bundle); -extern int doRemove(Bundle* bundle); -extern int doPackage(Bundle* bundle); -extern int doCrunch(Bundle* bundle); -extern int doSingleCrunch(Bundle* bundle); - -extern int calcPercent(long uncompressedLen, long compressedLen); - -extern android::status_t writeAPK(Bundle* bundle, - const sp<AaptAssets>& assets, - const android::String8& outputFile); - -extern android::status_t updatePreProcessedCache(Bundle* bundle); - -extern android::status_t buildResources(Bundle* bundle, - const sp<AaptAssets>& assets); - -extern android::status_t writeResourceSymbols(Bundle* bundle, - const sp<AaptAssets>& assets, const String8& pkgName, bool includePrivate); - -extern android::status_t writeProguardFile(Bundle* bundle, const sp<AaptAssets>& assets); - -extern bool isValidResourceType(const String8& type); - -ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptAssets>& assets); - -extern status_t filterResources(Bundle* bundle, const sp<AaptAssets>& assets); - -int dumpResources(Bundle* bundle); - -String8 getAttribute(const ResXMLTree& tree, const char* ns, - const char* attr, String8* outError); - -status_t writeDependencyPreReqs(Bundle* bundle, const sp<AaptAssets>& assets, - FILE* fp, bool includeRaw); -#endif // __MAIN_H diff --git a/tools/aapt/NOTICE b/tools/aapt/NOTICE deleted file mode 100644 index c5b1efa..0000000 --- a/tools/aapt/NOTICE +++ /dev/null @@ -1,190 +0,0 @@ - - Copyright (c) 2005-2008, The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp deleted file mode 100644 index 872d95c..0000000 --- a/tools/aapt/Package.cpp +++ /dev/null @@ -1,505 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Package assets into Zip files. -// -#include "Main.h" -#include "AaptAssets.h" -#include "ResourceTable.h" -#include "ResourceFilter.h" - -#include <androidfw/misc.h> - -#include <utils/Log.h> -#include <utils/threads.h> -#include <utils/List.h> -#include <utils/Errors.h> -#include <utils/misc.h> - -#include <sys/types.h> -#include <dirent.h> -#include <ctype.h> -#include <errno.h> - -using namespace android; - -static const char* kExcludeExtension = ".EXCLUDE"; - -/* these formats are already compressed, or don't compress well */ -static const char* kNoCompressExt[] = { - ".jpg", ".jpeg", ".png", ".gif", - ".wav", ".mp2", ".mp3", ".ogg", ".aac", - ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet", - ".rtttl", ".imy", ".xmf", ".mp4", ".m4a", - ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2", - ".amr", ".awb", ".wma", ".wmv" -}; - -/* fwd decls, so I can write this downward */ -ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptAssets>& assets); -ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptDir>& dir, - const AaptGroupEntry& ge, const ResourceFilter* filter); -bool processFile(Bundle* bundle, ZipFile* zip, - const sp<AaptGroup>& group, const sp<AaptFile>& file); -bool okayToCompress(Bundle* bundle, const String8& pathName); -ssize_t processJarFiles(Bundle* bundle, ZipFile* zip); - -/* - * The directory hierarchy looks like this: - * "outputDir" and "assetRoot" are existing directories. - * - * On success, "bundle->numPackages" will be the number of Zip packages - * we created. - */ -status_t writeAPK(Bundle* bundle, const sp<AaptAssets>& assets, - const String8& outputFile) -{ - #if BENCHMARK - fprintf(stdout, "BENCHMARK: Starting APK Bundling \n"); - long startAPKTime = clock(); - #endif /* BENCHMARK */ - - status_t result = NO_ERROR; - ZipFile* zip = NULL; - int count; - - //bundle->setPackageCount(0); - - /* - * Prep the Zip archive. - * - * If the file already exists, fail unless "update" or "force" is set. - * If "update" is set, update the contents of the existing archive. - * Else, if "force" is set, remove the existing archive. - */ - FileType fileType = getFileType(outputFile.string()); - if (fileType == kFileTypeNonexistent) { - // okay, create it below - } else if (fileType == kFileTypeRegular) { - if (bundle->getUpdate()) { - // okay, open it below - } else if (bundle->getForce()) { - if (unlink(outputFile.string()) != 0) { - fprintf(stderr, "ERROR: unable to remove '%s': %s\n", outputFile.string(), - strerror(errno)); - goto bail; - } - } else { - fprintf(stderr, "ERROR: '%s' exists (use '-f' to force overwrite)\n", - outputFile.string()); - goto bail; - } - } else { - fprintf(stderr, "ERROR: '%s' exists and is not a regular file\n", outputFile.string()); - goto bail; - } - - if (bundle->getVerbose()) { - printf("%s '%s'\n", (fileType == kFileTypeNonexistent) ? "Creating" : "Opening", - outputFile.string()); - } - - status_t status; - zip = new ZipFile; - status = zip->open(outputFile.string(), ZipFile::kOpenReadWrite | ZipFile::kOpenCreate); - if (status != NO_ERROR) { - fprintf(stderr, "ERROR: unable to open '%s' as Zip file for writing\n", - outputFile.string()); - goto bail; - } - - if (bundle->getVerbose()) { - printf("Writing all files...\n"); - } - - count = processAssets(bundle, zip, assets); - if (count < 0) { - fprintf(stderr, "ERROR: unable to process assets while packaging '%s'\n", - outputFile.string()); - result = count; - goto bail; - } - - if (bundle->getVerbose()) { - printf("Generated %d file%s\n", count, (count==1) ? "" : "s"); - } - - count = processJarFiles(bundle, zip); - if (count < 0) { - fprintf(stderr, "ERROR: unable to process jar files while packaging '%s'\n", - outputFile.string()); - result = count; - goto bail; - } - - if (bundle->getVerbose()) - printf("Included %d file%s from jar/zip files.\n", count, (count==1) ? "" : "s"); - - result = NO_ERROR; - - /* - * Check for cruft. We set the "marked" flag on all entries we created - * or decided not to update. If the entry isn't already slated for - * deletion, remove it now. - */ - { - if (bundle->getVerbose()) - printf("Checking for deleted files\n"); - int i, removed = 0; - for (i = 0; i < zip->getNumEntries(); i++) { - ZipEntry* entry = zip->getEntryByIndex(i); - - if (!entry->getMarked() && entry->getDeleted()) { - if (bundle->getVerbose()) { - printf(" (removing crufty '%s')\n", - entry->getFileName()); - } - zip->remove(entry); - removed++; - } - } - if (bundle->getVerbose() && removed > 0) - printf("Removed %d file%s\n", removed, (removed==1) ? "" : "s"); - } - - /* tell Zip lib to process deletions and other pending changes */ - result = zip->flush(); - if (result != NO_ERROR) { - fprintf(stderr, "ERROR: Zip flush failed, archive may be hosed\n"); - goto bail; - } - - /* anything here? */ - if (zip->getNumEntries() == 0) { - if (bundle->getVerbose()) { - printf("Archive is empty -- removing %s\n", outputFile.getPathLeaf().string()); - } - delete zip; // close the file so we can remove it in Win32 - zip = NULL; - if (unlink(outputFile.string()) != 0) { - fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.string()); - } - } - - // If we've been asked to generate a dependency file for the .ap_ package, - // do so here - if (bundle->getGenDependencies()) { - // The dependency file gets output to the same directory - // as the specified output file with an additional .d extension. - // e.g. bin/resources.ap_.d - String8 dependencyFile = outputFile; - dependencyFile.append(".d"); - - FILE* fp = fopen(dependencyFile.string(), "a"); - // Add this file to the dependency file - fprintf(fp, "%s \\\n", outputFile.string()); - fclose(fp); - } - - assert(result == NO_ERROR); - -bail: - delete zip; // must close before remove in Win32 - if (result != NO_ERROR) { - if (bundle->getVerbose()) { - printf("Removing %s due to earlier failures\n", outputFile.string()); - } - if (unlink(outputFile.string()) != 0) { - fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.string()); - } - } - - if (result == NO_ERROR && bundle->getVerbose()) - printf("Done!\n"); - - #if BENCHMARK - fprintf(stdout, "BENCHMARK: End APK Bundling. Time Elapsed: %f ms \n",(clock() - startAPKTime)/1000.0); - #endif /* BENCHMARK */ - return result; -} - -ssize_t processAssets(Bundle* bundle, ZipFile* zip, - const sp<AaptAssets>& assets) -{ - ResourceFilter filter; - status_t status = filter.parse(bundle->getConfigurations()); - if (status != NO_ERROR) { - return -1; - } - - ssize_t count = 0; - - const size_t N = assets->getGroupEntries().size(); - for (size_t i=0; i<N; i++) { - const AaptGroupEntry& ge = assets->getGroupEntries()[i]; - - ssize_t res = processAssets(bundle, zip, assets, ge, &filter); - if (res < 0) { - return res; - } - - count += res; - } - - return count; -} - -ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptDir>& dir, - const AaptGroupEntry& ge, const ResourceFilter* filter) -{ - ssize_t count = 0; - - const size_t ND = dir->getDirs().size(); - size_t i; - for (i=0; i<ND; i++) { - const sp<AaptDir>& subDir = dir->getDirs().valueAt(i); - - const bool filterable = filter != NULL && subDir->getLeaf().find("mipmap-") != 0; - - if (filterable && subDir->getLeaf() != subDir->getPath() && !filter->match(ge.toParams())) { - continue; - } - - ssize_t res = processAssets(bundle, zip, subDir, ge, filterable ? filter : NULL); - if (res < 0) { - return res; - } - count += res; - } - - if (filter != NULL && !filter->match(ge.toParams())) { - return count; - } - - const size_t NF = dir->getFiles().size(); - for (i=0; i<NF; i++) { - sp<AaptGroup> gp = dir->getFiles().valueAt(i); - ssize_t fi = gp->getFiles().indexOfKey(ge); - if (fi >= 0) { - sp<AaptFile> fl = gp->getFiles().valueAt(fi); - if (!processFile(bundle, zip, gp, fl)) { - return UNKNOWN_ERROR; - } - count++; - } - } - - return count; -} - -/* - * Process a regular file, adding it to the archive if appropriate. - * - * If we're in "update" mode, and the file already exists in the archive, - * delete the existing entry before adding the new one. - */ -bool processFile(Bundle* bundle, ZipFile* zip, - const sp<AaptGroup>& group, const sp<AaptFile>& file) -{ - const bool hasData = file->hasData(); - - String8 storageName(group->getPath()); - storageName.convertToResPath(); - ZipEntry* entry; - bool fromGzip = false; - status_t result; - - /* - * See if the filename ends in ".EXCLUDE". We can't use - * String8::getPathExtension() because the length of what it considers - * to be an extension is capped. - * - * The Asset Manager doesn't check for ".EXCLUDE" in Zip archives, - * so there's no value in adding them (and it makes life easier on - * the AssetManager lib if we don't). - * - * NOTE: this restriction has been removed. If you're in this code, you - * should clean this up, but I'm in here getting rid of Path Name, and I - * don't want to make other potentially breaking changes --joeo - */ - int fileNameLen = storageName.length(); - int excludeExtensionLen = strlen(kExcludeExtension); - if (fileNameLen > excludeExtensionLen - && (0 == strcmp(storageName.string() + (fileNameLen - excludeExtensionLen), - kExcludeExtension))) { - fprintf(stderr, "warning: '%s' not added to Zip\n", storageName.string()); - return true; - } - - if (strcasecmp(storageName.getPathExtension().string(), ".gz") == 0) { - fromGzip = true; - storageName = storageName.getBasePath(); - } - - if (bundle->getUpdate()) { - entry = zip->getEntryByName(storageName.string()); - if (entry != NULL) { - /* file already exists in archive; there can be only one */ - if (entry->getMarked()) { - fprintf(stderr, - "ERROR: '%s' exists twice (check for with & w/o '.gz'?)\n", - file->getPrintableSource().string()); - return false; - } - if (!hasData) { - const String8& srcName = file->getSourceFile(); - time_t fileModWhen; - fileModWhen = getFileModDate(srcName.string()); - if (fileModWhen == (time_t) -1) { // file existence tested earlier, - return false; // not expecting an error here - } - - if (fileModWhen > entry->getModWhen()) { - // mark as deleted so add() will succeed - if (bundle->getVerbose()) { - printf(" (removing old '%s')\n", storageName.string()); - } - - zip->remove(entry); - } else { - // version in archive is newer - if (bundle->getVerbose()) { - printf(" (not updating '%s')\n", storageName.string()); - } - entry->setMarked(true); - return true; - } - } else { - // Generated files are always replaced. - zip->remove(entry); - } - } - } - - //android_setMinPriority(NULL, ANDROID_LOG_VERBOSE); - - if (fromGzip) { - result = zip->addGzip(file->getSourceFile().string(), storageName.string(), &entry); - } else if (!hasData) { - /* don't compress certain files, e.g. PNGs */ - int compressionMethod = bundle->getCompressionMethod(); - if (!okayToCompress(bundle, storageName)) { - compressionMethod = ZipEntry::kCompressStored; - } - result = zip->add(file->getSourceFile().string(), storageName.string(), compressionMethod, - &entry); - } else { - result = zip->add(file->getData(), file->getSize(), storageName.string(), - file->getCompressionMethod(), &entry); - } - if (result == NO_ERROR) { - if (bundle->getVerbose()) { - printf(" '%s'%s", storageName.string(), fromGzip ? " (from .gz)" : ""); - if (entry->getCompressionMethod() == ZipEntry::kCompressStored) { - printf(" (not compressed)\n"); - } else { - printf(" (compressed %d%%)\n", calcPercent(entry->getUncompressedLen(), - entry->getCompressedLen())); - } - } - entry->setMarked(true); - } else { - if (result == ALREADY_EXISTS) { - fprintf(stderr, " Unable to add '%s': file already in archive (try '-u'?)\n", - file->getPrintableSource().string()); - } else { - fprintf(stderr, " Unable to add '%s': Zip add failed\n", - file->getPrintableSource().string()); - } - return false; - } - - return true; -} - -/* - * Determine whether or not we want to try to compress this file based - * on the file extension. - */ -bool okayToCompress(Bundle* bundle, const String8& pathName) -{ - String8 ext = pathName.getPathExtension(); - int i; - - if (ext.length() == 0) - return true; - - for (i = 0; i < NELEM(kNoCompressExt); i++) { - if (strcasecmp(ext.string(), kNoCompressExt[i]) == 0) - return false; - } - - const android::Vector<const char*>& others(bundle->getNoCompressExtensions()); - for (i = 0; i < (int)others.size(); i++) { - const char* str = others[i]; - int pos = pathName.length() - strlen(str); - if (pos < 0) { - continue; - } - const char* path = pathName.string(); - if (strcasecmp(path + pos, str) == 0) { - return false; - } - } - - return true; -} - -bool endsWith(const char* haystack, const char* needle) -{ - size_t a = strlen(haystack); - size_t b = strlen(needle); - if (a < b) return false; - return strcasecmp(haystack+(a-b), needle) == 0; -} - -ssize_t processJarFile(ZipFile* jar, ZipFile* out) -{ - status_t err; - size_t N = jar->getNumEntries(); - size_t count = 0; - for (size_t i=0; i<N; i++) { - ZipEntry* entry = jar->getEntryByIndex(i); - const char* storageName = entry->getFileName(); - if (endsWith(storageName, ".class")) { - int compressionMethod = entry->getCompressionMethod(); - size_t size = entry->getUncompressedLen(); - const void* data = jar->uncompress(entry); - if (data == NULL) { - fprintf(stderr, "ERROR: unable to uncompress entry '%s'\n", - storageName); - return -1; - } - out->add(data, size, storageName, compressionMethod, NULL); - free((void*)data); - } - count++; - } - return count; -} - -ssize_t processJarFiles(Bundle* bundle, ZipFile* zip) -{ - status_t err; - ssize_t count = 0; - const android::Vector<const char*>& jars = bundle->getJarFiles(); - - size_t N = jars.size(); - for (size_t i=0; i<N; i++) { - ZipFile jar; - err = jar.open(jars[i], ZipFile::kOpenReadOnly); - if (err != 0) { - fprintf(stderr, "ERROR: unable to open '%s' as a zip file: %d\n", - jars[i], err); - return err; - } - err += processJarFile(&jar, zip); - if (err < 0) { - fprintf(stderr, "ERROR: unable to process '%s'\n", jars[i]); - return err; - } - count += err; - } - - return count; -} diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp deleted file mode 100644 index d617928..0000000 --- a/tools/aapt/Resource.cpp +++ /dev/null @@ -1,2676 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Build resource files from raw assets. -// -#include "Main.h" -#include "AaptAssets.h" -#include "StringPool.h" -#include "XMLNode.h" -#include "ResourceTable.h" -#include "Images.h" - -#include "CrunchCache.h" -#include "FileFinder.h" -#include "CacheUpdater.h" - -#include "WorkQueue.h" - -#if HAVE_PRINTF_ZD -# define ZD "%zd" -# define ZD_TYPE ssize_t -#else -# define ZD "%ld" -# define ZD_TYPE long -#endif - -#define NOISY(x) // x - -// Number of threads to use for preprocessing images. -static const size_t MAX_THREADS = 4; - -// ========================================================================== -// ========================================================================== -// ========================================================================== - -class PackageInfo -{ -public: - PackageInfo() - { - } - ~PackageInfo() - { - } - - status_t parsePackage(const sp<AaptGroup>& grp); -}; - -// ========================================================================== -// ========================================================================== -// ========================================================================== - -static String8 parseResourceName(const String8& leaf) -{ - const char* firstDot = strchr(leaf.string(), '.'); - const char* str = leaf.string(); - - if (firstDot) { - return String8(str, firstDot-str); - } else { - return String8(str); - } -} - -ResourceTypeSet::ResourceTypeSet() - :RefBase(), - KeyedVector<String8,sp<AaptGroup> >() -{ -} - -FilePathStore::FilePathStore() - :RefBase(), - Vector<String8>() -{ -} - -class ResourceDirIterator -{ -public: - ResourceDirIterator(const sp<ResourceTypeSet>& set, const String8& resType) - : mResType(resType), mSet(set), mSetPos(0), mGroupPos(0) - { - } - - inline const sp<AaptGroup>& getGroup() const { return mGroup; } - inline const sp<AaptFile>& getFile() const { return mFile; } - - inline const String8& getBaseName() const { return mBaseName; } - inline const String8& getLeafName() const { return mLeafName; } - inline String8 getPath() const { return mPath; } - inline const ResTable_config& getParams() const { return mParams; } - - enum { - EOD = 1 - }; - - ssize_t next() - { - while (true) { - sp<AaptGroup> group; - sp<AaptFile> file; - - // Try to get next file in this current group. - if (mGroup != NULL && mGroupPos < mGroup->getFiles().size()) { - group = mGroup; - file = group->getFiles().valueAt(mGroupPos++); - - // Try to get the next group/file in this directory - } else if (mSetPos < mSet->size()) { - mGroup = group = mSet->valueAt(mSetPos++); - if (group->getFiles().size() < 1) { - continue; - } - file = group->getFiles().valueAt(0); - mGroupPos = 1; - - // All done! - } else { - return EOD; - } - - mFile = file; - - String8 leaf(group->getLeaf()); - mLeafName = String8(leaf); - mParams = file->getGroupEntry().toParams(); - NOISY(printf("Dir %s: mcc=%d mnc=%d lang=%c%c cnt=%c%c orient=%d ui=%d density=%d touch=%d key=%d inp=%d nav=%d\n", - group->getPath().string(), mParams.mcc, mParams.mnc, - mParams.language[0] ? mParams.language[0] : '-', - mParams.language[1] ? mParams.language[1] : '-', - mParams.country[0] ? mParams.country[0] : '-', - mParams.country[1] ? mParams.country[1] : '-', - mParams.orientation, mParams.uiMode, - mParams.density, mParams.touchscreen, mParams.keyboard, - mParams.inputFlags, mParams.navigation)); - mPath = "res"; - mPath.appendPath(file->getGroupEntry().toDirName(mResType)); - mPath.appendPath(leaf); - mBaseName = parseResourceName(leaf); - if (mBaseName == "") { - fprintf(stderr, "Error: malformed resource filename %s\n", - file->getPrintableSource().string()); - return UNKNOWN_ERROR; - } - - NOISY(printf("file name=%s\n", mBaseName.string())); - - return NO_ERROR; - } - } - -private: - String8 mResType; - - const sp<ResourceTypeSet> mSet; - size_t mSetPos; - - sp<AaptGroup> mGroup; - size_t mGroupPos; - - sp<AaptFile> mFile; - String8 mBaseName; - String8 mLeafName; - String8 mPath; - ResTable_config mParams; -}; - -// ========================================================================== -// ========================================================================== -// ========================================================================== - -bool isValidResourceType(const String8& type) -{ - return type == "anim" || type == "animator" || type == "interpolator" - || type == "transition" || type == "scene" - || type == "drawable" || type == "layout" - || type == "values" || type == "xml" || type == "raw" - || type == "color" || type == "menu" || type == "mipmap"; -} - -static sp<AaptFile> getResourceFile(const sp<AaptAssets>& assets, bool makeIfNecessary=true) -{ - sp<AaptGroup> group = assets->getFiles().valueFor(String8("resources.arsc")); - sp<AaptFile> file; - if (group != NULL) { - file = group->getFiles().valueFor(AaptGroupEntry()); - if (file != NULL) { - return file; - } - } - - if (!makeIfNecessary) { - return NULL; - } - return assets->addFile(String8("resources.arsc"), AaptGroupEntry(), String8(), - NULL, String8()); -} - -static status_t parsePackage(Bundle* bundle, const sp<AaptAssets>& assets, - const sp<AaptGroup>& grp) -{ - if (grp->getFiles().size() != 1) { - fprintf(stderr, "warning: Multiple AndroidManifest.xml files found, using %s\n", - grp->getFiles().valueAt(0)->getPrintableSource().string()); - } - - sp<AaptFile> file = grp->getFiles().valueAt(0); - - ResXMLTree block; - status_t err = parseXMLResource(file, &block); - if (err != NO_ERROR) { - return err; - } - //printXMLBlock(&block); - - ResXMLTree::event_code_t code; - while ((code=block.next()) != ResXMLTree::START_TAG - && code != ResXMLTree::END_DOCUMENT - && code != ResXMLTree::BAD_DOCUMENT) { - } - - size_t len; - if (code != ResXMLTree::START_TAG) { - fprintf(stderr, "%s:%d: No start tag found\n", - file->getPrintableSource().string(), block.getLineNumber()); - return UNKNOWN_ERROR; - } - if (strcmp16(block.getElementName(&len), String16("manifest").string()) != 0) { - fprintf(stderr, "%s:%d: Invalid start tag %s, expected <manifest>\n", - file->getPrintableSource().string(), block.getLineNumber(), - String8(block.getElementName(&len)).string()); - return UNKNOWN_ERROR; - } - - ssize_t nameIndex = block.indexOfAttribute(NULL, "package"); - if (nameIndex < 0) { - fprintf(stderr, "%s:%d: <manifest> does not have package attribute.\n", - file->getPrintableSource().string(), block.getLineNumber()); - return UNKNOWN_ERROR; - } - - assets->setPackage(String8(block.getAttributeStringValue(nameIndex, &len))); - - String16 uses_sdk16("uses-sdk"); - while ((code=block.next()) != ResXMLTree::END_DOCUMENT - && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::START_TAG) { - if (strcmp16(block.getElementName(&len), uses_sdk16.string()) == 0) { - ssize_t minSdkIndex = block.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE, - "minSdkVersion"); - if (minSdkIndex >= 0) { - const uint16_t* minSdk16 = block.getAttributeStringValue(minSdkIndex, &len); - const char* minSdk8 = strdup(String8(minSdk16).string()); - bundle->setManifestMinSdkVersion(minSdk8); - } - } - } - } - - return NO_ERROR; -} - -// ========================================================================== -// ========================================================================== -// ========================================================================== - -static status_t makeFileResources(Bundle* bundle, const sp<AaptAssets>& assets, - ResourceTable* table, - const sp<ResourceTypeSet>& set, - const char* resType) -{ - String8 type8(resType); - String16 type16(resType); - - bool hasErrors = false; - - ResourceDirIterator it(set, String8(resType)); - ssize_t res; - while ((res=it.next()) == NO_ERROR) { - if (bundle->getVerbose()) { - printf(" (new resource id %s from %s)\n", - it.getBaseName().string(), it.getFile()->getPrintableSource().string()); - } - String16 baseName(it.getBaseName()); - const char16_t* str = baseName.string(); - const char16_t* const end = str + baseName.size(); - while (str < end) { - if (!((*str >= 'a' && *str <= 'z') - || (*str >= '0' && *str <= '9') - || *str == '_' || *str == '.')) { - fprintf(stderr, "%s: Invalid file name: must contain only [a-z0-9_.]\n", - it.getPath().string()); - hasErrors = true; - } - str++; - } - String8 resPath = it.getPath(); - resPath.convertToResPath(); - table->addEntry(SourcePos(it.getPath(), 0), String16(assets->getPackage()), - type16, - baseName, - String16(resPath), - NULL, - &it.getParams()); - assets->addResource(it.getLeafName(), resPath, it.getFile(), type8); - } - - return hasErrors ? UNKNOWN_ERROR : NO_ERROR; -} - -class PreProcessImageWorkUnit : public WorkQueue::WorkUnit { -public: - PreProcessImageWorkUnit(const Bundle* bundle, const sp<AaptAssets>& assets, - const sp<AaptFile>& file, volatile bool* hasErrors) : - mBundle(bundle), mAssets(assets), mFile(file), mHasErrors(hasErrors) { - } - - virtual bool run() { - status_t status = preProcessImage(mBundle, mAssets, mFile, NULL); - if (status) { - *mHasErrors = true; - } - return true; // continue even if there are errors - } - -private: - const Bundle* mBundle; - sp<AaptAssets> mAssets; - sp<AaptFile> mFile; - volatile bool* mHasErrors; -}; - -static status_t preProcessImages(const Bundle* bundle, const sp<AaptAssets>& assets, - const sp<ResourceTypeSet>& set, const char* type) -{ - volatile bool hasErrors = false; - ssize_t res = NO_ERROR; - if (bundle->getUseCrunchCache() == false) { - WorkQueue wq(MAX_THREADS, false); - ResourceDirIterator it(set, String8(type)); - while ((res=it.next()) == NO_ERROR) { - PreProcessImageWorkUnit* w = new PreProcessImageWorkUnit( - bundle, assets, it.getFile(), &hasErrors); - status_t status = wq.schedule(w); - if (status) { - fprintf(stderr, "preProcessImages failed: schedule() returned %d\n", status); - hasErrors = true; - delete w; - break; - } - } - status_t status = wq.finish(); - if (status) { - fprintf(stderr, "preProcessImages failed: finish() returned %d\n", status); - hasErrors = true; - } - } - return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR; -} - -status_t postProcessImages(const sp<AaptAssets>& assets, - ResourceTable* table, - const sp<ResourceTypeSet>& set) -{ - ResourceDirIterator it(set, String8("drawable")); - bool hasErrors = false; - ssize_t res; - while ((res=it.next()) == NO_ERROR) { - res = postProcessImage(assets, table, it.getFile()); - if (res < NO_ERROR) { - hasErrors = true; - } - } - - return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR; -} - -static void collect_files(const sp<AaptDir>& dir, - KeyedVector<String8, sp<ResourceTypeSet> >* resources) -{ - const DefaultKeyedVector<String8, sp<AaptGroup> >& groups = dir->getFiles(); - int N = groups.size(); - for (int i=0; i<N; i++) { - String8 leafName = groups.keyAt(i); - const sp<AaptGroup>& group = groups.valueAt(i); - - const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& files - = group->getFiles(); - - if (files.size() == 0) { - continue; - } - - String8 resType = files.valueAt(0)->getResourceType(); - - ssize_t index = resources->indexOfKey(resType); - - if (index < 0) { - sp<ResourceTypeSet> set = new ResourceTypeSet(); - NOISY(printf("Creating new resource type set for leaf %s with group %s (%p)\n", - leafName.string(), group->getPath().string(), group.get())); - set->add(leafName, group); - resources->add(resType, set); - } else { - sp<ResourceTypeSet> set = resources->valueAt(index); - index = set->indexOfKey(leafName); - if (index < 0) { - NOISY(printf("Adding to resource type set for leaf %s group %s (%p)\n", - leafName.string(), group->getPath().string(), group.get())); - set->add(leafName, group); - } else { - sp<AaptGroup> existingGroup = set->valueAt(index); - NOISY(printf("Extending to resource type set for leaf %s group %s (%p)\n", - leafName.string(), group->getPath().string(), group.get())); - for (size_t j=0; j<files.size(); j++) { - NOISY(printf("Adding file %s in group %s resType %s\n", - files.valueAt(j)->getSourceFile().string(), - files.keyAt(j).toDirName(String8()).string(), - resType.string())); - status_t err = existingGroup->addFile(files.valueAt(j)); - } - } - } - } -} - -static void collect_files(const sp<AaptAssets>& ass, - KeyedVector<String8, sp<ResourceTypeSet> >* resources) -{ - const Vector<sp<AaptDir> >& dirs = ass->resDirs(); - int N = dirs.size(); - - for (int i=0; i<N; i++) { - sp<AaptDir> d = dirs.itemAt(i); - NOISY(printf("Collecting dir #%d %p: %s, leaf %s\n", i, d.get(), d->getPath().string(), - d->getLeaf().string())); - collect_files(d, resources); - - // don't try to include the res dir - NOISY(printf("Removing dir leaf %s\n", d->getLeaf().string())); - ass->removeDir(d->getLeaf()); - } -} - -enum { - ATTR_OKAY = -1, - ATTR_NOT_FOUND = -2, - ATTR_LEADING_SPACES = -3, - ATTR_TRAILING_SPACES = -4 -}; -static int validateAttr(const String8& path, const ResTable& table, - const ResXMLParser& parser, - const char* ns, const char* attr, const char* validChars, bool required) -{ - size_t len; - - ssize_t index = parser.indexOfAttribute(ns, attr); - const uint16_t* str; - Res_value value; - if (index >= 0 && parser.getAttributeValue(index, &value) >= 0) { - const ResStringPool* pool = &parser.getStrings(); - if (value.dataType == Res_value::TYPE_REFERENCE) { - uint32_t specFlags = 0; - int strIdx; - if ((strIdx=table.resolveReference(&value, 0x10000000, NULL, &specFlags)) < 0) { - fprintf(stderr, "%s:%d: Tag <%s> attribute %s references unknown resid 0x%08x.\n", - path.string(), parser.getLineNumber(), - String8(parser.getElementName(&len)).string(), attr, - value.data); - return ATTR_NOT_FOUND; - } - - pool = table.getTableStringBlock(strIdx); - #if 0 - if (pool != NULL) { - str = pool->stringAt(value.data, &len); - } - printf("***** RES ATTR: %s specFlags=0x%x strIdx=%d: %s\n", attr, - specFlags, strIdx, str != NULL ? String8(str).string() : "???"); - #endif - if ((specFlags&~ResTable_typeSpec::SPEC_PUBLIC) != 0 && false) { - fprintf(stderr, "%s:%d: Tag <%s> attribute %s varies by configurations 0x%x.\n", - path.string(), parser.getLineNumber(), - String8(parser.getElementName(&len)).string(), attr, - specFlags); - return ATTR_NOT_FOUND; - } - } - if (value.dataType == Res_value::TYPE_STRING) { - if (pool == NULL) { - fprintf(stderr, "%s:%d: Tag <%s> attribute %s has no string block.\n", - path.string(), parser.getLineNumber(), - String8(parser.getElementName(&len)).string(), attr); - return ATTR_NOT_FOUND; - } - if ((str=pool->stringAt(value.data, &len)) == NULL) { - fprintf(stderr, "%s:%d: Tag <%s> attribute %s has corrupt string value.\n", - path.string(), parser.getLineNumber(), - String8(parser.getElementName(&len)).string(), attr); - return ATTR_NOT_FOUND; - } - } else { - fprintf(stderr, "%s:%d: Tag <%s> attribute %s has invalid type %d.\n", - path.string(), parser.getLineNumber(), - String8(parser.getElementName(&len)).string(), attr, - value.dataType); - return ATTR_NOT_FOUND; - } - if (validChars) { - for (size_t i=0; i<len; i++) { - uint16_t c = str[i]; - const char* p = validChars; - bool okay = false; - while (*p) { - if (c == *p) { - okay = true; - break; - } - p++; - } - if (!okay) { - fprintf(stderr, "%s:%d: Tag <%s> attribute %s has invalid character '%c'.\n", - path.string(), parser.getLineNumber(), - String8(parser.getElementName(&len)).string(), attr, (char)str[i]); - return (int)i; - } - } - } - if (*str == ' ') { - fprintf(stderr, "%s:%d: Tag <%s> attribute %s can not start with a space.\n", - path.string(), parser.getLineNumber(), - String8(parser.getElementName(&len)).string(), attr); - return ATTR_LEADING_SPACES; - } - if (str[len-1] == ' ') { - fprintf(stderr, "%s:%d: Tag <%s> attribute %s can not end with a space.\n", - path.string(), parser.getLineNumber(), - String8(parser.getElementName(&len)).string(), attr); - return ATTR_TRAILING_SPACES; - } - return ATTR_OKAY; - } - if (required) { - fprintf(stderr, "%s:%d: Tag <%s> missing required attribute %s.\n", - path.string(), parser.getLineNumber(), - String8(parser.getElementName(&len)).string(), attr); - return ATTR_NOT_FOUND; - } - return ATTR_OKAY; -} - -static void checkForIds(const String8& path, ResXMLParser& parser) -{ - ResXMLTree::event_code_t code; - while ((code=parser.next()) != ResXMLTree::END_DOCUMENT - && code > ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::START_TAG) { - ssize_t index = parser.indexOfAttribute(NULL, "id"); - if (index >= 0) { - fprintf(stderr, "%s:%d: warning: found plain 'id' attribute; did you mean the new 'android:id' name?\n", - path.string(), parser.getLineNumber()); - } - } - } -} - -static bool applyFileOverlay(Bundle *bundle, - const sp<AaptAssets>& assets, - sp<ResourceTypeSet> *baseSet, - const char *resType) -{ - if (bundle->getVerbose()) { - printf("applyFileOverlay for %s\n", resType); - } - - // Replace any base level files in this category with any found from the overlay - // Also add any found only in the overlay. - sp<AaptAssets> overlay = assets->getOverlay(); - String8 resTypeString(resType); - - // work through the linked list of overlays - while (overlay.get()) { - KeyedVector<String8, sp<ResourceTypeSet> >* overlayRes = overlay->getResources(); - - // get the overlay resources of the requested type - ssize_t index = overlayRes->indexOfKey(resTypeString); - if (index >= 0) { - sp<ResourceTypeSet> overlaySet = overlayRes->valueAt(index); - - // for each of the resources, check for a match in the previously built - // non-overlay "baseset". - size_t overlayCount = overlaySet->size(); - for (size_t overlayIndex=0; overlayIndex<overlayCount; overlayIndex++) { - if (bundle->getVerbose()) { - printf("trying overlaySet Key=%s\n",overlaySet->keyAt(overlayIndex).string()); - } - size_t baseIndex = UNKNOWN_ERROR; - if (baseSet->get() != NULL) { - baseIndex = (*baseSet)->indexOfKey(overlaySet->keyAt(overlayIndex)); - } - if (baseIndex < UNKNOWN_ERROR) { - // look for same flavor. For a given file (strings.xml, for example) - // there may be a locale specific or other flavors - we want to match - // the same flavor. - sp<AaptGroup> overlayGroup = overlaySet->valueAt(overlayIndex); - sp<AaptGroup> baseGroup = (*baseSet)->valueAt(baseIndex); - - DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > overlayFiles = - overlayGroup->getFiles(); - if (bundle->getVerbose()) { - DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > baseFiles = - baseGroup->getFiles(); - for (size_t i=0; i < baseFiles.size(); i++) { - printf("baseFile " ZD " has flavor %s\n", (ZD_TYPE) i, - baseFiles.keyAt(i).toString().string()); - } - for (size_t i=0; i < overlayFiles.size(); i++) { - printf("overlayFile " ZD " has flavor %s\n", (ZD_TYPE) i, - overlayFiles.keyAt(i).toString().string()); - } - } - - size_t overlayGroupSize = overlayFiles.size(); - for (size_t overlayGroupIndex = 0; - overlayGroupIndex<overlayGroupSize; - overlayGroupIndex++) { - size_t baseFileIndex = - baseGroup->getFiles().indexOfKey(overlayFiles. - keyAt(overlayGroupIndex)); - if (baseFileIndex < UNKNOWN_ERROR) { - if (bundle->getVerbose()) { - printf("found a match (" ZD ") for overlay file %s, for flavor %s\n", - (ZD_TYPE) baseFileIndex, - overlayGroup->getLeaf().string(), - overlayFiles.keyAt(overlayGroupIndex).toString().string()); - } - baseGroup->removeFile(baseFileIndex); - } else { - // didn't find a match fall through and add it.. - if (true || bundle->getVerbose()) { - printf("nothing matches overlay file %s, for flavor %s\n", - overlayGroup->getLeaf().string(), - overlayFiles.keyAt(overlayGroupIndex).toString().string()); - } - } - baseGroup->addFile(overlayFiles.valueAt(overlayGroupIndex)); - assets->addGroupEntry(overlayFiles.keyAt(overlayGroupIndex)); - } - } else { - if (baseSet->get() == NULL) { - *baseSet = new ResourceTypeSet(); - assets->getResources()->add(String8(resType), *baseSet); - } - // this group doesn't exist (a file that's only in the overlay) - (*baseSet)->add(overlaySet->keyAt(overlayIndex), - overlaySet->valueAt(overlayIndex)); - // make sure all flavors are defined in the resources. - sp<AaptGroup> overlayGroup = overlaySet->valueAt(overlayIndex); - DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > overlayFiles = - overlayGroup->getFiles(); - size_t overlayGroupSize = overlayFiles.size(); - for (size_t overlayGroupIndex = 0; - overlayGroupIndex<overlayGroupSize; - overlayGroupIndex++) { - assets->addGroupEntry(overlayFiles.keyAt(overlayGroupIndex)); - } - } - } - // this overlay didn't have resources for this type - } - // try next overlay - overlay = overlay->getOverlay(); - } - return true; -} - -/* - * Inserts an attribute in a given node, only if the attribute does not - * exist. - * If errorOnFailedInsert is true, and the attribute already exists, returns false. - * Returns true otherwise, even if the attribute already exists. - */ -bool addTagAttribute(const sp<XMLNode>& node, const char* ns8, - const char* attr8, const char* value, bool errorOnFailedInsert) -{ - if (value == NULL) { - return true; - } - - const String16 ns(ns8); - const String16 attr(attr8); - - if (node->getAttribute(ns, attr) != NULL) { - if (errorOnFailedInsert) { - fprintf(stderr, "Error: AndroidManifest.xml already defines %s (in %s);" - " cannot insert new value %s.\n", - String8(attr).string(), String8(ns).string(), value); - return false; - } - - fprintf(stderr, "Warning: AndroidManifest.xml already defines %s (in %s);" - " using existing value in manifest.\n", - String8(attr).string(), String8(ns).string()); - - // don't stop the build. - return true; - } - - node->addAttribute(ns, attr, String16(value)); - return true; -} - -static void fullyQualifyClassName(const String8& package, sp<XMLNode> node, - const String16& attrName) { - XMLNode::attribute_entry* attr = node->editAttribute( - String16("http://schemas.android.com/apk/res/android"), attrName); - if (attr != NULL) { - String8 name(attr->string); - - // asdf --> package.asdf - // .asdf .a.b --> package.asdf package.a.b - // asdf.adsf --> asdf.asdf - String8 className; - const char* p = name.string(); - const char* q = strchr(p, '.'); - if (p == q) { - className += package; - className += name; - } else if (q == NULL) { - className += package; - className += "."; - className += name; - } else { - className += name; - } - NOISY(printf("Qualifying class '%s' to '%s'", name.string(), className.string())); - attr->string.setTo(String16(className)); - } -} - -status_t massageManifest(Bundle* bundle, sp<XMLNode> root) -{ - root = root->searchElement(String16(), String16("manifest")); - if (root == NULL) { - fprintf(stderr, "No <manifest> tag.\n"); - return UNKNOWN_ERROR; - } - - bool errorOnFailedInsert = bundle->getErrorOnFailedInsert(); - - if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionCode", - bundle->getVersionCode(), errorOnFailedInsert)) { - return UNKNOWN_ERROR; - } - if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionName", - bundle->getVersionName(), errorOnFailedInsert)) { - return UNKNOWN_ERROR; - } - - if (bundle->getMinSdkVersion() != NULL - || bundle->getTargetSdkVersion() != NULL - || bundle->getMaxSdkVersion() != NULL) { - sp<XMLNode> vers = root->getChildElement(String16(), String16("uses-sdk")); - if (vers == NULL) { - vers = XMLNode::newElement(root->getFilename(), String16(), String16("uses-sdk")); - root->insertChildAt(vers, 0); - } - - if (!addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "minSdkVersion", - bundle->getMinSdkVersion(), errorOnFailedInsert)) { - return UNKNOWN_ERROR; - } - if (!addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "targetSdkVersion", - bundle->getTargetSdkVersion(), errorOnFailedInsert)) { - return UNKNOWN_ERROR; - } - if (!addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "maxSdkVersion", - bundle->getMaxSdkVersion(), errorOnFailedInsert)) { - return UNKNOWN_ERROR; - } - } - - if (bundle->getDebugMode()) { - sp<XMLNode> application = root->getChildElement(String16(), String16("application")); - if (application != NULL) { - if (!addTagAttribute(application, RESOURCES_ANDROID_NAMESPACE, "debuggable", "true", - errorOnFailedInsert)) { - return UNKNOWN_ERROR; - } - } - } - - // Deal with manifest package name overrides - const char* manifestPackageNameOverride = bundle->getManifestPackageNameOverride(); - if (manifestPackageNameOverride != NULL) { - // Update the actual package name - XMLNode::attribute_entry* attr = root->editAttribute(String16(), String16("package")); - if (attr == NULL) { - fprintf(stderr, "package name is required with --rename-manifest-package.\n"); - return UNKNOWN_ERROR; - } - String8 origPackage(attr->string); - attr->string.setTo(String16(manifestPackageNameOverride)); - NOISY(printf("Overriding package '%s' to be '%s'\n", origPackage.string(), manifestPackageNameOverride)); - - // Make class names fully qualified - sp<XMLNode> application = root->getChildElement(String16(), String16("application")); - if (application != NULL) { - fullyQualifyClassName(origPackage, application, String16("name")); - fullyQualifyClassName(origPackage, application, String16("backupAgent")); - - Vector<sp<XMLNode> >& children = const_cast<Vector<sp<XMLNode> >&>(application->getChildren()); - for (size_t i = 0; i < children.size(); i++) { - sp<XMLNode> child = children.editItemAt(i); - String8 tag(child->getElementName()); - if (tag == "activity" || tag == "service" || tag == "receiver" || tag == "provider") { - fullyQualifyClassName(origPackage, child, String16("name")); - } else if (tag == "activity-alias") { - fullyQualifyClassName(origPackage, child, String16("name")); - fullyQualifyClassName(origPackage, child, String16("targetActivity")); - } - } - } - } - - // Deal with manifest package name overrides - const char* instrumentationPackageNameOverride = bundle->getInstrumentationPackageNameOverride(); - if (instrumentationPackageNameOverride != NULL) { - // Fix up instrumentation targets. - Vector<sp<XMLNode> >& children = const_cast<Vector<sp<XMLNode> >&>(root->getChildren()); - for (size_t i = 0; i < children.size(); i++) { - sp<XMLNode> child = children.editItemAt(i); - String8 tag(child->getElementName()); - if (tag == "instrumentation") { - XMLNode::attribute_entry* attr = child->editAttribute( - String16("http://schemas.android.com/apk/res/android"), String16("targetPackage")); - if (attr != NULL) { - attr->string.setTo(String16(instrumentationPackageNameOverride)); - } - } - } - } - - return NO_ERROR; -} - -#define ASSIGN_IT(n) \ - do { \ - ssize_t index = resources->indexOfKey(String8(#n)); \ - if (index >= 0) { \ - n ## s = resources->valueAt(index); \ - } \ - } while (0) - -status_t updatePreProcessedCache(Bundle* bundle) -{ - #if BENCHMARK - fprintf(stdout, "BENCHMARK: Starting PNG PreProcessing \n"); - long startPNGTime = clock(); - #endif /* BENCHMARK */ - - String8 source(bundle->getResourceSourceDirs()[0]); - String8 dest(bundle->getCrunchedOutputDir()); - - FileFinder* ff = new SystemFileFinder(); - CrunchCache cc(source,dest,ff); - - CacheUpdater* cu = new SystemCacheUpdater(bundle); - size_t numFiles = cc.crunch(cu); - - if (bundle->getVerbose()) - fprintf(stdout, "Crunched %d PNG files to update cache\n", (int)numFiles); - - delete ff; - delete cu; - - #if BENCHMARK - fprintf(stdout, "BENCHMARK: End PNG PreProcessing. Time Elapsed: %f ms \n" - ,(clock() - startPNGTime)/1000.0); - #endif /* BENCHMARK */ - return 0; -} - -status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets) -{ - // First, look for a package file to parse. This is required to - // be able to generate the resource information. - sp<AaptGroup> androidManifestFile = - assets->getFiles().valueFor(String8("AndroidManifest.xml")); - if (androidManifestFile == NULL) { - fprintf(stderr, "ERROR: No AndroidManifest.xml file found.\n"); - return UNKNOWN_ERROR; - } - - status_t err = parsePackage(bundle, assets, androidManifestFile); - if (err != NO_ERROR) { - return err; - } - - NOISY(printf("Creating resources for package %s\n", - assets->getPackage().string())); - - ResourceTable table(bundle, String16(assets->getPackage())); - err = table.addIncludedResources(bundle, assets); - if (err != NO_ERROR) { - return err; - } - - NOISY(printf("Found %d included resource packages\n", (int)table.size())); - - // Standard flags for compiled XML and optional UTF-8 encoding - int xmlFlags = XML_COMPILE_STANDARD_RESOURCE; - - /* Only enable UTF-8 if the caller of aapt didn't specifically - * request UTF-16 encoding and the parameters of this package - * allow UTF-8 to be used. - */ - if (!bundle->getUTF16StringsOption()) { - xmlFlags |= XML_COMPILE_UTF8; - } - - // -------------------------------------------------------------- - // First, gather all resource information. - // -------------------------------------------------------------- - - // resType -> leafName -> group - KeyedVector<String8, sp<ResourceTypeSet> > *resources = - new KeyedVector<String8, sp<ResourceTypeSet> >; - collect_files(assets, resources); - - sp<ResourceTypeSet> drawables; - sp<ResourceTypeSet> layouts; - sp<ResourceTypeSet> anims; - sp<ResourceTypeSet> animators; - sp<ResourceTypeSet> interpolators; - sp<ResourceTypeSet> transitions; - sp<ResourceTypeSet> scenes; - sp<ResourceTypeSet> xmls; - sp<ResourceTypeSet> raws; - sp<ResourceTypeSet> colors; - sp<ResourceTypeSet> menus; - sp<ResourceTypeSet> mipmaps; - - ASSIGN_IT(drawable); - ASSIGN_IT(layout); - ASSIGN_IT(anim); - ASSIGN_IT(animator); - ASSIGN_IT(interpolator); - ASSIGN_IT(transition); - ASSIGN_IT(scene); - ASSIGN_IT(xml); - ASSIGN_IT(raw); - ASSIGN_IT(color); - ASSIGN_IT(menu); - ASSIGN_IT(mipmap); - - assets->setResources(resources); - // now go through any resource overlays and collect their files - sp<AaptAssets> current = assets->getOverlay(); - while(current.get()) { - KeyedVector<String8, sp<ResourceTypeSet> > *resources = - new KeyedVector<String8, sp<ResourceTypeSet> >; - current->setResources(resources); - collect_files(current, resources); - current = current->getOverlay(); - } - // apply the overlay files to the base set - if (!applyFileOverlay(bundle, assets, &drawables, "drawable") || - !applyFileOverlay(bundle, assets, &layouts, "layout") || - !applyFileOverlay(bundle, assets, &anims, "anim") || - !applyFileOverlay(bundle, assets, &animators, "animator") || - !applyFileOverlay(bundle, assets, &interpolators, "interpolator") || - !applyFileOverlay(bundle, assets, &transitions, "transition") || - !applyFileOverlay(bundle, assets, &scenes, "scene") || - !applyFileOverlay(bundle, assets, &xmls, "xml") || - !applyFileOverlay(bundle, assets, &raws, "raw") || - !applyFileOverlay(bundle, assets, &colors, "color") || - !applyFileOverlay(bundle, assets, &menus, "menu") || - !applyFileOverlay(bundle, assets, &mipmaps, "mipmap")) { - return UNKNOWN_ERROR; - } - - bool hasErrors = false; - - if (drawables != NULL) { - if (bundle->getOutputAPKFile() != NULL) { - err = preProcessImages(bundle, assets, drawables, "drawable"); - } - if (err == NO_ERROR) { - err = makeFileResources(bundle, assets, &table, drawables, "drawable"); - if (err != NO_ERROR) { - hasErrors = true; - } - } else { - hasErrors = true; - } - } - - if (mipmaps != NULL) { - if (bundle->getOutputAPKFile() != NULL) { - err = preProcessImages(bundle, assets, mipmaps, "mipmap"); - } - if (err == NO_ERROR) { - err = makeFileResources(bundle, assets, &table, mipmaps, "mipmap"); - if (err != NO_ERROR) { - hasErrors = true; - } - } else { - hasErrors = true; - } - } - - if (layouts != NULL) { - err = makeFileResources(bundle, assets, &table, layouts, "layout"); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - if (anims != NULL) { - err = makeFileResources(bundle, assets, &table, anims, "anim"); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - if (animators != NULL) { - err = makeFileResources(bundle, assets, &table, animators, "animator"); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - if (transitions != NULL) { - err = makeFileResources(bundle, assets, &table, transitions, "transition"); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - if (scenes != NULL) { - err = makeFileResources(bundle, assets, &table, scenes, "scene"); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - if (interpolators != NULL) { - err = makeFileResources(bundle, assets, &table, interpolators, "interpolator"); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - if (xmls != NULL) { - err = makeFileResources(bundle, assets, &table, xmls, "xml"); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - if (raws != NULL) { - err = makeFileResources(bundle, assets, &table, raws, "raw"); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - // compile resources - current = assets; - while(current.get()) { - KeyedVector<String8, sp<ResourceTypeSet> > *resources = - current->getResources(); - - ssize_t index = resources->indexOfKey(String8("values")); - if (index >= 0) { - ResourceDirIterator it(resources->valueAt(index), String8("values")); - ssize_t res; - while ((res=it.next()) == NO_ERROR) { - sp<AaptFile> file = it.getFile(); - res = compileResourceFile(bundle, assets, file, it.getParams(), - (current!=assets), &table); - if (res != NO_ERROR) { - hasErrors = true; - } - } - } - current = current->getOverlay(); - } - - if (colors != NULL) { - err = makeFileResources(bundle, assets, &table, colors, "color"); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - if (menus != NULL) { - err = makeFileResources(bundle, assets, &table, menus, "menu"); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - // -------------------------------------------------------------------- - // Assignment of resource IDs and initial generation of resource table. - // -------------------------------------------------------------------- - - if (table.hasResources()) { - sp<AaptFile> resFile(getResourceFile(assets)); - if (resFile == NULL) { - fprintf(stderr, "Error: unable to generate entry for resource data\n"); - return UNKNOWN_ERROR; - } - - err = table.assignResourceIds(); - if (err < NO_ERROR) { - return err; - } - } - - // -------------------------------------------------------------- - // Finally, we can now we can compile XML files, which may reference - // resources. - // -------------------------------------------------------------- - - if (layouts != NULL) { - ResourceDirIterator it(layouts, String8("layout")); - while ((err=it.next()) == NO_ERROR) { - String8 src = it.getFile()->getPrintableSource(); - err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); - if (err == NO_ERROR) { - ResXMLTree block; - block.setTo(it.getFile()->getData(), it.getFile()->getSize(), true); - checkForIds(src, block); - } else { - hasErrors = true; - } - } - - if (err < NO_ERROR) { - hasErrors = true; - } - err = NO_ERROR; - } - - if (anims != NULL) { - ResourceDirIterator it(anims, String8("anim")); - while ((err=it.next()) == NO_ERROR) { - err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - if (err < NO_ERROR) { - hasErrors = true; - } - err = NO_ERROR; - } - - if (animators != NULL) { - ResourceDirIterator it(animators, String8("animator")); - while ((err=it.next()) == NO_ERROR) { - err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - if (err < NO_ERROR) { - hasErrors = true; - } - err = NO_ERROR; - } - - if (interpolators != NULL) { - ResourceDirIterator it(interpolators, String8("interpolator")); - while ((err=it.next()) == NO_ERROR) { - err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - if (err < NO_ERROR) { - hasErrors = true; - } - err = NO_ERROR; - } - - if (transitions != NULL) { - ResourceDirIterator it(transitions, String8("transition")); - while ((err=it.next()) == NO_ERROR) { - err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - if (err < NO_ERROR) { - hasErrors = true; - } - err = NO_ERROR; - } - - if (scenes != NULL) { - ResourceDirIterator it(scenes, String8("scene")); - while ((err=it.next()) == NO_ERROR) { - err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - if (err < NO_ERROR) { - hasErrors = true; - } - err = NO_ERROR; - } - - if (xmls != NULL) { - ResourceDirIterator it(xmls, String8("xml")); - while ((err=it.next()) == NO_ERROR) { - err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - if (err < NO_ERROR) { - hasErrors = true; - } - err = NO_ERROR; - } - - if (drawables != NULL) { - err = postProcessImages(assets, &table, drawables); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - if (colors != NULL) { - ResourceDirIterator it(colors, String8("color")); - while ((err=it.next()) == NO_ERROR) { - err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - if (err < NO_ERROR) { - hasErrors = true; - } - err = NO_ERROR; - } - - if (menus != NULL) { - ResourceDirIterator it(menus, String8("menu")); - while ((err=it.next()) == NO_ERROR) { - String8 src = it.getFile()->getPrintableSource(); - err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); - if (err != NO_ERROR) { - hasErrors = true; - } - ResXMLTree block; - block.setTo(it.getFile()->getData(), it.getFile()->getSize(), true); - checkForIds(src, block); - } - - if (err < NO_ERROR) { - hasErrors = true; - } - err = NO_ERROR; - } - - if (table.validateLocalizations()) { - hasErrors = true; - } - - if (hasErrors) { - return UNKNOWN_ERROR; - } - - const sp<AaptFile> manifestFile(androidManifestFile->getFiles().valueAt(0)); - String8 manifestPath(manifestFile->getPrintableSource()); - - // Generate final compiled manifest file. - manifestFile->clearData(); - sp<XMLNode> manifestTree = XMLNode::parse(manifestFile); - if (manifestTree == NULL) { - return UNKNOWN_ERROR; - } - err = massageManifest(bundle, manifestTree); - if (err < NO_ERROR) { - return err; - } - err = compileXmlFile(assets, manifestTree, manifestFile, &table); - if (err < NO_ERROR) { - return err; - } - - //block.restart(); - //printXMLBlock(&block); - - // -------------------------------------------------------------- - // Generate the final resource table. - // Re-flatten because we may have added new resource IDs - // -------------------------------------------------------------- - - ResTable finalResTable; - sp<AaptFile> resFile; - - if (table.hasResources()) { - sp<AaptSymbols> symbols = assets->getSymbolsFor(String8("R")); - err = table.addSymbols(symbols); - if (err < NO_ERROR) { - return err; - } - - resFile = getResourceFile(assets); - if (resFile == NULL) { - fprintf(stderr, "Error: unable to generate entry for resource data\n"); - return UNKNOWN_ERROR; - } - - err = table.flatten(bundle, resFile); - if (err < NO_ERROR) { - return err; - } - - if (bundle->getPublicOutputFile()) { - FILE* fp = fopen(bundle->getPublicOutputFile(), "w+"); - if (fp == NULL) { - fprintf(stderr, "ERROR: Unable to open public definitions output file %s: %s\n", - (const char*)bundle->getPublicOutputFile(), strerror(errno)); - return UNKNOWN_ERROR; - } - if (bundle->getVerbose()) { - printf(" Writing public definitions to %s.\n", bundle->getPublicOutputFile()); - } - table.writePublicDefinitions(String16(assets->getPackage()), fp); - fclose(fp); - } - - // Read resources back in, - finalResTable.add(resFile->getData(), resFile->getSize(), NULL); - -#if 0 - NOISY( - printf("Generated resources:\n"); - finalResTable.print(); - ) -#endif - } - - // Perform a basic validation of the manifest file. This time we - // parse it with the comments intact, so that we can use them to - // generate java docs... so we are not going to write this one - // back out to the final manifest data. - sp<AaptFile> outManifestFile = new AaptFile(manifestFile->getSourceFile(), - manifestFile->getGroupEntry(), - manifestFile->getResourceType()); - err = compileXmlFile(assets, manifestFile, - outManifestFile, &table, - XML_COMPILE_ASSIGN_ATTRIBUTE_IDS - | XML_COMPILE_STRIP_WHITESPACE | XML_COMPILE_STRIP_RAW_VALUES); - if (err < NO_ERROR) { - return err; - } - ResXMLTree block; - block.setTo(outManifestFile->getData(), outManifestFile->getSize(), true); - String16 manifest16("manifest"); - String16 permission16("permission"); - String16 permission_group16("permission-group"); - String16 uses_permission16("uses-permission"); - String16 instrumentation16("instrumentation"); - String16 application16("application"); - String16 provider16("provider"); - String16 service16("service"); - String16 receiver16("receiver"); - String16 activity16("activity"); - String16 action16("action"); - String16 category16("category"); - String16 data16("scheme"); - const char* packageIdentChars = "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789"; - const char* packageIdentCharsWithTheStupid = "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789-"; - const char* classIdentChars = "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789$"; - const char* processIdentChars = "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789:"; - const char* authoritiesIdentChars = "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789-:;"; - const char* typeIdentChars = "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789:-/*+"; - const char* schemeIdentChars = "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789-"; - ResXMLTree::event_code_t code; - sp<AaptSymbols> permissionSymbols; - sp<AaptSymbols> permissionGroupSymbols; - while ((code=block.next()) != ResXMLTree::END_DOCUMENT - && code > ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::START_TAG) { - size_t len; - if (block.getElementNamespace(&len) != NULL) { - continue; - } - if (strcmp16(block.getElementName(&len), manifest16.string()) == 0) { - if (validateAttr(manifestPath, finalResTable, block, NULL, "package", - packageIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE, - "sharedUserId", packageIdentChars, false) != ATTR_OKAY) { - hasErrors = true; - } - } else if (strcmp16(block.getElementName(&len), permission16.string()) == 0 - || strcmp16(block.getElementName(&len), permission_group16.string()) == 0) { - const bool isGroup = strcmp16(block.getElementName(&len), - permission_group16.string()) == 0; - if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE, - "name", isGroup ? packageIdentCharsWithTheStupid - : packageIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - SourcePos srcPos(manifestPath, block.getLineNumber()); - sp<AaptSymbols> syms; - if (!isGroup) { - syms = permissionSymbols; - if (syms == NULL) { - sp<AaptSymbols> symbols = - assets->getSymbolsFor(String8("Manifest")); - syms = permissionSymbols = symbols->addNestedSymbol( - String8("permission"), srcPos); - } - } else { - syms = permissionGroupSymbols; - if (syms == NULL) { - sp<AaptSymbols> symbols = - assets->getSymbolsFor(String8("Manifest")); - syms = permissionGroupSymbols = symbols->addNestedSymbol( - String8("permission_group"), srcPos); - } - } - size_t len; - ssize_t index = block.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE, "name"); - const uint16_t* id = block.getAttributeStringValue(index, &len); - if (id == NULL) { - fprintf(stderr, "%s:%d: missing name attribute in element <%s>.\n", - manifestPath.string(), block.getLineNumber(), - String8(block.getElementName(&len)).string()); - hasErrors = true; - break; - } - String8 idStr(id); - char* p = idStr.lockBuffer(idStr.size()); - char* e = p + idStr.size(); - bool begins_with_digit = true; // init to true so an empty string fails - while (e > p) { - e--; - if (*e >= '0' && *e <= '9') { - begins_with_digit = true; - continue; - } - if ((*e >= 'a' && *e <= 'z') || - (*e >= 'A' && *e <= 'Z') || - (*e == '_')) { - begins_with_digit = false; - continue; - } - if (isGroup && (*e == '-')) { - *e = '_'; - begins_with_digit = false; - continue; - } - e++; - break; - } - idStr.unlockBuffer(); - // verify that we stopped because we hit a period or - // the beginning of the string, and that the - // identifier didn't begin with a digit. - if (begins_with_digit || (e != p && *(e-1) != '.')) { - fprintf(stderr, - "%s:%d: Permission name <%s> is not a valid Java symbol\n", - manifestPath.string(), block.getLineNumber(), idStr.string()); - hasErrors = true; - } - syms->addStringSymbol(String8(e), idStr, srcPos); - const uint16_t* cmt = block.getComment(&len); - if (cmt != NULL && *cmt != 0) { - //printf("Comment of %s: %s\n", String8(e).string(), - // String8(cmt).string()); - syms->appendComment(String8(e), String16(cmt), srcPos); - } else { - //printf("No comment for %s\n", String8(e).string()); - } - syms->makeSymbolPublic(String8(e), srcPos); - } else if (strcmp16(block.getElementName(&len), uses_permission16.string()) == 0) { - if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE, - "name", packageIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - } else if (strcmp16(block.getElementName(&len), instrumentation16.string()) == 0) { - if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE, - "name", classIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, finalResTable, block, - RESOURCES_ANDROID_NAMESPACE, "targetPackage", - packageIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - } else if (strcmp16(block.getElementName(&len), application16.string()) == 0) { - if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE, - "name", classIdentChars, false) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, finalResTable, block, - RESOURCES_ANDROID_NAMESPACE, "permission", - packageIdentChars, false) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, finalResTable, block, - RESOURCES_ANDROID_NAMESPACE, "process", - processIdentChars, false) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, finalResTable, block, - RESOURCES_ANDROID_NAMESPACE, "taskAffinity", - processIdentChars, false) != ATTR_OKAY) { - hasErrors = true; - } - } else if (strcmp16(block.getElementName(&len), provider16.string()) == 0) { - if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE, - "name", classIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, finalResTable, block, - RESOURCES_ANDROID_NAMESPACE, "authorities", - authoritiesIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, finalResTable, block, - RESOURCES_ANDROID_NAMESPACE, "permission", - packageIdentChars, false) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, finalResTable, block, - RESOURCES_ANDROID_NAMESPACE, "process", - processIdentChars, false) != ATTR_OKAY) { - hasErrors = true; - } - } else if (strcmp16(block.getElementName(&len), service16.string()) == 0 - || strcmp16(block.getElementName(&len), receiver16.string()) == 0 - || strcmp16(block.getElementName(&len), activity16.string()) == 0) { - if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE, - "name", classIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, finalResTable, block, - RESOURCES_ANDROID_NAMESPACE, "permission", - packageIdentChars, false) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, finalResTable, block, - RESOURCES_ANDROID_NAMESPACE, "process", - processIdentChars, false) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, finalResTable, block, - RESOURCES_ANDROID_NAMESPACE, "taskAffinity", - processIdentChars, false) != ATTR_OKAY) { - hasErrors = true; - } - } else if (strcmp16(block.getElementName(&len), action16.string()) == 0 - || strcmp16(block.getElementName(&len), category16.string()) == 0) { - if (validateAttr(manifestPath, finalResTable, block, - RESOURCES_ANDROID_NAMESPACE, "name", - packageIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - } else if (strcmp16(block.getElementName(&len), data16.string()) == 0) { - if (validateAttr(manifestPath, finalResTable, block, - RESOURCES_ANDROID_NAMESPACE, "mimeType", - typeIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, finalResTable, block, - RESOURCES_ANDROID_NAMESPACE, "scheme", - schemeIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - } - } - } - - if (resFile != NULL) { - // These resources are now considered to be a part of the included - // resources, for others to reference. - err = assets->addIncludedResources(resFile); - if (err < NO_ERROR) { - fprintf(stderr, "ERROR: Unable to parse generated resources, aborting.\n"); - return err; - } - } - - return err; -} - -static const char* getIndentSpace(int indent) -{ -static const char whitespace[] = -" "; - - return whitespace + sizeof(whitespace) - 1 - indent*4; -} - -static String8 flattenSymbol(const String8& symbol) { - String8 result(symbol); - ssize_t first; - if ((first = symbol.find(":", 0)) >= 0 - || (first = symbol.find(".", 0)) >= 0) { - size_t size = symbol.size(); - char* buf = result.lockBuffer(size); - for (size_t i = first; i < size; i++) { - if (buf[i] == ':' || buf[i] == '.') { - buf[i] = '_'; - } - } - result.unlockBuffer(size); - } - return result; -} - -static String8 getSymbolPackage(const String8& symbol, const sp<AaptAssets>& assets, bool pub) { - ssize_t colon = symbol.find(":", 0); - if (colon >= 0) { - return String8(symbol.string(), colon); - } - return pub ? assets->getPackage() : assets->getSymbolsPrivatePackage(); -} - -static String8 getSymbolName(const String8& symbol) { - ssize_t colon = symbol.find(":", 0); - if (colon >= 0) { - return String8(symbol.string() + colon + 1); - } - return symbol; -} - -static String16 getAttributeComment(const sp<AaptAssets>& assets, - const String8& name, - String16* outTypeComment = NULL) -{ - sp<AaptSymbols> asym = assets->getSymbolsFor(String8("R")); - if (asym != NULL) { - //printf("Got R symbols!\n"); - asym = asym->getNestedSymbols().valueFor(String8("attr")); - if (asym != NULL) { - //printf("Got attrs symbols! comment %s=%s\n", - // name.string(), String8(asym->getComment(name)).string()); - if (outTypeComment != NULL) { - *outTypeComment = asym->getTypeComment(name); - } - return asym->getComment(name); - } - } - return String16(); -} - -static status_t writeLayoutClasses( - FILE* fp, const sp<AaptAssets>& assets, - const sp<AaptSymbols>& symbols, int indent, bool includePrivate) -{ - const char* indentStr = getIndentSpace(indent); - if (!includePrivate) { - fprintf(fp, "%s/** @doconly */\n", indentStr); - } - fprintf(fp, "%spublic static final class styleable {\n", indentStr); - indent++; - - String16 attr16("attr"); - String16 package16(assets->getPackage()); - - indentStr = getIndentSpace(indent); - bool hasErrors = false; - - size_t i; - size_t N = symbols->getNestedSymbols().size(); - for (i=0; i<N; i++) { - sp<AaptSymbols> nsymbols = symbols->getNestedSymbols().valueAt(i); - String8 realClassName(symbols->getNestedSymbols().keyAt(i)); - String8 nclassName(flattenSymbol(realClassName)); - - SortedVector<uint32_t> idents; - Vector<uint32_t> origOrder; - Vector<bool> publicFlags; - - size_t a; - size_t NA = nsymbols->getSymbols().size(); - for (a=0; a<NA; a++) { - const AaptSymbolEntry& sym(nsymbols->getSymbols().valueAt(a)); - int32_t code = sym.typeCode == AaptSymbolEntry::TYPE_INT32 - ? sym.int32Val : 0; - bool isPublic = true; - if (code == 0) { - String16 name16(sym.name); - uint32_t typeSpecFlags; - code = assets->getIncludedResources().identifierForName( - name16.string(), name16.size(), - attr16.string(), attr16.size(), - package16.string(), package16.size(), &typeSpecFlags); - if (code == 0) { - fprintf(stderr, "ERROR: In <declare-styleable> %s, unable to find attribute %s\n", - nclassName.string(), sym.name.string()); - hasErrors = true; - } - isPublic = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0; - } - idents.add(code); - origOrder.add(code); - publicFlags.add(isPublic); - } - - NA = idents.size(); - - bool deprecated = false; - - String16 comment = symbols->getComment(realClassName); - fprintf(fp, "%s/** ", indentStr); - if (comment.size() > 0) { - String8 cmt(comment); - fprintf(fp, "%s\n", cmt.string()); - if (strstr(cmt.string(), "@deprecated") != NULL) { - deprecated = true; - } - } else { - fprintf(fp, "Attributes that can be used with a %s.\n", nclassName.string()); - } - bool hasTable = false; - for (a=0; a<NA; a++) { - ssize_t pos = idents.indexOf(origOrder.itemAt(a)); - if (pos >= 0) { - if (!hasTable) { - hasTable = true; - fprintf(fp, - "%s <p>Includes the following attributes:</p>\n" - "%s <table>\n" - "%s <colgroup align=\"left\" />\n" - "%s <colgroup align=\"left\" />\n" - "%s <tr><th>Attribute</th><th>Description</th></tr>\n", - indentStr, - indentStr, - indentStr, - indentStr, - indentStr); - } - const AaptSymbolEntry& sym = nsymbols->getSymbols().valueAt(a); - if (!publicFlags.itemAt(a) && !includePrivate) { - continue; - } - String8 name8(sym.name); - String16 comment(sym.comment); - if (comment.size() <= 0) { - comment = getAttributeComment(assets, name8); - } - if (comment.size() > 0) { - const char16_t* p = comment.string(); - while (*p != 0 && *p != '.') { - if (*p == '{') { - while (*p != 0 && *p != '}') { - p++; - } - } else { - p++; - } - } - if (*p == '.') { - p++; - } - comment = String16(comment.string(), p-comment.string()); - } - fprintf(fp, "%s <tr><td><code>{@link #%s_%s %s:%s}</code></td><td>%s</td></tr>\n", - indentStr, nclassName.string(), - flattenSymbol(name8).string(), - getSymbolPackage(name8, assets, true).string(), - getSymbolName(name8).string(), - String8(comment).string()); - } - } - if (hasTable) { - fprintf(fp, "%s </table>\n", indentStr); - } - for (a=0; a<NA; a++) { - ssize_t pos = idents.indexOf(origOrder.itemAt(a)); - if (pos >= 0) { - const AaptSymbolEntry& sym = nsymbols->getSymbols().valueAt(a); - if (!publicFlags.itemAt(a) && !includePrivate) { - continue; - } - fprintf(fp, "%s @see #%s_%s\n", - indentStr, nclassName.string(), - flattenSymbol(sym.name).string()); - } - } - fprintf(fp, "%s */\n", getIndentSpace(indent)); - - if (deprecated) { - fprintf(fp, "%s@Deprecated\n", indentStr); - } - - fprintf(fp, - "%spublic static final int[] %s = {\n" - "%s", - indentStr, nclassName.string(), - getIndentSpace(indent+1)); - - for (a=0; a<NA; a++) { - if (a != 0) { - if ((a&3) == 0) { - fprintf(fp, ",\n%s", getIndentSpace(indent+1)); - } else { - fprintf(fp, ", "); - } - } - fprintf(fp, "0x%08x", idents[a]); - } - - fprintf(fp, "\n%s};\n", indentStr); - - for (a=0; a<NA; a++) { - ssize_t pos = idents.indexOf(origOrder.itemAt(a)); - if (pos >= 0) { - const AaptSymbolEntry& sym = nsymbols->getSymbols().valueAt(a); - if (!publicFlags.itemAt(a) && !includePrivate) { - continue; - } - String8 name8(sym.name); - String16 comment(sym.comment); - String16 typeComment; - if (comment.size() <= 0) { - comment = getAttributeComment(assets, name8, &typeComment); - } else { - getAttributeComment(assets, name8, &typeComment); - } - - uint32_t typeSpecFlags = 0; - String16 name16(sym.name); - assets->getIncludedResources().identifierForName( - name16.string(), name16.size(), - attr16.string(), attr16.size(), - package16.string(), package16.size(), &typeSpecFlags); - //printf("%s:%s/%s: 0x%08x\n", String8(package16).string(), - // String8(attr16).string(), String8(name16).string(), typeSpecFlags); - const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0; - - bool deprecated = false; - - fprintf(fp, "%s/**\n", indentStr); - if (comment.size() > 0) { - String8 cmt(comment); - fprintf(fp, "%s <p>\n%s @attr description\n", indentStr, indentStr); - fprintf(fp, "%s %s\n", indentStr, cmt.string()); - if (strstr(cmt.string(), "@deprecated") != NULL) { - deprecated = true; - } - } else { - fprintf(fp, - "%s <p>This symbol is the offset where the {@link %s.R.attr#%s}\n" - "%s attribute's value can be found in the {@link #%s} array.\n", - indentStr, - getSymbolPackage(name8, assets, pub).string(), - getSymbolName(name8).string(), - indentStr, nclassName.string()); - } - if (typeComment.size() > 0) { - String8 cmt(typeComment); - fprintf(fp, "\n\n%s %s\n", indentStr, cmt.string()); - if (strstr(cmt.string(), "@deprecated") != NULL) { - deprecated = true; - } - } - if (comment.size() > 0) { - if (pub) { - fprintf(fp, - "%s <p>This corresponds to the global attribute\n" - "%s resource symbol {@link %s.R.attr#%s}.\n", - indentStr, indentStr, - getSymbolPackage(name8, assets, true).string(), - getSymbolName(name8).string()); - } else { - fprintf(fp, - "%s <p>This is a private symbol.\n", indentStr); - } - } - fprintf(fp, "%s @attr name %s:%s\n", indentStr, - getSymbolPackage(name8, assets, pub).string(), - getSymbolName(name8).string()); - fprintf(fp, "%s*/\n", indentStr); - if (deprecated) { - fprintf(fp, "%s@Deprecated\n", indentStr); - } - fprintf(fp, - "%spublic static final int %s_%s = %d;\n", - indentStr, nclassName.string(), - flattenSymbol(name8).string(), (int)pos); - } - } - } - - indent--; - fprintf(fp, "%s};\n", getIndentSpace(indent)); - return hasErrors ? UNKNOWN_ERROR : NO_ERROR; -} - -static status_t writeTextLayoutClasses( - FILE* fp, const sp<AaptAssets>& assets, - const sp<AaptSymbols>& symbols, bool includePrivate) -{ - String16 attr16("attr"); - String16 package16(assets->getPackage()); - - bool hasErrors = false; - - size_t i; - size_t N = symbols->getNestedSymbols().size(); - for (i=0; i<N; i++) { - sp<AaptSymbols> nsymbols = symbols->getNestedSymbols().valueAt(i); - String8 realClassName(symbols->getNestedSymbols().keyAt(i)); - String8 nclassName(flattenSymbol(realClassName)); - - SortedVector<uint32_t> idents; - Vector<uint32_t> origOrder; - Vector<bool> publicFlags; - - size_t a; - size_t NA = nsymbols->getSymbols().size(); - for (a=0; a<NA; a++) { - const AaptSymbolEntry& sym(nsymbols->getSymbols().valueAt(a)); - int32_t code = sym.typeCode == AaptSymbolEntry::TYPE_INT32 - ? sym.int32Val : 0; - bool isPublic = true; - if (code == 0) { - String16 name16(sym.name); - uint32_t typeSpecFlags; - code = assets->getIncludedResources().identifierForName( - name16.string(), name16.size(), - attr16.string(), attr16.size(), - package16.string(), package16.size(), &typeSpecFlags); - if (code == 0) { - fprintf(stderr, "ERROR: In <declare-styleable> %s, unable to find attribute %s\n", - nclassName.string(), sym.name.string()); - hasErrors = true; - } - isPublic = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0; - } - idents.add(code); - origOrder.add(code); - publicFlags.add(isPublic); - } - - NA = idents.size(); - - fprintf(fp, "int[] styleable %s {", nclassName.string()); - - for (a=0; a<NA; a++) { - if (a != 0) { - fprintf(fp, ","); - } - fprintf(fp, " 0x%08x", idents[a]); - } - - fprintf(fp, " }\n"); - - for (a=0; a<NA; a++) { - ssize_t pos = idents.indexOf(origOrder.itemAt(a)); - if (pos >= 0) { - const AaptSymbolEntry& sym = nsymbols->getSymbols().valueAt(a); - if (!publicFlags.itemAt(a) && !includePrivate) { - continue; - } - String8 name8(sym.name); - String16 comment(sym.comment); - String16 typeComment; - if (comment.size() <= 0) { - comment = getAttributeComment(assets, name8, &typeComment); - } else { - getAttributeComment(assets, name8, &typeComment); - } - - uint32_t typeSpecFlags = 0; - String16 name16(sym.name); - assets->getIncludedResources().identifierForName( - name16.string(), name16.size(), - attr16.string(), attr16.size(), - package16.string(), package16.size(), &typeSpecFlags); - //printf("%s:%s/%s: 0x%08x\n", String8(package16).string(), - // String8(attr16).string(), String8(name16).string(), typeSpecFlags); - const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0; - - fprintf(fp, - "int styleable %s_%s %d\n", - nclassName.string(), - flattenSymbol(name8).string(), (int)pos); - } - } - } - - return hasErrors ? UNKNOWN_ERROR : NO_ERROR; -} - -static status_t writeSymbolClass( - FILE* fp, const sp<AaptAssets>& assets, bool includePrivate, - const sp<AaptSymbols>& symbols, const String8& className, int indent, - bool nonConstantId) -{ - fprintf(fp, "%spublic %sfinal class %s {\n", - getIndentSpace(indent), - indent != 0 ? "static " : "", className.string()); - indent++; - - size_t i; - status_t err = NO_ERROR; - - const char * id_format = nonConstantId ? - "%spublic static int %s=0x%08x;\n" : - "%spublic static final int %s=0x%08x;\n"; - - size_t N = symbols->getSymbols().size(); - for (i=0; i<N; i++) { - const AaptSymbolEntry& sym = symbols->getSymbols().valueAt(i); - if (sym.typeCode != AaptSymbolEntry::TYPE_INT32) { - continue; - } - if (!assets->isJavaSymbol(sym, includePrivate)) { - continue; - } - String8 name8(sym.name); - String16 comment(sym.comment); - bool haveComment = false; - bool deprecated = false; - if (comment.size() > 0) { - haveComment = true; - String8 cmt(comment); - fprintf(fp, - "%s/** %s\n", - getIndentSpace(indent), cmt.string()); - if (strstr(cmt.string(), "@deprecated") != NULL) { - deprecated = true; - } - } else if (sym.isPublic && !includePrivate) { - sym.sourcePos.warning("No comment for public symbol %s:%s/%s", - assets->getPackage().string(), className.string(), - String8(sym.name).string()); - } - String16 typeComment(sym.typeComment); - if (typeComment.size() > 0) { - String8 cmt(typeComment); - if (!haveComment) { - haveComment = true; - fprintf(fp, - "%s/** %s\n", getIndentSpace(indent), cmt.string()); - } else { - fprintf(fp, - "%s %s\n", getIndentSpace(indent), cmt.string()); - } - if (strstr(cmt.string(), "@deprecated") != NULL) { - deprecated = true; - } - } - if (haveComment) { - fprintf(fp,"%s */\n", getIndentSpace(indent)); - } - if (deprecated) { - fprintf(fp, "%s@Deprecated\n", getIndentSpace(indent)); - } - fprintf(fp, id_format, - getIndentSpace(indent), - flattenSymbol(name8).string(), (int)sym.int32Val); - } - - for (i=0; i<N; i++) { - const AaptSymbolEntry& sym = symbols->getSymbols().valueAt(i); - if (sym.typeCode != AaptSymbolEntry::TYPE_STRING) { - continue; - } - if (!assets->isJavaSymbol(sym, includePrivate)) { - continue; - } - String8 name8(sym.name); - String16 comment(sym.comment); - bool deprecated = false; - if (comment.size() > 0) { - String8 cmt(comment); - fprintf(fp, - "%s/** %s\n" - "%s */\n", - getIndentSpace(indent), cmt.string(), - getIndentSpace(indent)); - if (strstr(cmt.string(), "@deprecated") != NULL) { - deprecated = true; - } - } else if (sym.isPublic && !includePrivate) { - sym.sourcePos.warning("No comment for public symbol %s:%s/%s", - assets->getPackage().string(), className.string(), - String8(sym.name).string()); - } - if (deprecated) { - fprintf(fp, "%s@Deprecated\n", getIndentSpace(indent)); - } - fprintf(fp, "%spublic static final String %s=\"%s\";\n", - getIndentSpace(indent), - flattenSymbol(name8).string(), sym.stringVal.string()); - } - - sp<AaptSymbols> styleableSymbols; - - N = symbols->getNestedSymbols().size(); - for (i=0; i<N; i++) { - sp<AaptSymbols> nsymbols = symbols->getNestedSymbols().valueAt(i); - String8 nclassName(symbols->getNestedSymbols().keyAt(i)); - if (nclassName == "styleable") { - styleableSymbols = nsymbols; - } else { - err = writeSymbolClass(fp, assets, includePrivate, nsymbols, nclassName, indent, nonConstantId); - } - if (err != NO_ERROR) { - return err; - } - } - - if (styleableSymbols != NULL) { - err = writeLayoutClasses(fp, assets, styleableSymbols, indent, includePrivate); - if (err != NO_ERROR) { - return err; - } - } - - indent--; - fprintf(fp, "%s}\n", getIndentSpace(indent)); - return NO_ERROR; -} - -static status_t writeTextSymbolClass( - FILE* fp, const sp<AaptAssets>& assets, bool includePrivate, - const sp<AaptSymbols>& symbols, const String8& className) -{ - size_t i; - status_t err = NO_ERROR; - - size_t N = symbols->getSymbols().size(); - for (i=0; i<N; i++) { - const AaptSymbolEntry& sym = symbols->getSymbols().valueAt(i); - if (sym.typeCode != AaptSymbolEntry::TYPE_INT32) { - continue; - } - - if (!assets->isJavaSymbol(sym, includePrivate)) { - continue; - } - - String8 name8(sym.name); - fprintf(fp, "int %s %s 0x%08x\n", - className.string(), - flattenSymbol(name8).string(), (int)sym.int32Val); - } - - N = symbols->getNestedSymbols().size(); - for (i=0; i<N; i++) { - sp<AaptSymbols> nsymbols = symbols->getNestedSymbols().valueAt(i); - String8 nclassName(symbols->getNestedSymbols().keyAt(i)); - if (nclassName == "styleable") { - err = writeTextLayoutClasses(fp, assets, nsymbols, includePrivate); - } else { - err = writeTextSymbolClass(fp, assets, includePrivate, nsymbols, nclassName); - } - if (err != NO_ERROR) { - return err; - } - } - - return NO_ERROR; -} - -status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets, - const String8& package, bool includePrivate) -{ - if (!bundle->getRClassDir()) { - return NO_ERROR; - } - - const char* textSymbolsDest = bundle->getOutputTextSymbols(); - - String8 R("R"); - const size_t N = assets->getSymbols().size(); - for (size_t i=0; i<N; i++) { - sp<AaptSymbols> symbols = assets->getSymbols().valueAt(i); - String8 className(assets->getSymbols().keyAt(i)); - String8 dest(bundle->getRClassDir()); - - if (bundle->getMakePackageDirs()) { - String8 pkg(package); - const char* last = pkg.string(); - const char* s = last-1; - do { - s++; - if (s > last && (*s == '.' || *s == 0)) { - String8 part(last, s-last); - dest.appendPath(part); -#ifdef HAVE_MS_C_RUNTIME - _mkdir(dest.string()); -#else - mkdir(dest.string(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP); -#endif - last = s+1; - } - } while (*s); - } - dest.appendPath(className); - dest.append(".java"); - FILE* fp = fopen(dest.string(), "w+"); - if (fp == NULL) { - fprintf(stderr, "ERROR: Unable to open class file %s: %s\n", - dest.string(), strerror(errno)); - return UNKNOWN_ERROR; - } - if (bundle->getVerbose()) { - printf(" Writing symbols for class %s.\n", className.string()); - } - - fprintf(fp, - "/* AUTO-GENERATED FILE. DO NOT MODIFY.\n" - " *\n" - " * This class was automatically generated by the\n" - " * aapt tool from the resource data it found. It\n" - " * should not be modified by hand.\n" - " */\n" - "\n" - "package %s;\n\n", package.string()); - - status_t err = writeSymbolClass(fp, assets, includePrivate, symbols, - className, 0, bundle->getNonConstantId()); - if (err != NO_ERROR) { - return err; - } - fclose(fp); - - if (textSymbolsDest != NULL && R == className) { - String8 textDest(textSymbolsDest); - textDest.appendPath(className); - textDest.append(".txt"); - - FILE* fp = fopen(textDest.string(), "w+"); - if (fp == NULL) { - fprintf(stderr, "ERROR: Unable to open text symbol file %s: %s\n", - textDest.string(), strerror(errno)); - return UNKNOWN_ERROR; - } - if (bundle->getVerbose()) { - printf(" Writing text symbols for class %s.\n", className.string()); - } - - status_t err = writeTextSymbolClass(fp, assets, includePrivate, symbols, - className); - if (err != NO_ERROR) { - return err; - } - fclose(fp); - } - - // If we were asked to generate a dependency file, we'll go ahead and add this R.java - // as a target in the dependency file right next to it. - if (bundle->getGenDependencies() && R == className) { - // Add this R.java to the dependency file - String8 dependencyFile(bundle->getRClassDir()); - dependencyFile.appendPath("R.java.d"); - - FILE *fp = fopen(dependencyFile.string(), "a"); - fprintf(fp,"%s \\\n", dest.string()); - fclose(fp); - } - } - - return NO_ERROR; -} - - -class ProguardKeepSet -{ -public: - // { rule --> { file locations } } - KeyedVector<String8, SortedVector<String8> > rules; - - void add(const String8& rule, const String8& where); -}; - -void ProguardKeepSet::add(const String8& rule, const String8& where) -{ - ssize_t index = rules.indexOfKey(rule); - if (index < 0) { - index = rules.add(rule, SortedVector<String8>()); - } - rules.editValueAt(index).add(where); -} - -void -addProguardKeepRule(ProguardKeepSet* keep, const String8& inClassName, - const char* pkg, const String8& srcName, int line) -{ - String8 className(inClassName); - if (pkg != NULL) { - // asdf --> package.asdf - // .asdf .a.b --> package.asdf package.a.b - // asdf.adsf --> asdf.asdf - const char* p = className.string(); - const char* q = strchr(p, '.'); - if (p == q) { - className = pkg; - className.append(inClassName); - } else if (q == NULL) { - className = pkg; - className.append("."); - className.append(inClassName); - } - } - - String8 rule("-keep class "); - rule += className; - rule += " { <init>(...); }"; - - String8 location("view "); - location += srcName; - char lineno[20]; - sprintf(lineno, ":%d", line); - location += lineno; - - keep->add(rule, location); -} - -void -addProguardKeepMethodRule(ProguardKeepSet* keep, const String8& memberName, - const char* pkg, const String8& srcName, int line) -{ - String8 rule("-keepclassmembers class * { *** "); - rule += memberName; - rule += "(...); }"; - - String8 location("onClick "); - location += srcName; - char lineno[20]; - sprintf(lineno, ":%d", line); - location += lineno; - - keep->add(rule, location); -} - -status_t -writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& assets) -{ - status_t err; - ResXMLTree tree; - size_t len; - ResXMLTree::event_code_t code; - int depth = 0; - bool inApplication = false; - String8 error; - sp<AaptGroup> assGroup; - sp<AaptFile> assFile; - String8 pkg; - - // First, look for a package file to parse. This is required to - // be able to generate the resource information. - assGroup = assets->getFiles().valueFor(String8("AndroidManifest.xml")); - if (assGroup == NULL) { - fprintf(stderr, "ERROR: No AndroidManifest.xml file found.\n"); - return -1; - } - - if (assGroup->getFiles().size() != 1) { - fprintf(stderr, "warning: Multiple AndroidManifest.xml files found, using %s\n", - assGroup->getFiles().valueAt(0)->getPrintableSource().string()); - } - - assFile = assGroup->getFiles().valueAt(0); - - err = parseXMLResource(assFile, &tree); - if (err != NO_ERROR) { - return err; - } - - tree.restart(); - - while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::END_TAG) { - if (/* name == "Application" && */ depth == 2) { - inApplication = false; - } - depth--; - continue; - } - if (code != ResXMLTree::START_TAG) { - continue; - } - depth++; - String8 tag(tree.getElementName(&len)); - // printf("Depth %d tag %s\n", depth, tag.string()); - bool keepTag = false; - if (depth == 1) { - if (tag != "manifest") { - fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n"); - return -1; - } - pkg = getAttribute(tree, NULL, "package", NULL); - } else if (depth == 2) { - if (tag == "application") { - inApplication = true; - keepTag = true; - - String8 agent = getAttribute(tree, "http://schemas.android.com/apk/res/android", - "backupAgent", &error); - if (agent.length() > 0) { - addProguardKeepRule(keep, agent, pkg.string(), - assFile->getPrintableSource(), tree.getLineNumber()); - } - } else if (tag == "instrumentation") { - keepTag = true; - } - } - if (!keepTag && inApplication && depth == 3) { - if (tag == "activity" || tag == "service" || tag == "receiver" || tag == "provider") { - keepTag = true; - } - } - if (keepTag) { - String8 name = getAttribute(tree, "http://schemas.android.com/apk/res/android", - "name", &error); - if (error != "") { - fprintf(stderr, "ERROR: %s\n", error.string()); - return -1; - } - if (name.length() > 0) { - addProguardKeepRule(keep, name, pkg.string(), - assFile->getPrintableSource(), tree.getLineNumber()); - } - } - } - - return NO_ERROR; -} - -struct NamespaceAttributePair { - const char* ns; - const char* attr; - - NamespaceAttributePair(const char* n, const char* a) : ns(n), attr(a) {} - NamespaceAttributePair() : ns(NULL), attr(NULL) {} -}; - -status_t -writeProguardForXml(ProguardKeepSet* keep, const sp<AaptFile>& layoutFile, - const char* startTag, const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs) -{ - status_t err; - ResXMLTree tree; - size_t len; - ResXMLTree::event_code_t code; - - err = parseXMLResource(layoutFile, &tree); - if (err != NO_ERROR) { - return err; - } - - tree.restart(); - - if (startTag != NULL) { - bool haveStart = false; - while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - if (code != ResXMLTree::START_TAG) { - continue; - } - String8 tag(tree.getElementName(&len)); - if (tag == startTag) { - haveStart = true; - } - break; - } - if (!haveStart) { - return NO_ERROR; - } - } - - while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - if (code != ResXMLTree::START_TAG) { - continue; - } - String8 tag(tree.getElementName(&len)); - - // If there is no '.', we'll assume that it's one of the built in names. - if (strchr(tag.string(), '.')) { - addProguardKeepRule(keep, tag, NULL, - layoutFile->getPrintableSource(), tree.getLineNumber()); - } else if (tagAttrPairs != NULL) { - ssize_t tagIndex = tagAttrPairs->indexOfKey(tag); - if (tagIndex >= 0) { - const Vector<NamespaceAttributePair>& nsAttrVector = tagAttrPairs->valueAt(tagIndex); - for (size_t i = 0; i < nsAttrVector.size(); i++) { - const NamespaceAttributePair& nsAttr = nsAttrVector[i]; - - ssize_t attrIndex = tree.indexOfAttribute(nsAttr.ns, nsAttr.attr); - if (attrIndex < 0) { - // fprintf(stderr, "%s:%d: <%s> does not have attribute %s:%s.\n", - // layoutFile->getPrintableSource().string(), tree.getLineNumber(), - // tag.string(), nsAttr.ns, nsAttr.attr); - } else { - size_t len; - addProguardKeepRule(keep, - String8(tree.getAttributeStringValue(attrIndex, &len)), NULL, - layoutFile->getPrintableSource(), tree.getLineNumber()); - } - } - } - } - ssize_t attrIndex = tree.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE, "onClick"); - if (attrIndex >= 0) { - size_t len; - addProguardKeepMethodRule(keep, - String8(tree.getAttributeStringValue(attrIndex, &len)), NULL, - layoutFile->getPrintableSource(), tree.getLineNumber()); - } - } - - return NO_ERROR; -} - -static void addTagAttrPair(KeyedVector<String8, Vector<NamespaceAttributePair> >* dest, - const char* tag, const char* ns, const char* attr) { - String8 tagStr(tag); - ssize_t index = dest->indexOfKey(tagStr); - - if (index < 0) { - Vector<NamespaceAttributePair> vector; - vector.add(NamespaceAttributePair(ns, attr)); - dest->add(tagStr, vector); - } else { - dest->editValueAt(index).add(NamespaceAttributePair(ns, attr)); - } -} - -status_t -writeProguardForLayouts(ProguardKeepSet* keep, const sp<AaptAssets>& assets) -{ - status_t err; - - // tag:attribute pairs that should be checked in layout files. - KeyedVector<String8, Vector<NamespaceAttributePair> > kLayoutTagAttrPairs; - addTagAttrPair(&kLayoutTagAttrPairs, "view", NULL, "class"); - addTagAttrPair(&kLayoutTagAttrPairs, "fragment", NULL, "class"); - addTagAttrPair(&kLayoutTagAttrPairs, "fragment", RESOURCES_ANDROID_NAMESPACE, "name"); - - // tag:attribute pairs that should be checked in xml files. - KeyedVector<String8, Vector<NamespaceAttributePair> > kXmlTagAttrPairs; - addTagAttrPair(&kXmlTagAttrPairs, "PreferenceScreen", RESOURCES_ANDROID_NAMESPACE, "fragment"); - addTagAttrPair(&kXmlTagAttrPairs, "header", RESOURCES_ANDROID_NAMESPACE, "fragment"); - - const Vector<sp<AaptDir> >& dirs = assets->resDirs(); - const size_t K = dirs.size(); - for (size_t k=0; k<K; k++) { - const sp<AaptDir>& d = dirs.itemAt(k); - const String8& dirName = d->getLeaf(); - const char* startTag = NULL; - const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs = NULL; - if ((dirName == String8("layout")) || (strncmp(dirName.string(), "layout-", 7) == 0)) { - tagAttrPairs = &kLayoutTagAttrPairs; - } else if ((dirName == String8("xml")) || (strncmp(dirName.string(), "xml-", 4) == 0)) { - startTag = "PreferenceScreen"; - tagAttrPairs = &kXmlTagAttrPairs; - } else if ((dirName == String8("menu")) || (strncmp(dirName.string(), "menu-", 5) == 0)) { - startTag = "menu"; - tagAttrPairs = NULL; - } else { - continue; - } - - const KeyedVector<String8,sp<AaptGroup> > groups = d->getFiles(); - const size_t N = groups.size(); - for (size_t i=0; i<N; i++) { - const sp<AaptGroup>& group = groups.valueAt(i); - const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& files = group->getFiles(); - const size_t M = files.size(); - for (size_t j=0; j<M; j++) { - err = writeProguardForXml(keep, files.valueAt(j), startTag, tagAttrPairs); - if (err < 0) { - return err; - } - } - } - } - // Handle the overlays - sp<AaptAssets> overlay = assets->getOverlay(); - if (overlay.get()) { - return writeProguardForLayouts(keep, overlay); - } - - return NO_ERROR; -} - -status_t -writeProguardFile(Bundle* bundle, const sp<AaptAssets>& assets) -{ - status_t err = -1; - - if (!bundle->getProguardFile()) { - return NO_ERROR; - } - - ProguardKeepSet keep; - - err = writeProguardForAndroidManifest(&keep, assets); - if (err < 0) { - return err; - } - - err = writeProguardForLayouts(&keep, assets); - if (err < 0) { - return err; - } - - FILE* fp = fopen(bundle->getProguardFile(), "w+"); - if (fp == NULL) { - fprintf(stderr, "ERROR: Unable to open class file %s: %s\n", - bundle->getProguardFile(), strerror(errno)); - return UNKNOWN_ERROR; - } - - const KeyedVector<String8, SortedVector<String8> >& rules = keep.rules; - const size_t N = rules.size(); - for (size_t i=0; i<N; i++) { - const SortedVector<String8>& locations = rules.valueAt(i); - const size_t M = locations.size(); - for (size_t j=0; j<M; j++) { - fprintf(fp, "# %s\n", locations.itemAt(j).string()); - } - fprintf(fp, "%s\n\n", rules.keyAt(i).string()); - } - fclose(fp); - - return err; -} - -// Loops through the string paths and writes them to the file pointer -// Each file path is written on its own line with a terminating backslash. -status_t writePathsToFile(const sp<FilePathStore>& files, FILE* fp) -{ - status_t deps = -1; - for (size_t file_i = 0; file_i < files->size(); ++file_i) { - // Add the full file path to the dependency file - fprintf(fp, "%s \\\n", files->itemAt(file_i).string()); - deps++; - } - return deps; -} - -status_t -writeDependencyPreReqs(Bundle* bundle, const sp<AaptAssets>& assets, FILE* fp, bool includeRaw) -{ - status_t deps = -1; - deps += writePathsToFile(assets->getFullResPaths(), fp); - if (includeRaw) { - deps += writePathsToFile(assets->getFullAssetPaths(), fp); - } - return deps; -} diff --git a/tools/aapt/ResourceFilter.cpp b/tools/aapt/ResourceFilter.cpp deleted file mode 100644 index 8cfd2a5..0000000 --- a/tools/aapt/ResourceFilter.cpp +++ /dev/null @@ -1,112 +0,0 @@ -// -// Copyright 2011 The Android Open Source Project -// -// Build resource files from raw assets. -// - -#include "ResourceFilter.h" - -status_t -ResourceFilter::parse(const char* arg) -{ - if (arg == NULL) { - return 0; - } - - const char* p = arg; - const char* q; - - while (true) { - q = strchr(p, ','); - if (q == NULL) { - q = p + strlen(p); - } - - String8 part(p, q-p); - - if (part == "zz_ZZ") { - mContainsPseudo = true; - } - int axis; - uint32_t value; - if (AaptGroupEntry::parseNamePart(part, &axis, &value)) { - fprintf(stderr, "Invalid configuration: %s\n", arg); - fprintf(stderr, " "); - for (int i=0; i<p-arg; i++) { - fprintf(stderr, " "); - } - for (int i=0; i<q-p; i++) { - fprintf(stderr, "^"); - } - fprintf(stderr, "\n"); - return 1; - } - - ssize_t index = mData.indexOfKey(axis); - if (index < 0) { - mData.add(axis, SortedVector<uint32_t>()); - } - SortedVector<uint32_t>& sv = mData.editValueFor(axis); - sv.add(value); - // if it's a locale with a region, also match an unmodified locale of the - // same language - if (axis == AXIS_LANGUAGE) { - if (value & 0xffff0000) { - sv.add(value & 0x0000ffff); - } - } - p = q; - if (!*p) break; - p++; - } - - return NO_ERROR; -} - -bool -ResourceFilter::isEmpty() const -{ - return mData.size() == 0; -} - -bool -ResourceFilter::match(int axis, uint32_t value) const -{ - if (value == 0) { - // they didn't specify anything so take everything - return true; - } - ssize_t index = mData.indexOfKey(axis); - if (index < 0) { - // we didn't request anything on this axis so take everything - return true; - } - const SortedVector<uint32_t>& sv = mData.valueAt(index); - return sv.indexOf(value) >= 0; -} - -bool -ResourceFilter::match(int axis, const ResTable_config& config) const -{ - return match(axis, AaptGroupEntry::getConfigValueForAxis(config, axis)); -} - -bool -ResourceFilter::match(const ResTable_config& config) const -{ - for (int i=AXIS_START; i<=AXIS_END; i++) { - if (!match(i, AaptGroupEntry::getConfigValueForAxis(config, i))) { - return false; - } - } - return true; -} - -const SortedVector<uint32_t>* ResourceFilter::configsForAxis(int axis) const -{ - ssize_t index = mData.indexOfKey(axis); - if (index < 0) { - return NULL; - } - return &mData.valueAt(index); -} diff --git a/tools/aapt/ResourceFilter.h b/tools/aapt/ResourceFilter.h deleted file mode 100644 index 647b7bb..0000000 --- a/tools/aapt/ResourceFilter.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// Copyright 2011 The Android Open Source Project -// -// Build resource files from raw assets. -// - -#ifndef RESOURCE_FILTER_H -#define RESOURCE_FILTER_H - -#include "AaptAssets.h" - -/** - * Implements logic for parsing and handling "-c" and "--preferred-configurations" - * options. - */ -class ResourceFilter -{ -public: - ResourceFilter() : mData(), mContainsPseudo(false) {} - status_t parse(const char* arg); - bool isEmpty() const; - bool match(int axis, uint32_t value) const; - bool match(int axis, const ResTable_config& config) const; - bool match(const ResTable_config& config) const; - const SortedVector<uint32_t>* configsForAxis(int axis) const; - inline bool containsPseudo() const { return mContainsPseudo; } - -private: - KeyedVector<int,SortedVector<uint32_t> > mData; - bool mContainsPseudo; -}; - -#endif diff --git a/tools/aapt/ResourceIdCache.cpp b/tools/aapt/ResourceIdCache.cpp deleted file mode 100644 index e03f4f6..0000000 --- a/tools/aapt/ResourceIdCache.cpp +++ /dev/null @@ -1,107 +0,0 @@ -// -// Copyright 2012 The Android Open Source Project -// -// Manage a resource ID cache. - -#define LOG_TAG "ResourceIdCache" - -#include <utils/String16.h> -#include <utils/Log.h> -#include "ResourceIdCache.h" -#include <map> -using namespace std; - - -static size_t mHits = 0; -static size_t mMisses = 0; -static size_t mCollisions = 0; - -static const size_t MAX_CACHE_ENTRIES = 2048; -static const android::String16 TRUE16("1"); -static const android::String16 FALSE16("0"); - -struct CacheEntry { - // concatenation of the relevant strings into a single instance - android::String16 hashedName; - uint32_t id; - - CacheEntry() {} - CacheEntry(const android::String16& name, uint32_t resId) : hashedName(name), id(resId) { } -}; - -static map< uint32_t, CacheEntry > mIdMap; - - -// djb2; reasonable choice for strings when collisions aren't particularly important -static inline uint32_t hashround(uint32_t hash, int c) { - return ((hash << 5) + hash) + c; /* hash * 33 + c */ -} - -static uint32_t hash(const android::String16& hashableString) { - uint32_t hash = 5381; - const char16_t* str = hashableString.string(); - while (int c = *str++) hash = hashround(hash, c); - return hash; -} - -namespace android { - -static inline String16 makeHashableName(const android::String16& package, - const android::String16& type, - const android::String16& name, - bool onlyPublic) { - String16 hashable = String16(name); - hashable += type; - hashable += package; - hashable += (onlyPublic ? TRUE16 : FALSE16); - return hashable; -} - -uint32_t ResourceIdCache::lookup(const android::String16& package, - const android::String16& type, - const android::String16& name, - bool onlyPublic) { - const String16 hashedName = makeHashableName(package, type, name, onlyPublic); - const uint32_t hashcode = hash(hashedName); - map<uint32_t, CacheEntry>::iterator item = mIdMap.find(hashcode); - if (item == mIdMap.end()) { - // cache miss - mMisses++; - return 0; - } - - // legit match? - if (hashedName == (*item).second.hashedName) { - mHits++; - return (*item).second.id; - } - - // collision - mCollisions++; - mIdMap.erase(hashcode); - return 0; -} - -// returns the resource ID being stored, for callsite convenience -uint32_t ResourceIdCache::store(const android::String16& package, - const android::String16& type, - const android::String16& name, - bool onlyPublic, - uint32_t resId) { - if (mIdMap.size() < MAX_CACHE_ENTRIES) { - const String16 hashedName = makeHashableName(package, type, name, onlyPublic); - const uint32_t hashcode = hash(hashedName); - mIdMap[hashcode] = CacheEntry(hashedName, resId); - } - return resId; -} - -void ResourceIdCache::dump() { - printf("ResourceIdCache dump:\n"); - printf("Size: %ld\n", mIdMap.size()); - printf("Hits: %ld\n", mHits); - printf("Misses: %ld\n", mMisses); - printf("(Collisions: %ld)\n", mCollisions); -} - -} diff --git a/tools/aapt/ResourceIdCache.h b/tools/aapt/ResourceIdCache.h deleted file mode 100644 index 65f7781..0000000 --- a/tools/aapt/ResourceIdCache.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright 2012 The Android Open Source Project -// -// Manage a resource ID cache. - -#ifndef RESOURCE_ID_CACHE_H -#define RESOURCE_ID_CACHE_H - -namespace android { -class android::String16; - -class ResourceIdCache { -public: - static uint32_t lookup(const android::String16& package, - const android::String16& type, - const android::String16& name, - bool onlyPublic); - - static uint32_t store(const android::String16& package, - const android::String16& type, - const android::String16& name, - bool onlyPublic, - uint32_t resId); - - static void dump(void); -}; - -} - -#endif diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp deleted file mode 100644 index 52ebaf0..0000000 --- a/tools/aapt/ResourceTable.cpp +++ /dev/null @@ -1,3905 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Build resource files from raw assets. -// - -#include "ResourceTable.h" - -#include "XMLNode.h" -#include "ResourceFilter.h" -#include "ResourceIdCache.h" - -#include <androidfw/ResourceTypes.h> -#include <utils/ByteOrder.h> -#include <stdarg.h> - -#define NOISY(x) //x - -status_t compileXmlFile(const sp<AaptAssets>& assets, - const sp<AaptFile>& target, - ResourceTable* table, - int options) -{ - sp<XMLNode> root = XMLNode::parse(target); - if (root == NULL) { - return UNKNOWN_ERROR; - } - - return compileXmlFile(assets, root, target, table, options); -} - -status_t compileXmlFile(const sp<AaptAssets>& assets, - const sp<AaptFile>& target, - const sp<AaptFile>& outTarget, - ResourceTable* table, - int options) -{ - sp<XMLNode> root = XMLNode::parse(target); - if (root == NULL) { - return UNKNOWN_ERROR; - } - - return compileXmlFile(assets, root, outTarget, table, options); -} - -status_t compileXmlFile(const sp<AaptAssets>& assets, - const sp<XMLNode>& root, - const sp<AaptFile>& target, - ResourceTable* table, - int options) -{ - if ((options&XML_COMPILE_STRIP_WHITESPACE) != 0) { - root->removeWhitespace(true, NULL); - } else if ((options&XML_COMPILE_COMPACT_WHITESPACE) != 0) { - root->removeWhitespace(false, NULL); - } - - if ((options&XML_COMPILE_UTF8) != 0) { - root->setUTF8(true); - } - - bool hasErrors = false; - - if ((options&XML_COMPILE_ASSIGN_ATTRIBUTE_IDS) != 0) { - status_t err = root->assignResourceIds(assets, table); - if (err != NO_ERROR) { - hasErrors = true; - } - } - - status_t err = root->parseValues(assets, table); - if (err != NO_ERROR) { - hasErrors = true; - } - - if (hasErrors) { - return UNKNOWN_ERROR; - } - - NOISY(printf("Input XML Resource:\n")); - NOISY(root->print()); - err = root->flatten(target, - (options&XML_COMPILE_STRIP_COMMENTS) != 0, - (options&XML_COMPILE_STRIP_RAW_VALUES) != 0); - if (err != NO_ERROR) { - return err; - } - - NOISY(printf("Output XML Resource:\n")); - NOISY(ResXMLTree tree; - tree.setTo(target->getData(), target->getSize()); - printXMLBlock(&tree)); - - target->setCompressionMethod(ZipEntry::kCompressDeflated); - - return err; -} - -#undef NOISY -#define NOISY(x) //x - -struct flag_entry -{ - const char16_t* name; - size_t nameLen; - uint32_t value; - const char* description; -}; - -static const char16_t referenceArray[] = - { 'r', 'e', 'f', 'e', 'r', 'e', 'n', 'c', 'e' }; -static const char16_t stringArray[] = - { 's', 't', 'r', 'i', 'n', 'g' }; -static const char16_t integerArray[] = - { 'i', 'n', 't', 'e', 'g', 'e', 'r' }; -static const char16_t booleanArray[] = - { 'b', 'o', 'o', 'l', 'e', 'a', 'n' }; -static const char16_t colorArray[] = - { 'c', 'o', 'l', 'o', 'r' }; -static const char16_t floatArray[] = - { 'f', 'l', 'o', 'a', 't' }; -static const char16_t dimensionArray[] = - { 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n' }; -static const char16_t fractionArray[] = - { 'f', 'r', 'a', 'c', 't', 'i', 'o', 'n' }; -static const char16_t enumArray[] = - { 'e', 'n', 'u', 'm' }; -static const char16_t flagsArray[] = - { 'f', 'l', 'a', 'g', 's' }; - -static const flag_entry gFormatFlags[] = { - { referenceArray, sizeof(referenceArray)/2, ResTable_map::TYPE_REFERENCE, - "a reference to another resource, in the form \"<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>\"\n" - "or to a theme attribute in the form \"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>\"."}, - { stringArray, sizeof(stringArray)/2, ResTable_map::TYPE_STRING, - "a string value, using '\\\\;' to escape characters such as '\\\\n' or '\\\\uxxxx' for a unicode character." }, - { integerArray, sizeof(integerArray)/2, ResTable_map::TYPE_INTEGER, - "an integer value, such as \"<code>100</code>\"." }, - { booleanArray, sizeof(booleanArray)/2, ResTable_map::TYPE_BOOLEAN, - "a boolean value, either \"<code>true</code>\" or \"<code>false</code>\"." }, - { colorArray, sizeof(colorArray)/2, ResTable_map::TYPE_COLOR, - "a color value, in the form of \"<code>#<i>rgb</i></code>\", \"<code>#<i>argb</i></code>\",\n" - "\"<code>#<i>rrggbb</i></code>\", or \"<code>#<i>aarrggbb</i></code>\"." }, - { floatArray, sizeof(floatArray)/2, ResTable_map::TYPE_FLOAT, - "a floating point value, such as \"<code>1.2</code>\"."}, - { dimensionArray, sizeof(dimensionArray)/2, ResTable_map::TYPE_DIMENSION, - "a dimension value, which is a floating point number appended with a unit such as \"<code>14.5sp</code>\".\n" - "Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\n" - "in (inches), mm (millimeters)." }, - { fractionArray, sizeof(fractionArray)/2, ResTable_map::TYPE_FRACTION, - "a fractional value, which is a floating point number appended with either % or %p, such as \"<code>14.5%</code>\".\n" - "The % suffix always means a percentage of the base size; the optional %p suffix provides a size relative to\n" - "some parent container." }, - { enumArray, sizeof(enumArray)/2, ResTable_map::TYPE_ENUM, NULL }, - { flagsArray, sizeof(flagsArray)/2, ResTable_map::TYPE_FLAGS, NULL }, - { NULL, 0, 0, NULL } -}; - -static const char16_t suggestedArray[] = { 's', 'u', 'g', 'g', 'e', 's', 't', 'e', 'd' }; - -static const flag_entry l10nRequiredFlags[] = { - { suggestedArray, sizeof(suggestedArray)/2, ResTable_map::L10N_SUGGESTED, NULL }, - { NULL, 0, 0, NULL } -}; - -static const char16_t nulStr[] = { 0 }; - -static uint32_t parse_flags(const char16_t* str, size_t len, - const flag_entry* flags, bool* outError = NULL) -{ - while (len > 0 && isspace(*str)) { - str++; - len--; - } - while (len > 0 && isspace(str[len-1])) { - len--; - } - - const char16_t* const end = str + len; - uint32_t value = 0; - - while (str < end) { - const char16_t* div = str; - while (div < end && *div != '|') { - div++; - } - - const flag_entry* cur = flags; - while (cur->name) { - if (strzcmp16(cur->name, cur->nameLen, str, div-str) == 0) { - value |= cur->value; - break; - } - cur++; - } - - if (!cur->name) { - if (outError) *outError = true; - return 0; - } - - str = div < end ? div+1 : div; - } - - if (outError) *outError = false; - return value; -} - -static String16 mayOrMust(int type, int flags) -{ - if ((type&(~flags)) == 0) { - return String16("<p>Must"); - } - - return String16("<p>May"); -} - -static void appendTypeInfo(ResourceTable* outTable, const String16& pkg, - const String16& typeName, const String16& ident, int type, - const flag_entry* flags) -{ - bool hadType = false; - while (flags->name) { - if ((type&flags->value) != 0 && flags->description != NULL) { - String16 fullMsg(mayOrMust(type, flags->value)); - fullMsg.append(String16(" be ")); - fullMsg.append(String16(flags->description)); - outTable->appendTypeComment(pkg, typeName, ident, fullMsg); - hadType = true; - } - flags++; - } - if (hadType && (type&ResTable_map::TYPE_REFERENCE) == 0) { - outTable->appendTypeComment(pkg, typeName, ident, - String16("<p>This may also be a reference to a resource (in the form\n" - "\"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>\") or\n" - "theme attribute (in the form\n" - "\"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>\")\n" - "containing a value of this type.")); - } -} - -struct PendingAttribute -{ - const String16 myPackage; - const SourcePos sourcePos; - const bool appendComment; - int32_t type; - String16 ident; - String16 comment; - bool hasErrors; - bool added; - - PendingAttribute(String16 _package, const sp<AaptFile>& in, - ResXMLTree& block, bool _appendComment) - : myPackage(_package) - , sourcePos(in->getPrintableSource(), block.getLineNumber()) - , appendComment(_appendComment) - , type(ResTable_map::TYPE_ANY) - , hasErrors(false) - , added(false) - { - } - - status_t createIfNeeded(ResourceTable* outTable) - { - if (added || hasErrors) { - return NO_ERROR; - } - added = true; - - String16 attr16("attr"); - - if (outTable->hasBagOrEntry(myPackage, attr16, ident)) { - sourcePos.error("Attribute \"%s\" has already been defined\n", - String8(ident).string()); - hasErrors = true; - return UNKNOWN_ERROR; - } - - char numberStr[16]; - sprintf(numberStr, "%d", type); - status_t err = outTable->addBag(sourcePos, myPackage, - attr16, ident, String16(""), - String16("^type"), - String16(numberStr), NULL, NULL); - if (err != NO_ERROR) { - hasErrors = true; - return err; - } - outTable->appendComment(myPackage, attr16, ident, comment, appendComment); - //printf("Attribute %s comment: %s\n", String8(ident).string(), - // String8(comment).string()); - return err; - } -}; - -static status_t compileAttribute(const sp<AaptFile>& in, - ResXMLTree& block, - const String16& myPackage, - ResourceTable* outTable, - String16* outIdent = NULL, - bool inStyleable = false) -{ - PendingAttribute attr(myPackage, in, block, inStyleable); - - const String16 attr16("attr"); - const String16 id16("id"); - - // Attribute type constants. - const String16 enum16("enum"); - const String16 flag16("flag"); - - ResXMLTree::event_code_t code; - size_t len; - status_t err; - - ssize_t identIdx = block.indexOfAttribute(NULL, "name"); - if (identIdx >= 0) { - attr.ident = String16(block.getAttributeStringValue(identIdx, &len)); - if (outIdent) { - *outIdent = attr.ident; - } - } else { - attr.sourcePos.error("A 'name' attribute is required for <attr>\n"); - attr.hasErrors = true; - } - - attr.comment = String16( - block.getComment(&len) ? block.getComment(&len) : nulStr); - - ssize_t typeIdx = block.indexOfAttribute(NULL, "format"); - if (typeIdx >= 0) { - String16 typeStr = String16(block.getAttributeStringValue(typeIdx, &len)); - attr.type = parse_flags(typeStr.string(), typeStr.size(), gFormatFlags); - if (attr.type == 0) { - attr.sourcePos.error("Tag <attr> 'format' attribute value \"%s\" not valid\n", - String8(typeStr).string()); - attr.hasErrors = true; - } - attr.createIfNeeded(outTable); - } else if (!inStyleable) { - // Attribute definitions outside of styleables always define the - // attribute as a generic value. - attr.createIfNeeded(outTable); - } - - //printf("Attribute %s: type=0x%08x\n", String8(attr.ident).string(), attr.type); - - ssize_t minIdx = block.indexOfAttribute(NULL, "min"); - if (minIdx >= 0) { - String16 val = String16(block.getAttributeStringValue(minIdx, &len)); - if (!ResTable::stringToInt(val.string(), val.size(), NULL)) { - attr.sourcePos.error("Tag <attr> 'min' attribute must be a number, not \"%s\"\n", - String8(val).string()); - attr.hasErrors = true; - } - attr.createIfNeeded(outTable); - if (!attr.hasErrors) { - err = outTable->addBag(attr.sourcePos, myPackage, attr16, attr.ident, - String16(""), String16("^min"), String16(val), NULL, NULL); - if (err != NO_ERROR) { - attr.hasErrors = true; - } - } - } - - ssize_t maxIdx = block.indexOfAttribute(NULL, "max"); - if (maxIdx >= 0) { - String16 val = String16(block.getAttributeStringValue(maxIdx, &len)); - if (!ResTable::stringToInt(val.string(), val.size(), NULL)) { - attr.sourcePos.error("Tag <attr> 'max' attribute must be a number, not \"%s\"\n", - String8(val).string()); - attr.hasErrors = true; - } - attr.createIfNeeded(outTable); - if (!attr.hasErrors) { - err = outTable->addBag(attr.sourcePos, myPackage, attr16, attr.ident, - String16(""), String16("^max"), String16(val), NULL, NULL); - attr.hasErrors = true; - } - } - - if ((minIdx >= 0 || maxIdx >= 0) && (attr.type&ResTable_map::TYPE_INTEGER) == 0) { - attr.sourcePos.error("Tag <attr> must have format=integer attribute if using max or min\n"); - attr.hasErrors = true; - } - - ssize_t l10nIdx = block.indexOfAttribute(NULL, "localization"); - if (l10nIdx >= 0) { - const uint16_t* str = block.getAttributeStringValue(l10nIdx, &len); - bool error; - uint32_t l10n_required = parse_flags(str, len, l10nRequiredFlags, &error); - if (error) { - attr.sourcePos.error("Tag <attr> 'localization' attribute value \"%s\" not valid\n", - String8(str).string()); - attr.hasErrors = true; - } - attr.createIfNeeded(outTable); - if (!attr.hasErrors) { - char buf[11]; - sprintf(buf, "%d", l10n_required); - err = outTable->addBag(attr.sourcePos, myPackage, attr16, attr.ident, - String16(""), String16("^l10n"), String16(buf), NULL, NULL); - if (err != NO_ERROR) { - attr.hasErrors = true; - } - } - } - - String16 enumOrFlagsComment; - - while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::START_TAG) { - uint32_t localType = 0; - if (strcmp16(block.getElementName(&len), enum16.string()) == 0) { - localType = ResTable_map::TYPE_ENUM; - } else if (strcmp16(block.getElementName(&len), flag16.string()) == 0) { - localType = ResTable_map::TYPE_FLAGS; - } else { - SourcePos(in->getPrintableSource(), block.getLineNumber()) - .error("Tag <%s> can not appear inside <attr>, only <enum> or <flag>\n", - String8(block.getElementName(&len)).string()); - return UNKNOWN_ERROR; - } - - attr.createIfNeeded(outTable); - - if (attr.type == ResTable_map::TYPE_ANY) { - // No type was explicitly stated, so supplying enum tags - // implicitly creates an enum or flag. - attr.type = 0; - } - - if ((attr.type&(ResTable_map::TYPE_ENUM|ResTable_map::TYPE_FLAGS)) == 0) { - // Wasn't originally specified as an enum, so update its type. - attr.type |= localType; - if (!attr.hasErrors) { - char numberStr[16]; - sprintf(numberStr, "%d", attr.type); - err = outTable->addBag(SourcePos(in->getPrintableSource(), block.getLineNumber()), - myPackage, attr16, attr.ident, String16(""), - String16("^type"), String16(numberStr), NULL, NULL, true); - if (err != NO_ERROR) { - attr.hasErrors = true; - } - } - } else if ((uint32_t)(attr.type&(ResTable_map::TYPE_ENUM|ResTable_map::TYPE_FLAGS)) != localType) { - if (localType == ResTable_map::TYPE_ENUM) { - SourcePos(in->getPrintableSource(), block.getLineNumber()) - .error("<enum> attribute can not be used inside a flags format\n"); - attr.hasErrors = true; - } else { - SourcePos(in->getPrintableSource(), block.getLineNumber()) - .error("<flag> attribute can not be used inside a enum format\n"); - attr.hasErrors = true; - } - } - - String16 itemIdent; - ssize_t itemIdentIdx = block.indexOfAttribute(NULL, "name"); - if (itemIdentIdx >= 0) { - itemIdent = String16(block.getAttributeStringValue(itemIdentIdx, &len)); - } else { - SourcePos(in->getPrintableSource(), block.getLineNumber()) - .error("A 'name' attribute is required for <enum> or <flag>\n"); - attr.hasErrors = true; - } - - String16 value; - ssize_t valueIdx = block.indexOfAttribute(NULL, "value"); - if (valueIdx >= 0) { - value = String16(block.getAttributeStringValue(valueIdx, &len)); - } else { - SourcePos(in->getPrintableSource(), block.getLineNumber()) - .error("A 'value' attribute is required for <enum> or <flag>\n"); - attr.hasErrors = true; - } - if (!attr.hasErrors && !ResTable::stringToInt(value.string(), value.size(), NULL)) { - SourcePos(in->getPrintableSource(), block.getLineNumber()) - .error("Tag <enum> or <flag> 'value' attribute must be a number," - " not \"%s\"\n", - String8(value).string()); - attr.hasErrors = true; - } - - // Make sure an id is defined for this enum/flag identifier... - if (!attr.hasErrors && !outTable->hasBagOrEntry(itemIdent, &id16, &myPackage)) { - err = outTable->startBag(SourcePos(in->getPrintableSource(), block.getLineNumber()), - myPackage, id16, itemIdent, String16(), NULL); - if (err != NO_ERROR) { - attr.hasErrors = true; - } - } - - if (!attr.hasErrors) { - if (enumOrFlagsComment.size() == 0) { - enumOrFlagsComment.append(mayOrMust(attr.type, - ResTable_map::TYPE_ENUM|ResTable_map::TYPE_FLAGS)); - enumOrFlagsComment.append((attr.type&ResTable_map::TYPE_ENUM) - ? String16(" be one of the following constant values.") - : String16(" be one or more (separated by '|') of the following constant values.")); - enumOrFlagsComment.append(String16("</p>\n<table>\n" - "<colgroup align=\"left\" />\n" - "<colgroup align=\"left\" />\n" - "<colgroup align=\"left\" />\n" - "<tr><th>Constant</th><th>Value</th><th>Description</th></tr>")); - } - - enumOrFlagsComment.append(String16("\n<tr><td><code>")); - enumOrFlagsComment.append(itemIdent); - enumOrFlagsComment.append(String16("</code></td><td>")); - enumOrFlagsComment.append(value); - enumOrFlagsComment.append(String16("</td><td>")); - if (block.getComment(&len)) { - enumOrFlagsComment.append(String16(block.getComment(&len))); - } - enumOrFlagsComment.append(String16("</td></tr>")); - - err = outTable->addBag(SourcePos(in->getPrintableSource(), block.getLineNumber()), - myPackage, - attr16, attr.ident, String16(""), - itemIdent, value, NULL, NULL, false, true); - if (err != NO_ERROR) { - attr.hasErrors = true; - } - } - } else if (code == ResXMLTree::END_TAG) { - if (strcmp16(block.getElementName(&len), attr16.string()) == 0) { - break; - } - if ((attr.type&ResTable_map::TYPE_ENUM) != 0) { - if (strcmp16(block.getElementName(&len), enum16.string()) != 0) { - SourcePos(in->getPrintableSource(), block.getLineNumber()) - .error("Found tag </%s> where </enum> is expected\n", - String8(block.getElementName(&len)).string()); - return UNKNOWN_ERROR; - } - } else { - if (strcmp16(block.getElementName(&len), flag16.string()) != 0) { - SourcePos(in->getPrintableSource(), block.getLineNumber()) - .error("Found tag </%s> where </flag> is expected\n", - String8(block.getElementName(&len)).string()); - return UNKNOWN_ERROR; - } - } - } - } - - if (!attr.hasErrors && attr.added) { - appendTypeInfo(outTable, myPackage, attr16, attr.ident, attr.type, gFormatFlags); - } - - if (!attr.hasErrors && enumOrFlagsComment.size() > 0) { - enumOrFlagsComment.append(String16("\n</table>")); - outTable->appendTypeComment(myPackage, attr16, attr.ident, enumOrFlagsComment); - } - - - return NO_ERROR; -} - -bool localeIsDefined(const ResTable_config& config) -{ - return config.locale == 0; -} - -status_t parseAndAddBag(Bundle* bundle, - const sp<AaptFile>& in, - ResXMLTree* block, - const ResTable_config& config, - const String16& myPackage, - const String16& curType, - const String16& ident, - const String16& parentIdent, - const String16& itemIdent, - int32_t curFormat, - bool isFormatted, - const String16& product, - bool pseudolocalize, - const bool overwrite, - ResourceTable* outTable) -{ - status_t err; - const String16 item16("item"); - - String16 str; - Vector<StringPool::entry_style_span> spans; - err = parseStyledString(bundle, in->getPrintableSource().string(), - block, item16, &str, &spans, isFormatted, - pseudolocalize); - if (err != NO_ERROR) { - return err; - } - - NOISY(printf("Adding resource bag entry l=%c%c c=%c%c orien=%d d=%d " - " pid=%s, bag=%s, id=%s: %s\n", - config.language[0], config.language[1], - config.country[0], config.country[1], - config.orientation, config.density, - String8(parentIdent).string(), - String8(ident).string(), - String8(itemIdent).string(), - String8(str).string())); - - err = outTable->addBag(SourcePos(in->getPrintableSource(), block->getLineNumber()), - myPackage, curType, ident, parentIdent, itemIdent, str, - &spans, &config, overwrite, false, curFormat); - return err; -} - -/* - * Returns true if needle is one of the elements in the comma-separated list - * haystack, false otherwise. - */ -bool isInProductList(const String16& needle, const String16& haystack) { - const char16_t *needle2 = needle.string(); - const char16_t *haystack2 = haystack.string(); - size_t needlesize = needle.size(); - - while (*haystack2 != '\0') { - if (strncmp16(haystack2, needle2, needlesize) == 0) { - if (haystack2[needlesize] == '\0' || haystack2[needlesize] == ',') { - return true; - } - } - - while (*haystack2 != '\0' && *haystack2 != ',') { - haystack2++; - } - if (*haystack2 == ',') { - haystack2++; - } - } - - return false; -} - -status_t parseAndAddEntry(Bundle* bundle, - const sp<AaptFile>& in, - ResXMLTree* block, - const ResTable_config& config, - const String16& myPackage, - const String16& curType, - const String16& ident, - const String16& curTag, - bool curIsStyled, - int32_t curFormat, - bool isFormatted, - const String16& product, - bool pseudolocalize, - const bool overwrite, - ResourceTable* outTable) -{ - status_t err; - - String16 str; - Vector<StringPool::entry_style_span> spans; - err = parseStyledString(bundle, in->getPrintableSource().string(), block, - curTag, &str, curIsStyled ? &spans : NULL, - isFormatted, pseudolocalize); - - if (err < NO_ERROR) { - return err; - } - - /* - * If a product type was specified on the command line - * and also in the string, and the two are not the same, - * return without adding the string. - */ - - const char *bundleProduct = bundle->getProduct(); - if (bundleProduct == NULL) { - bundleProduct = ""; - } - - if (product.size() != 0) { - /* - * If the command-line-specified product is empty, only "default" - * matches. Other variants are skipped. This is so generation - * of the R.java file when the product is not known is predictable. - */ - - if (bundleProduct[0] == '\0') { - if (strcmp16(String16("default").string(), product.string()) != 0) { - return NO_ERROR; - } - } else { - /* - * The command-line product is not empty. - * If the product for this string is on the command-line list, - * it matches. "default" also matches, but only if nothing - * else has matched already. - */ - - if (isInProductList(product, String16(bundleProduct))) { - ; - } else if (strcmp16(String16("default").string(), product.string()) == 0 && - !outTable->hasBagOrEntry(myPackage, curType, ident, config)) { - ; - } else { - return NO_ERROR; - } - } - } - - NOISY(printf("Adding resource entry l=%c%c c=%c%c orien=%d d=%d id=%s: %s\n", - config.language[0], config.language[1], - config.country[0], config.country[1], - config.orientation, config.density, - String8(ident).string(), String8(str).string())); - - err = outTable->addEntry(SourcePos(in->getPrintableSource(), block->getLineNumber()), - myPackage, curType, ident, str, &spans, &config, - false, curFormat, overwrite); - - return err; -} - -status_t compileResourceFile(Bundle* bundle, - const sp<AaptAssets>& assets, - const sp<AaptFile>& in, - const ResTable_config& defParams, - const bool overwrite, - ResourceTable* outTable) -{ - ResXMLTree block; - status_t err = parseXMLResource(in, &block, false, true); - if (err != NO_ERROR) { - return err; - } - - // Top-level tag. - const String16 resources16("resources"); - - // Identifier declaration tags. - const String16 declare_styleable16("declare-styleable"); - const String16 attr16("attr"); - - // Data creation organizational tags. - const String16 string16("string"); - const String16 drawable16("drawable"); - const String16 color16("color"); - const String16 bool16("bool"); - const String16 integer16("integer"); - const String16 dimen16("dimen"); - const String16 fraction16("fraction"); - const String16 style16("style"); - const String16 plurals16("plurals"); - const String16 array16("array"); - const String16 string_array16("string-array"); - const String16 integer_array16("integer-array"); - const String16 public16("public"); - const String16 public_padding16("public-padding"); - const String16 private_symbols16("private-symbols"); - const String16 java_symbol16("java-symbol"); - const String16 add_resource16("add-resource"); - const String16 skip16("skip"); - const String16 eat_comment16("eat-comment"); - - // Data creation tags. - const String16 bag16("bag"); - const String16 item16("item"); - - // Attribute type constants. - const String16 enum16("enum"); - - // plural values - const String16 other16("other"); - const String16 quantityOther16("^other"); - const String16 zero16("zero"); - const String16 quantityZero16("^zero"); - const String16 one16("one"); - const String16 quantityOne16("^one"); - const String16 two16("two"); - const String16 quantityTwo16("^two"); - const String16 few16("few"); - const String16 quantityFew16("^few"); - const String16 many16("many"); - const String16 quantityMany16("^many"); - - // useful attribute names and special values - const String16 name16("name"); - const String16 translatable16("translatable"); - const String16 formatted16("formatted"); - const String16 false16("false"); - - const String16 myPackage(assets->getPackage()); - - bool hasErrors = false; - - bool fileIsTranslatable = true; - if (strstr(in->getPrintableSource().string(), "donottranslate") != NULL) { - fileIsTranslatable = false; - } - - DefaultKeyedVector<String16, uint32_t> nextPublicId(0); - - ResXMLTree::event_code_t code; - do { - code = block.next(); - } while (code == ResXMLTree::START_NAMESPACE); - - size_t len; - if (code != ResXMLTree::START_TAG) { - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "No start tag found\n"); - return UNKNOWN_ERROR; - } - if (strcmp16(block.getElementName(&len), resources16.string()) != 0) { - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "Invalid start tag %s\n", String8(block.getElementName(&len)).string()); - return UNKNOWN_ERROR; - } - - ResTable_config curParams(defParams); - - ResTable_config pseudoParams(curParams); - pseudoParams.language[0] = 'z'; - pseudoParams.language[1] = 'z'; - pseudoParams.country[0] = 'Z'; - pseudoParams.country[1] = 'Z'; - - while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::START_TAG) { - const String16* curTag = NULL; - String16 curType; - int32_t curFormat = ResTable_map::TYPE_ANY; - bool curIsBag = false; - bool curIsBagReplaceOnOverwrite = false; - bool curIsStyled = false; - bool curIsPseudolocalizable = false; - bool curIsFormatted = fileIsTranslatable; - bool localHasErrors = false; - - if (strcmp16(block.getElementName(&len), skip16.string()) == 0) { - while ((code=block.next()) != ResXMLTree::END_DOCUMENT - && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::END_TAG) { - if (strcmp16(block.getElementName(&len), skip16.string()) == 0) { - break; - } - } - } - continue; - - } else if (strcmp16(block.getElementName(&len), eat_comment16.string()) == 0) { - while ((code=block.next()) != ResXMLTree::END_DOCUMENT - && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::END_TAG) { - if (strcmp16(block.getElementName(&len), eat_comment16.string()) == 0) { - break; - } - } - } - continue; - - } else if (strcmp16(block.getElementName(&len), public16.string()) == 0) { - SourcePos srcPos(in->getPrintableSource(), block.getLineNumber()); - - String16 type; - ssize_t typeIdx = block.indexOfAttribute(NULL, "type"); - if (typeIdx < 0) { - srcPos.error("A 'type' attribute is required for <public>\n"); - hasErrors = localHasErrors = true; - } - type = String16(block.getAttributeStringValue(typeIdx, &len)); - - String16 name; - ssize_t nameIdx = block.indexOfAttribute(NULL, "name"); - if (nameIdx < 0) { - srcPos.error("A 'name' attribute is required for <public>\n"); - hasErrors = localHasErrors = true; - } - name = String16(block.getAttributeStringValue(nameIdx, &len)); - - uint32_t ident = 0; - ssize_t identIdx = block.indexOfAttribute(NULL, "id"); - if (identIdx >= 0) { - const char16_t* identStr = block.getAttributeStringValue(identIdx, &len); - Res_value identValue; - if (!ResTable::stringToInt(identStr, len, &identValue)) { - srcPos.error("Given 'id' attribute is not an integer: %s\n", - String8(block.getAttributeStringValue(identIdx, &len)).string()); - hasErrors = localHasErrors = true; - } else { - ident = identValue.data; - nextPublicId.replaceValueFor(type, ident+1); - } - } else if (nextPublicId.indexOfKey(type) < 0) { - srcPos.error("No 'id' attribute supplied <public>," - " and no previous id defined in this file.\n"); - hasErrors = localHasErrors = true; - } else if (!localHasErrors) { - ident = nextPublicId.valueFor(type); - nextPublicId.replaceValueFor(type, ident+1); - } - - if (!localHasErrors) { - err = outTable->addPublic(srcPos, myPackage, type, name, ident); - if (err < NO_ERROR) { - hasErrors = localHasErrors = true; - } - } - if (!localHasErrors) { - sp<AaptSymbols> symbols = assets->getSymbolsFor(String8("R")); - if (symbols != NULL) { - symbols = symbols->addNestedSymbol(String8(type), srcPos); - } - if (symbols != NULL) { - symbols->makeSymbolPublic(String8(name), srcPos); - String16 comment( - block.getComment(&len) ? block.getComment(&len) : nulStr); - symbols->appendComment(String8(name), comment, srcPos); - } else { - srcPos.error("Unable to create symbols!\n"); - hasErrors = localHasErrors = true; - } - } - - while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::END_TAG) { - if (strcmp16(block.getElementName(&len), public16.string()) == 0) { - break; - } - } - } - continue; - - } else if (strcmp16(block.getElementName(&len), public_padding16.string()) == 0) { - SourcePos srcPos(in->getPrintableSource(), block.getLineNumber()); - - String16 type; - ssize_t typeIdx = block.indexOfAttribute(NULL, "type"); - if (typeIdx < 0) { - srcPos.error("A 'type' attribute is required for <public-padding>\n"); - hasErrors = localHasErrors = true; - } - type = String16(block.getAttributeStringValue(typeIdx, &len)); - - String16 name; - ssize_t nameIdx = block.indexOfAttribute(NULL, "name"); - if (nameIdx < 0) { - srcPos.error("A 'name' attribute is required for <public-padding>\n"); - hasErrors = localHasErrors = true; - } - name = String16(block.getAttributeStringValue(nameIdx, &len)); - - uint32_t start = 0; - ssize_t startIdx = block.indexOfAttribute(NULL, "start"); - if (startIdx >= 0) { - const char16_t* startStr = block.getAttributeStringValue(startIdx, &len); - Res_value startValue; - if (!ResTable::stringToInt(startStr, len, &startValue)) { - srcPos.error("Given 'start' attribute is not an integer: %s\n", - String8(block.getAttributeStringValue(startIdx, &len)).string()); - hasErrors = localHasErrors = true; - } else { - start = startValue.data; - } - } else if (nextPublicId.indexOfKey(type) < 0) { - srcPos.error("No 'start' attribute supplied <public-padding>," - " and no previous id defined in this file.\n"); - hasErrors = localHasErrors = true; - } else if (!localHasErrors) { - start = nextPublicId.valueFor(type); - } - - uint32_t end = 0; - ssize_t endIdx = block.indexOfAttribute(NULL, "end"); - if (endIdx >= 0) { - const char16_t* endStr = block.getAttributeStringValue(endIdx, &len); - Res_value endValue; - if (!ResTable::stringToInt(endStr, len, &endValue)) { - srcPos.error("Given 'end' attribute is not an integer: %s\n", - String8(block.getAttributeStringValue(endIdx, &len)).string()); - hasErrors = localHasErrors = true; - } else { - end = endValue.data; - } - } else { - srcPos.error("No 'end' attribute supplied <public-padding>\n"); - hasErrors = localHasErrors = true; - } - - if (end >= start) { - nextPublicId.replaceValueFor(type, end+1); - } else { - srcPos.error("Padding start '%ul' is after end '%ul'\n", - start, end); - hasErrors = localHasErrors = true; - } - - String16 comment( - block.getComment(&len) ? block.getComment(&len) : nulStr); - for (uint32_t curIdent=start; curIdent<=end; curIdent++) { - if (localHasErrors) { - break; - } - String16 curName(name); - char buf[64]; - sprintf(buf, "%d", (int)(end-curIdent+1)); - curName.append(String16(buf)); - - err = outTable->addEntry(srcPos, myPackage, type, curName, - String16("padding"), NULL, &curParams, false, - ResTable_map::TYPE_STRING, overwrite); - if (err < NO_ERROR) { - hasErrors = localHasErrors = true; - break; - } - err = outTable->addPublic(srcPos, myPackage, type, - curName, curIdent); - if (err < NO_ERROR) { - hasErrors = localHasErrors = true; - break; - } - sp<AaptSymbols> symbols = assets->getSymbolsFor(String8("R")); - if (symbols != NULL) { - symbols = symbols->addNestedSymbol(String8(type), srcPos); - } - if (symbols != NULL) { - symbols->makeSymbolPublic(String8(curName), srcPos); - symbols->appendComment(String8(curName), comment, srcPos); - } else { - srcPos.error("Unable to create symbols!\n"); - hasErrors = localHasErrors = true; - } - } - - while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::END_TAG) { - if (strcmp16(block.getElementName(&len), public_padding16.string()) == 0) { - break; - } - } - } - continue; - - } else if (strcmp16(block.getElementName(&len), private_symbols16.string()) == 0) { - String16 pkg; - ssize_t pkgIdx = block.indexOfAttribute(NULL, "package"); - if (pkgIdx < 0) { - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "A 'package' attribute is required for <private-symbols>\n"); - hasErrors = localHasErrors = true; - } - pkg = String16(block.getAttributeStringValue(pkgIdx, &len)); - if (!localHasErrors) { - assets->setSymbolsPrivatePackage(String8(pkg)); - } - - while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::END_TAG) { - if (strcmp16(block.getElementName(&len), private_symbols16.string()) == 0) { - break; - } - } - } - continue; - - } else if (strcmp16(block.getElementName(&len), java_symbol16.string()) == 0) { - SourcePos srcPos(in->getPrintableSource(), block.getLineNumber()); - - String16 type; - ssize_t typeIdx = block.indexOfAttribute(NULL, "type"); - if (typeIdx < 0) { - srcPos.error("A 'type' attribute is required for <public>\n"); - hasErrors = localHasErrors = true; - } - type = String16(block.getAttributeStringValue(typeIdx, &len)); - - String16 name; - ssize_t nameIdx = block.indexOfAttribute(NULL, "name"); - if (nameIdx < 0) { - srcPos.error("A 'name' attribute is required for <public>\n"); - hasErrors = localHasErrors = true; - } - name = String16(block.getAttributeStringValue(nameIdx, &len)); - - sp<AaptSymbols> symbols = assets->getJavaSymbolsFor(String8("R")); - if (symbols != NULL) { - symbols = symbols->addNestedSymbol(String8(type), srcPos); - } - if (symbols != NULL) { - symbols->makeSymbolJavaSymbol(String8(name), srcPos); - String16 comment( - block.getComment(&len) ? block.getComment(&len) : nulStr); - symbols->appendComment(String8(name), comment, srcPos); - } else { - srcPos.error("Unable to create symbols!\n"); - hasErrors = localHasErrors = true; - } - - while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::END_TAG) { - if (strcmp16(block.getElementName(&len), java_symbol16.string()) == 0) { - break; - } - } - } - continue; - - - } else if (strcmp16(block.getElementName(&len), add_resource16.string()) == 0) { - SourcePos srcPos(in->getPrintableSource(), block.getLineNumber()); - - String16 typeName; - ssize_t typeIdx = block.indexOfAttribute(NULL, "type"); - if (typeIdx < 0) { - srcPos.error("A 'type' attribute is required for <add-resource>\n"); - hasErrors = localHasErrors = true; - } - typeName = String16(block.getAttributeStringValue(typeIdx, &len)); - - String16 name; - ssize_t nameIdx = block.indexOfAttribute(NULL, "name"); - if (nameIdx < 0) { - srcPos.error("A 'name' attribute is required for <add-resource>\n"); - hasErrors = localHasErrors = true; - } - name = String16(block.getAttributeStringValue(nameIdx, &len)); - - outTable->canAddEntry(srcPos, myPackage, typeName, name); - - while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::END_TAG) { - if (strcmp16(block.getElementName(&len), add_resource16.string()) == 0) { - break; - } - } - } - continue; - - } else if (strcmp16(block.getElementName(&len), declare_styleable16.string()) == 0) { - SourcePos srcPos(in->getPrintableSource(), block.getLineNumber()); - - String16 ident; - ssize_t identIdx = block.indexOfAttribute(NULL, "name"); - if (identIdx < 0) { - srcPos.error("A 'name' attribute is required for <declare-styleable>\n"); - hasErrors = localHasErrors = true; - } - ident = String16(block.getAttributeStringValue(identIdx, &len)); - - sp<AaptSymbols> symbols = assets->getSymbolsFor(String8("R")); - if (!localHasErrors) { - if (symbols != NULL) { - symbols = symbols->addNestedSymbol(String8("styleable"), srcPos); - } - sp<AaptSymbols> styleSymbols = symbols; - if (symbols != NULL) { - symbols = symbols->addNestedSymbol(String8(ident), srcPos); - } - if (symbols == NULL) { - srcPos.error("Unable to create symbols!\n"); - return UNKNOWN_ERROR; - } - - String16 comment( - block.getComment(&len) ? block.getComment(&len) : nulStr); - styleSymbols->appendComment(String8(ident), comment, srcPos); - } else { - symbols = NULL; - } - - while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::START_TAG) { - if (strcmp16(block.getElementName(&len), skip16.string()) == 0) { - while ((code=block.next()) != ResXMLTree::END_DOCUMENT - && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::END_TAG) { - if (strcmp16(block.getElementName(&len), skip16.string()) == 0) { - break; - } - } - } - continue; - } else if (strcmp16(block.getElementName(&len), eat_comment16.string()) == 0) { - while ((code=block.next()) != ResXMLTree::END_DOCUMENT - && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::END_TAG) { - if (strcmp16(block.getElementName(&len), eat_comment16.string()) == 0) { - break; - } - } - } - continue; - } else if (strcmp16(block.getElementName(&len), attr16.string()) != 0) { - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "Tag <%s> can not appear inside <declare-styleable>, only <attr>\n", - String8(block.getElementName(&len)).string()); - return UNKNOWN_ERROR; - } - - String16 comment( - block.getComment(&len) ? block.getComment(&len) : nulStr); - String16 itemIdent; - err = compileAttribute(in, block, myPackage, outTable, &itemIdent, true); - if (err != NO_ERROR) { - hasErrors = localHasErrors = true; - } - - if (symbols != NULL) { - SourcePos srcPos(String8(in->getPrintableSource()), block.getLineNumber()); - symbols->addSymbol(String8(itemIdent), 0, srcPos); - symbols->appendComment(String8(itemIdent), comment, srcPos); - //printf("Attribute %s comment: %s\n", String8(itemIdent).string(), - // String8(comment).string()); - } - } else if (code == ResXMLTree::END_TAG) { - if (strcmp16(block.getElementName(&len), declare_styleable16.string()) == 0) { - break; - } - - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "Found tag </%s> where </attr> is expected\n", - String8(block.getElementName(&len)).string()); - return UNKNOWN_ERROR; - } - } - continue; - - } else if (strcmp16(block.getElementName(&len), attr16.string()) == 0) { - err = compileAttribute(in, block, myPackage, outTable, NULL); - if (err != NO_ERROR) { - hasErrors = true; - } - continue; - - } else if (strcmp16(block.getElementName(&len), item16.string()) == 0) { - curTag = &item16; - ssize_t attri = block.indexOfAttribute(NULL, "type"); - if (attri >= 0) { - curType = String16(block.getAttributeStringValue(attri, &len)); - ssize_t formatIdx = block.indexOfAttribute(NULL, "format"); - if (formatIdx >= 0) { - String16 formatStr = String16(block.getAttributeStringValue( - formatIdx, &len)); - curFormat = parse_flags(formatStr.string(), formatStr.size(), - gFormatFlags); - if (curFormat == 0) { - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "Tag <item> 'format' attribute value \"%s\" not valid\n", - String8(formatStr).string()); - hasErrors = localHasErrors = true; - } - } - } else { - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "A 'type' attribute is required for <item>\n"); - hasErrors = localHasErrors = true; - } - curIsStyled = true; - } else if (strcmp16(block.getElementName(&len), string16.string()) == 0) { - // Note the existence and locale of every string we process - char rawLocale[16]; - curParams.getLocale(rawLocale); - String8 locale(rawLocale); - String16 name; - String16 translatable; - String16 formatted; - - size_t n = block.getAttributeCount(); - for (size_t i = 0; i < n; i++) { - size_t length; - const uint16_t* attr = block.getAttributeName(i, &length); - if (strcmp16(attr, name16.string()) == 0) { - name.setTo(block.getAttributeStringValue(i, &length)); - } else if (strcmp16(attr, translatable16.string()) == 0) { - translatable.setTo(block.getAttributeStringValue(i, &length)); - } else if (strcmp16(attr, formatted16.string()) == 0) { - formatted.setTo(block.getAttributeStringValue(i, &length)); - } - } - - if (name.size() > 0) { - if (translatable == false16) { - curIsFormatted = false; - // Untranslatable strings must only exist in the default [empty] locale - if (locale.size() > 0) { - fprintf(stderr, "aapt: warning: string '%s' in %s marked untranslatable but exists" - " in locale '%s'\n", String8(name).string(), - bundle->getResourceSourceDirs()[0], - locale.string()); - // hasErrors = localHasErrors = true; - } else { - // Intentionally empty block: - // - // Don't add untranslatable strings to the localization table; that - // way if we later see localizations of them, they'll be flagged as - // having no default translation. - } - } else { - outTable->addLocalization(name, locale); - } - - if (formatted == false16) { - curIsFormatted = false; - } - } - - curTag = &string16; - curType = string16; - curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING; - curIsStyled = true; - curIsPseudolocalizable = true; - } else if (strcmp16(block.getElementName(&len), drawable16.string()) == 0) { - curTag = &drawable16; - curType = drawable16; - curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_COLOR; - } else if (strcmp16(block.getElementName(&len), color16.string()) == 0) { - curTag = &color16; - curType = color16; - curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_COLOR; - } else if (strcmp16(block.getElementName(&len), bool16.string()) == 0) { - curTag = &bool16; - curType = bool16; - curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_BOOLEAN; - } else if (strcmp16(block.getElementName(&len), integer16.string()) == 0) { - curTag = &integer16; - curType = integer16; - curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_INTEGER; - } else if (strcmp16(block.getElementName(&len), dimen16.string()) == 0) { - curTag = &dimen16; - curType = dimen16; - curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_DIMENSION; - } else if (strcmp16(block.getElementName(&len), fraction16.string()) == 0) { - curTag = &fraction16; - curType = fraction16; - curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_FRACTION; - } else if (strcmp16(block.getElementName(&len), bag16.string()) == 0) { - curTag = &bag16; - curIsBag = true; - ssize_t attri = block.indexOfAttribute(NULL, "type"); - if (attri >= 0) { - curType = String16(block.getAttributeStringValue(attri, &len)); - } else { - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "A 'type' attribute is required for <bag>\n"); - hasErrors = localHasErrors = true; - } - } else if (strcmp16(block.getElementName(&len), style16.string()) == 0) { - curTag = &style16; - curType = style16; - curIsBag = true; - } else if (strcmp16(block.getElementName(&len), plurals16.string()) == 0) { - curTag = &plurals16; - curType = plurals16; - curIsBag = true; - } else if (strcmp16(block.getElementName(&len), array16.string()) == 0) { - curTag = &array16; - curType = array16; - curIsBag = true; - curIsBagReplaceOnOverwrite = true; - ssize_t formatIdx = block.indexOfAttribute(NULL, "format"); - if (formatIdx >= 0) { - String16 formatStr = String16(block.getAttributeStringValue( - formatIdx, &len)); - curFormat = parse_flags(formatStr.string(), formatStr.size(), - gFormatFlags); - if (curFormat == 0) { - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "Tag <array> 'format' attribute value \"%s\" not valid\n", - String8(formatStr).string()); - hasErrors = localHasErrors = true; - } - } - } else if (strcmp16(block.getElementName(&len), string_array16.string()) == 0) { - // Check whether these strings need valid formats. - // (simplified form of what string16 does above) - size_t n = block.getAttributeCount(); - for (size_t i = 0; i < n; i++) { - size_t length; - const uint16_t* attr = block.getAttributeName(i, &length); - if (strcmp16(attr, translatable16.string()) == 0 - || strcmp16(attr, formatted16.string()) == 0) { - const uint16_t* value = block.getAttributeStringValue(i, &length); - if (strcmp16(value, false16.string()) == 0) { - curIsFormatted = false; - break; - } - } - } - - curTag = &string_array16; - curType = array16; - curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING; - curIsBag = true; - curIsBagReplaceOnOverwrite = true; - curIsPseudolocalizable = true; - } else if (strcmp16(block.getElementName(&len), integer_array16.string()) == 0) { - curTag = &integer_array16; - curType = array16; - curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_INTEGER; - curIsBag = true; - curIsBagReplaceOnOverwrite = true; - } else { - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "Found tag %s where item is expected\n", - String8(block.getElementName(&len)).string()); - return UNKNOWN_ERROR; - } - - String16 ident; - ssize_t identIdx = block.indexOfAttribute(NULL, "name"); - if (identIdx >= 0) { - ident = String16(block.getAttributeStringValue(identIdx, &len)); - } else { - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "A 'name' attribute is required for <%s>\n", - String8(*curTag).string()); - hasErrors = localHasErrors = true; - } - - String16 product; - identIdx = block.indexOfAttribute(NULL, "product"); - if (identIdx >= 0) { - product = String16(block.getAttributeStringValue(identIdx, &len)); - } - - String16 comment(block.getComment(&len) ? block.getComment(&len) : nulStr); - - if (curIsBag) { - // Figure out the parent of this bag... - String16 parentIdent; - ssize_t parentIdentIdx = block.indexOfAttribute(NULL, "parent"); - if (parentIdentIdx >= 0) { - parentIdent = String16(block.getAttributeStringValue(parentIdentIdx, &len)); - } else { - ssize_t sep = ident.findLast('.'); - if (sep >= 0) { - parentIdent.setTo(ident, sep); - } - } - - if (!localHasErrors) { - err = outTable->startBag(SourcePos(in->getPrintableSource(), - block.getLineNumber()), myPackage, curType, ident, - parentIdent, &curParams, - overwrite, curIsBagReplaceOnOverwrite); - if (err != NO_ERROR) { - hasErrors = localHasErrors = true; - } - } - - ssize_t elmIndex = 0; - char elmIndexStr[14]; - while ((code=block.next()) != ResXMLTree::END_DOCUMENT - && code != ResXMLTree::BAD_DOCUMENT) { - - if (code == ResXMLTree::START_TAG) { - if (strcmp16(block.getElementName(&len), item16.string()) != 0) { - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "Tag <%s> can not appear inside <%s>, only <item>\n", - String8(block.getElementName(&len)).string(), - String8(*curTag).string()); - return UNKNOWN_ERROR; - } - - String16 itemIdent; - if (curType == array16) { - sprintf(elmIndexStr, "^index_%d", (int)elmIndex++); - itemIdent = String16(elmIndexStr); - } else if (curType == plurals16) { - ssize_t itemIdentIdx = block.indexOfAttribute(NULL, "quantity"); - if (itemIdentIdx >= 0) { - String16 quantity16(block.getAttributeStringValue(itemIdentIdx, &len)); - if (quantity16 == other16) { - itemIdent = quantityOther16; - } - else if (quantity16 == zero16) { - itemIdent = quantityZero16; - } - else if (quantity16 == one16) { - itemIdent = quantityOne16; - } - else if (quantity16 == two16) { - itemIdent = quantityTwo16; - } - else if (quantity16 == few16) { - itemIdent = quantityFew16; - } - else if (quantity16 == many16) { - itemIdent = quantityMany16; - } - else { - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "Illegal 'quantity' attribute is <item> inside <plurals>\n"); - hasErrors = localHasErrors = true; - } - } else { - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "A 'quantity' attribute is required for <item> inside <plurals>\n"); - hasErrors = localHasErrors = true; - } - } else { - ssize_t itemIdentIdx = block.indexOfAttribute(NULL, "name"); - if (itemIdentIdx >= 0) { - itemIdent = String16(block.getAttributeStringValue(itemIdentIdx, &len)); - } else { - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "A 'name' attribute is required for <item>\n"); - hasErrors = localHasErrors = true; - } - } - - ResXMLParser::ResXMLPosition parserPosition; - block.getPosition(&parserPosition); - - err = parseAndAddBag(bundle, in, &block, curParams, myPackage, curType, - ident, parentIdent, itemIdent, curFormat, curIsFormatted, - product, false, overwrite, outTable); - if (err == NO_ERROR) { - if (curIsPseudolocalizable && localeIsDefined(curParams) - && bundle->getPseudolocalize()) { - // pseudolocalize here -#if 1 - block.setPosition(parserPosition); - err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage, - curType, ident, parentIdent, itemIdent, curFormat, - curIsFormatted, product, true, overwrite, outTable); -#endif - } - } - if (err != NO_ERROR) { - hasErrors = localHasErrors = true; - } - } else if (code == ResXMLTree::END_TAG) { - if (strcmp16(block.getElementName(&len), curTag->string()) != 0) { - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "Found tag </%s> where </%s> is expected\n", - String8(block.getElementName(&len)).string(), - String8(*curTag).string()); - return UNKNOWN_ERROR; - } - break; - } - } - } else { - ResXMLParser::ResXMLPosition parserPosition; - block.getPosition(&parserPosition); - - err = parseAndAddEntry(bundle, in, &block, curParams, myPackage, curType, ident, - *curTag, curIsStyled, curFormat, curIsFormatted, - product, false, overwrite, outTable); - - if (err < NO_ERROR) { // Why err < NO_ERROR instead of err != NO_ERROR? - hasErrors = localHasErrors = true; - } - else if (err == NO_ERROR) { - if (curIsPseudolocalizable && localeIsDefined(curParams) - && bundle->getPseudolocalize()) { - // pseudolocalize here - block.setPosition(parserPosition); - err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType, - ident, *curTag, curIsStyled, curFormat, - curIsFormatted, product, - true, overwrite, outTable); - if (err != NO_ERROR) { - hasErrors = localHasErrors = true; - } - } - } - } - -#if 0 - if (comment.size() > 0) { - printf("Comment for @%s:%s/%s: %s\n", String8(myPackage).string(), - String8(curType).string(), String8(ident).string(), - String8(comment).string()); - } -#endif - if (!localHasErrors) { - outTable->appendComment(myPackage, curType, ident, comment, false); - } - } - else if (code == ResXMLTree::END_TAG) { - if (strcmp16(block.getElementName(&len), resources16.string()) != 0) { - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "Unexpected end tag %s\n", String8(block.getElementName(&len)).string()); - return UNKNOWN_ERROR; - } - } - else if (code == ResXMLTree::START_NAMESPACE || code == ResXMLTree::END_NAMESPACE) { - } - else if (code == ResXMLTree::TEXT) { - if (isWhitespace(block.getText(&len))) { - continue; - } - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "Found text \"%s\" where item tag is expected\n", - String8(block.getText(&len)).string()); - return UNKNOWN_ERROR; - } - } - - return hasErrors ? UNKNOWN_ERROR : NO_ERROR; -} - -ResourceTable::ResourceTable(Bundle* bundle, const String16& assetsPackage) - : mAssetsPackage(assetsPackage), mNextPackageId(1), mHaveAppPackage(false), - mIsAppPackage(!bundle->getExtending()), - mNumLocal(0), - mBundle(bundle) -{ -} - -status_t ResourceTable::addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets) -{ - status_t err = assets->buildIncludedResources(bundle); - if (err != NO_ERROR) { - return err; - } - - // For future reference to included resources. - mAssets = assets; - - const ResTable& incl = assets->getIncludedResources(); - - // Retrieve all the packages. - const size_t N = incl.getBasePackageCount(); - for (size_t phase=0; phase<2; phase++) { - for (size_t i=0; i<N; i++) { - String16 name(incl.getBasePackageName(i)); - uint32_t id = incl.getBasePackageId(i); - // First time through: only add base packages (id - // is not 0); second time through add the other - // packages. - if (phase != 0) { - if (id != 0) { - // Skip base packages -- already one. - id = 0; - } else { - // Assign a dynamic id. - id = mNextPackageId; - } - } else if (id != 0) { - if (id == 127) { - if (mHaveAppPackage) { - fprintf(stderr, "Included resources have two application packages!\n"); - return UNKNOWN_ERROR; - } - mHaveAppPackage = true; - } - if (mNextPackageId > id) { - fprintf(stderr, "Included base package ID %d already in use!\n", id); - return UNKNOWN_ERROR; - } - } - if (id != 0) { - NOISY(printf("Including package %s with ID=%d\n", - String8(name).string(), id)); - sp<Package> p = new Package(name, id); - mPackages.add(name, p); - mOrderedPackages.add(p); - - if (id >= mNextPackageId) { - mNextPackageId = id+1; - } - } - } - } - - // Every resource table always has one first entry, the bag attributes. - const SourcePos unknown(String8("????"), 0); - sp<Type> attr = getType(mAssetsPackage, String16("attr"), unknown); - - return NO_ERROR; -} - -status_t ResourceTable::addPublic(const SourcePos& sourcePos, - const String16& package, - const String16& type, - const String16& name, - const uint32_t ident) -{ - uint32_t rid = mAssets->getIncludedResources() - .identifierForName(name.string(), name.size(), - type.string(), type.size(), - package.string(), package.size()); - if (rid != 0) { - sourcePos.error("Error declaring public resource %s/%s for included package %s\n", - String8(type).string(), String8(name).string(), - String8(package).string()); - return UNKNOWN_ERROR; - } - - sp<Type> t = getType(package, type, sourcePos); - if (t == NULL) { - return UNKNOWN_ERROR; - } - return t->addPublic(sourcePos, name, ident); -} - -status_t ResourceTable::addEntry(const SourcePos& sourcePos, - const String16& package, - const String16& type, - const String16& name, - const String16& value, - const Vector<StringPool::entry_style_span>* style, - const ResTable_config* params, - const bool doSetIndex, - const int32_t format, - const bool overwrite) -{ - // Check for adding entries in other packages... for now we do - // nothing. We need to do the right thing here to support skinning. - uint32_t rid = mAssets->getIncludedResources() - .identifierForName(name.string(), name.size(), - type.string(), type.size(), - package.string(), package.size()); - if (rid != 0) { - return NO_ERROR; - } - -#if 0 - if (name == String16("left")) { - printf("Adding entry left: file=%s, line=%d, type=%s, value=%s\n", - sourcePos.file.string(), sourcePos.line, String8(type).string(), - String8(value).string()); - } -#endif - - sp<Entry> e = getEntry(package, type, name, sourcePos, overwrite, - params, doSetIndex); - if (e == NULL) { - return UNKNOWN_ERROR; - } - status_t err = e->setItem(sourcePos, value, style, format, overwrite); - if (err == NO_ERROR) { - mNumLocal++; - } - return err; -} - -status_t ResourceTable::startBag(const SourcePos& sourcePos, - const String16& package, - const String16& type, - const String16& name, - const String16& bagParent, - const ResTable_config* params, - bool overlay, - bool replace, bool isId) -{ - status_t result = NO_ERROR; - - // Check for adding entries in other packages... for now we do - // nothing. We need to do the right thing here to support skinning. - uint32_t rid = mAssets->getIncludedResources() - .identifierForName(name.string(), name.size(), - type.string(), type.size(), - package.string(), package.size()); - if (rid != 0) { - return NO_ERROR; - } - -#if 0 - if (name == String16("left")) { - printf("Adding bag left: file=%s, line=%d, type=%s\n", - sourcePos.file.striing(), sourcePos.line, String8(type).string()); - } -#endif - if (overlay && !mBundle->getAutoAddOverlay() && !hasBagOrEntry(package, type, name)) { - bool canAdd = false; - sp<Package> p = mPackages.valueFor(package); - if (p != NULL) { - sp<Type> t = p->getTypes().valueFor(type); - if (t != NULL) { - if (t->getCanAddEntries().indexOf(name) >= 0) { - canAdd = true; - } - } - } - if (!canAdd) { - sourcePos.error("Resource does not already exist in overlay at '%s'; use <add-resource> to add.\n", - String8(name).string()); - return UNKNOWN_ERROR; - } - } - sp<Entry> e = getEntry(package, type, name, sourcePos, overlay, params); - if (e == NULL) { - return UNKNOWN_ERROR; - } - - // If a parent is explicitly specified, set it. - if (bagParent.size() > 0) { - e->setParent(bagParent); - } - - if ((result = e->makeItABag(sourcePos)) != NO_ERROR) { - return result; - } - - if (overlay && replace) { - return e->emptyBag(sourcePos); - } - return result; -} - -status_t ResourceTable::addBag(const SourcePos& sourcePos, - const String16& package, - const String16& type, - const String16& name, - const String16& bagParent, - const String16& bagKey, - const String16& value, - const Vector<StringPool::entry_style_span>* style, - const ResTable_config* params, - bool replace, bool isId, const int32_t format) -{ - // Check for adding entries in other packages... for now we do - // nothing. We need to do the right thing here to support skinning. - uint32_t rid = mAssets->getIncludedResources() - .identifierForName(name.string(), name.size(), - type.string(), type.size(), - package.string(), package.size()); - if (rid != 0) { - return NO_ERROR; - } - -#if 0 - if (name == String16("left")) { - printf("Adding bag left: file=%s, line=%d, type=%s\n", - sourcePos.file.striing(), sourcePos.line, String8(type).string()); - } -#endif - sp<Entry> e = getEntry(package, type, name, sourcePos, replace, params); - if (e == NULL) { - return UNKNOWN_ERROR; - } - - // If a parent is explicitly specified, set it. - if (bagParent.size() > 0) { - e->setParent(bagParent); - } - - const bool first = e->getBag().indexOfKey(bagKey) < 0; - status_t err = e->addToBag(sourcePos, bagKey, value, style, replace, isId, format); - if (err == NO_ERROR && first) { - mNumLocal++; - } - return err; -} - -bool ResourceTable::hasBagOrEntry(const String16& package, - const String16& type, - const String16& name) const -{ - // First look for this in the included resources... - uint32_t rid = mAssets->getIncludedResources() - .identifierForName(name.string(), name.size(), - type.string(), type.size(), - package.string(), package.size()); - if (rid != 0) { - return true; - } - - sp<Package> p = mPackages.valueFor(package); - if (p != NULL) { - sp<Type> t = p->getTypes().valueFor(type); - if (t != NULL) { - sp<ConfigList> c = t->getConfigs().valueFor(name); - if (c != NULL) return true; - } - } - - return false; -} - -bool ResourceTable::hasBagOrEntry(const String16& package, - const String16& type, - const String16& name, - const ResTable_config& config) const -{ - // First look for this in the included resources... - uint32_t rid = mAssets->getIncludedResources() - .identifierForName(name.string(), name.size(), - type.string(), type.size(), - package.string(), package.size()); - if (rid != 0) { - return true; - } - - sp<Package> p = mPackages.valueFor(package); - if (p != NULL) { - sp<Type> t = p->getTypes().valueFor(type); - if (t != NULL) { - sp<ConfigList> c = t->getConfigs().valueFor(name); - if (c != NULL) { - sp<Entry> e = c->getEntries().valueFor(config); - if (e != NULL) { - return true; - } - } - } - } - - return false; -} - -bool ResourceTable::hasBagOrEntry(const String16& ref, - const String16* defType, - const String16* defPackage) -{ - String16 package, type, name; - if (!ResTable::expandResourceRef(ref.string(), ref.size(), &package, &type, &name, - defType, defPackage ? defPackage:&mAssetsPackage, NULL)) { - return false; - } - return hasBagOrEntry(package, type, name); -} - -bool ResourceTable::appendComment(const String16& package, - const String16& type, - const String16& name, - const String16& comment, - bool onlyIfEmpty) -{ - if (comment.size() <= 0) { - return true; - } - - sp<Package> p = mPackages.valueFor(package); - if (p != NULL) { - sp<Type> t = p->getTypes().valueFor(type); - if (t != NULL) { - sp<ConfigList> c = t->getConfigs().valueFor(name); - if (c != NULL) { - c->appendComment(comment, onlyIfEmpty); - return true; - } - } - } - return false; -} - -bool ResourceTable::appendTypeComment(const String16& package, - const String16& type, - const String16& name, - const String16& comment) -{ - if (comment.size() <= 0) { - return true; - } - - sp<Package> p = mPackages.valueFor(package); - if (p != NULL) { - sp<Type> t = p->getTypes().valueFor(type); - if (t != NULL) { - sp<ConfigList> c = t->getConfigs().valueFor(name); - if (c != NULL) { - c->appendTypeComment(comment); - return true; - } - } - } - return false; -} - -void ResourceTable::canAddEntry(const SourcePos& pos, - const String16& package, const String16& type, const String16& name) -{ - sp<Type> t = getType(package, type, pos); - if (t != NULL) { - t->canAddEntry(name); - } -} - -size_t ResourceTable::size() const { - return mPackages.size(); -} - -size_t ResourceTable::numLocalResources() const { - return mNumLocal; -} - -bool ResourceTable::hasResources() const { - return mNumLocal > 0; -} - -sp<AaptFile> ResourceTable::flatten(Bundle* bundle) -{ - sp<AaptFile> data = new AaptFile(String8(), AaptGroupEntry(), String8()); - status_t err = flatten(bundle, data); - return err == NO_ERROR ? data : NULL; -} - -inline uint32_t ResourceTable::getResId(const sp<Package>& p, - const sp<Type>& t, - uint32_t nameId) -{ - return makeResId(p->getAssignedId(), t->getIndex(), nameId); -} - -uint32_t ResourceTable::getResId(const String16& package, - const String16& type, - const String16& name, - bool onlyPublic) const -{ - uint32_t id = ResourceIdCache::lookup(package, type, name, onlyPublic); - if (id != 0) return id; // cache hit - - sp<Package> p = mPackages.valueFor(package); - if (p == NULL) return 0; - - // First look for this in the included resources... - uint32_t specFlags = 0; - uint32_t rid = mAssets->getIncludedResources() - .identifierForName(name.string(), name.size(), - type.string(), type.size(), - package.string(), package.size(), - &specFlags); - if (rid != 0) { - if (onlyPublic) { - if ((specFlags & ResTable_typeSpec::SPEC_PUBLIC) == 0) { - return 0; - } - } - - if (Res_INTERNALID(rid)) { - return ResourceIdCache::store(package, type, name, onlyPublic, rid); - } - return ResourceIdCache::store(package, type, name, onlyPublic, - Res_MAKEID(p->getAssignedId()-1, Res_GETTYPE(rid), Res_GETENTRY(rid))); - } - - sp<Type> t = p->getTypes().valueFor(type); - if (t == NULL) return 0; - sp<ConfigList> c = t->getConfigs().valueFor(name); - if (c == NULL) return 0; - int32_t ei = c->getEntryIndex(); - if (ei < 0) return 0; - - return ResourceIdCache::store(package, type, name, onlyPublic, - getResId(p, t, ei)); -} - -uint32_t ResourceTable::getResId(const String16& ref, - const String16* defType, - const String16* defPackage, - const char** outErrorMsg, - bool onlyPublic) const -{ - String16 package, type, name; - bool refOnlyPublic = true; - if (!ResTable::expandResourceRef( - ref.string(), ref.size(), &package, &type, &name, - defType, defPackage ? defPackage:&mAssetsPackage, - outErrorMsg, &refOnlyPublic)) { - NOISY(printf("Expanding resource: ref=%s\n", - String8(ref).string())); - NOISY(printf("Expanding resource: defType=%s\n", - defType ? String8(*defType).string() : "NULL")); - NOISY(printf("Expanding resource: defPackage=%s\n", - defPackage ? String8(*defPackage).string() : "NULL")); - NOISY(printf("Expanding resource: ref=%s\n", String8(ref).string())); - NOISY(printf("Expanded resource: p=%s, t=%s, n=%s, res=0\n", - String8(package).string(), String8(type).string(), - String8(name).string())); - return 0; - } - uint32_t res = getResId(package, type, name, onlyPublic && refOnlyPublic); - NOISY(printf("Expanded resource: p=%s, t=%s, n=%s, res=%d\n", - String8(package).string(), String8(type).string(), - String8(name).string(), res)); - if (res == 0) { - if (outErrorMsg) - *outErrorMsg = "No resource found that matches the given name"; - } - return res; -} - -bool ResourceTable::isValidResourceName(const String16& s) -{ - const char16_t* p = s.string(); - bool first = true; - while (*p) { - if ((*p >= 'a' && *p <= 'z') - || (*p >= 'A' && *p <= 'Z') - || *p == '_' - || (!first && *p >= '0' && *p <= '9')) { - first = false; - p++; - continue; - } - return false; - } - return true; -} - -bool ResourceTable::stringToValue(Res_value* outValue, StringPool* pool, - const String16& str, - bool preserveSpaces, bool coerceType, - uint32_t attrID, - const Vector<StringPool::entry_style_span>* style, - String16* outStr, void* accessorCookie, - uint32_t attrType, const String8* configTypeName, - const ConfigDescription* config) -{ - String16 finalStr; - - bool res = true; - if (style == NULL || style->size() == 0) { - // Text is not styled so it can be any type... let's figure it out. - res = mAssets->getIncludedResources() - .stringToValue(outValue, &finalStr, str.string(), str.size(), preserveSpaces, - coerceType, attrID, NULL, &mAssetsPackage, this, - accessorCookie, attrType); - } else { - // Styled text can only be a string, and while collecting the style - // information we have already processed that string! - outValue->size = sizeof(Res_value); - outValue->res0 = 0; - outValue->dataType = outValue->TYPE_STRING; - outValue->data = 0; - finalStr = str; - } - - if (!res) { - return false; - } - - if (outValue->dataType == outValue->TYPE_STRING) { - // Should do better merging styles. - if (pool) { - String8 configStr; - if (config != NULL) { - configStr = config->toString(); - } else { - configStr = "(null)"; - } - NOISY(printf("Adding to pool string style #%d config %s: %s\n", - style != NULL ? style->size() : 0, - configStr.string(), String8(finalStr).string())); - if (style != NULL && style->size() > 0) { - outValue->data = pool->add(finalStr, *style, configTypeName, config); - } else { - outValue->data = pool->add(finalStr, true, configTypeName, config); - } - } else { - // Caller will fill this in later. - outValue->data = 0; - } - - if (outStr) { - *outStr = finalStr; - } - - } - - return true; -} - -uint32_t ResourceTable::getCustomResource( - const String16& package, const String16& type, const String16& name) const -{ - //printf("getCustomResource: %s %s %s\n", String8(package).string(), - // String8(type).string(), String8(name).string()); - sp<Package> p = mPackages.valueFor(package); - if (p == NULL) return 0; - sp<Type> t = p->getTypes().valueFor(type); - if (t == NULL) return 0; - sp<ConfigList> c = t->getConfigs().valueFor(name); - if (c == NULL) return 0; - int32_t ei = c->getEntryIndex(); - if (ei < 0) return 0; - return getResId(p, t, ei); -} - -uint32_t ResourceTable::getCustomResourceWithCreation( - const String16& package, const String16& type, const String16& name, - const bool createIfNotFound) -{ - uint32_t resId = getCustomResource(package, type, name); - if (resId != 0 || !createIfNotFound) { - return resId; - } - String16 value("false"); - - status_t status = addEntry(mCurrentXmlPos, package, type, name, value, NULL, NULL, true); - if (status == NO_ERROR) { - resId = getResId(package, type, name); - return resId; - } - return 0; -} - -uint32_t ResourceTable::getRemappedPackage(uint32_t origPackage) const -{ - return origPackage; -} - -bool ResourceTable::getAttributeType(uint32_t attrID, uint32_t* outType) -{ - //printf("getAttributeType #%08x\n", attrID); - Res_value value; - if (getItemValue(attrID, ResTable_map::ATTR_TYPE, &value)) { - //printf("getAttributeType #%08x (%s): #%08x\n", attrID, - // String8(getEntry(attrID)->getName()).string(), value.data); - *outType = value.data; - return true; - } - return false; -} - -bool ResourceTable::getAttributeMin(uint32_t attrID, uint32_t* outMin) -{ - //printf("getAttributeMin #%08x\n", attrID); - Res_value value; - if (getItemValue(attrID, ResTable_map::ATTR_MIN, &value)) { - *outMin = value.data; - return true; - } - return false; -} - -bool ResourceTable::getAttributeMax(uint32_t attrID, uint32_t* outMax) -{ - //printf("getAttributeMax #%08x\n", attrID); - Res_value value; - if (getItemValue(attrID, ResTable_map::ATTR_MAX, &value)) { - *outMax = value.data; - return true; - } - return false; -} - -uint32_t ResourceTable::getAttributeL10N(uint32_t attrID) -{ - //printf("getAttributeL10N #%08x\n", attrID); - Res_value value; - if (getItemValue(attrID, ResTable_map::ATTR_L10N, &value)) { - return value.data; - } - return ResTable_map::L10N_NOT_REQUIRED; -} - -bool ResourceTable::getLocalizationSetting() -{ - return mBundle->getRequireLocalization(); -} - -void ResourceTable::reportError(void* accessorCookie, const char* fmt, ...) -{ - if (accessorCookie != NULL && fmt != NULL) { - AccessorCookie* ac = (AccessorCookie*)accessorCookie; - int retval=0; - char buf[1024]; - va_list ap; - va_start(ap, fmt); - retval = vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - ac->sourcePos.error("Error: %s (at '%s' with value '%s').\n", - buf, ac->attr.string(), ac->value.string()); - } -} - -bool ResourceTable::getAttributeKeys( - uint32_t attrID, Vector<String16>* outKeys) -{ - sp<const Entry> e = getEntry(attrID); - if (e != NULL) { - const size_t N = e->getBag().size(); - for (size_t i=0; i<N; i++) { - const String16& key = e->getBag().keyAt(i); - if (key.size() > 0 && key.string()[0] != '^') { - outKeys->add(key); - } - } - return true; - } - return false; -} - -bool ResourceTable::getAttributeEnum( - uint32_t attrID, const char16_t* name, size_t nameLen, - Res_value* outValue) -{ - //printf("getAttributeEnum #%08x %s\n", attrID, String8(name, nameLen).string()); - String16 nameStr(name, nameLen); - sp<const Entry> e = getEntry(attrID); - if (e != NULL) { - const size_t N = e->getBag().size(); - for (size_t i=0; i<N; i++) { - //printf("Comparing %s to %s\n", String8(name, nameLen).string(), - // String8(e->getBag().keyAt(i)).string()); - if (e->getBag().keyAt(i) == nameStr) { - return getItemValue(attrID, e->getBag().valueAt(i).bagKeyId, outValue); - } - } - } - return false; -} - -bool ResourceTable::getAttributeFlags( - uint32_t attrID, const char16_t* name, size_t nameLen, - Res_value* outValue) -{ - outValue->dataType = Res_value::TYPE_INT_HEX; - outValue->data = 0; - - //printf("getAttributeFlags #%08x %s\n", attrID, String8(name, nameLen).string()); - String16 nameStr(name, nameLen); - sp<const Entry> e = getEntry(attrID); - if (e != NULL) { - const size_t N = e->getBag().size(); - - const char16_t* end = name + nameLen; - const char16_t* pos = name; - while (pos < end) { - const char16_t* start = pos; - while (pos < end && *pos != '|') { - pos++; - } - - String16 nameStr(start, pos-start); - size_t i; - for (i=0; i<N; i++) { - //printf("Comparing \"%s\" to \"%s\"\n", String8(nameStr).string(), - // String8(e->getBag().keyAt(i)).string()); - if (e->getBag().keyAt(i) == nameStr) { - Res_value val; - bool got = getItemValue(attrID, e->getBag().valueAt(i).bagKeyId, &val); - if (!got) { - return false; - } - //printf("Got value: 0x%08x\n", val.data); - outValue->data |= val.data; - break; - } - } - - if (i >= N) { - // Didn't find this flag identifier. - return false; - } - pos++; - } - - return true; - } - return false; -} - -status_t ResourceTable::assignResourceIds() -{ - const size_t N = mOrderedPackages.size(); - size_t pi; - status_t firstError = NO_ERROR; - - // First generate all bag attributes and assign indices. - for (pi=0; pi<N; pi++) { - sp<Package> p = mOrderedPackages.itemAt(pi); - if (p == NULL || p->getTypes().size() == 0) { - // Empty, skip! - continue; - } - - status_t err = p->applyPublicTypeOrder(); - if (err != NO_ERROR && firstError == NO_ERROR) { - firstError = err; - } - - // Generate attributes... - const size_t N = p->getOrderedTypes().size(); - size_t ti; - for (ti=0; ti<N; ti++) { - sp<Type> t = p->getOrderedTypes().itemAt(ti); - if (t == NULL) { - continue; - } - const size_t N = t->getOrderedConfigs().size(); - for (size_t ci=0; ci<N; ci++) { - sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci); - if (c == NULL) { - continue; - } - const size_t N = c->getEntries().size(); - for (size_t ei=0; ei<N; ei++) { - sp<Entry> e = c->getEntries().valueAt(ei); - if (e == NULL) { - continue; - } - status_t err = e->generateAttributes(this, p->getName()); - if (err != NO_ERROR && firstError == NO_ERROR) { - firstError = err; - } - } - } - } - - const SourcePos unknown(String8("????"), 0); - sp<Type> attr = p->getType(String16("attr"), unknown); - - // Assign indices... - for (ti=0; ti<N; ti++) { - sp<Type> t = p->getOrderedTypes().itemAt(ti); - if (t == NULL) { - continue; - } - err = t->applyPublicEntryOrder(); - if (err != NO_ERROR && firstError == NO_ERROR) { - firstError = err; - } - - const size_t N = t->getOrderedConfigs().size(); - t->setIndex(ti+1); - - LOG_ALWAYS_FATAL_IF(ti == 0 && attr != t, - "First type is not attr!"); - - for (size_t ei=0; ei<N; ei++) { - sp<ConfigList> c = t->getOrderedConfigs().itemAt(ei); - if (c == NULL) { - continue; - } - c->setEntryIndex(ei); - } - } - - // Assign resource IDs to keys in bags... - for (ti=0; ti<N; ti++) { - sp<Type> t = p->getOrderedTypes().itemAt(ti); - if (t == NULL) { - continue; - } - const size_t N = t->getOrderedConfigs().size(); - for (size_t ci=0; ci<N; ci++) { - sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci); - //printf("Ordered config #%d: %p\n", ci, c.get()); - const size_t N = c->getEntries().size(); - for (size_t ei=0; ei<N; ei++) { - sp<Entry> e = c->getEntries().valueAt(ei); - if (e == NULL) { - continue; - } - status_t err = e->assignResourceIds(this, p->getName()); - if (err != NO_ERROR && firstError == NO_ERROR) { - firstError = err; - } - } - } - } - } - return firstError; -} - -status_t ResourceTable::addSymbols(const sp<AaptSymbols>& outSymbols) { - const size_t N = mOrderedPackages.size(); - size_t pi; - - for (pi=0; pi<N; pi++) { - sp<Package> p = mOrderedPackages.itemAt(pi); - if (p->getTypes().size() == 0) { - // Empty, skip! - continue; - } - - const size_t N = p->getOrderedTypes().size(); - size_t ti; - - for (ti=0; ti<N; ti++) { - sp<Type> t = p->getOrderedTypes().itemAt(ti); - if (t == NULL) { - continue; - } - const size_t N = t->getOrderedConfigs().size(); - sp<AaptSymbols> typeSymbols; - typeSymbols = outSymbols->addNestedSymbol(String8(t->getName()), t->getPos()); - for (size_t ci=0; ci<N; ci++) { - sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci); - if (c == NULL) { - continue; - } - uint32_t rid = getResId(p, t, ci); - if (rid == 0) { - return UNKNOWN_ERROR; - } - if (Res_GETPACKAGE(rid) == (size_t)(p->getAssignedId()-1)) { - typeSymbols->addSymbol(String8(c->getName()), rid, c->getPos()); - - String16 comment(c->getComment()); - typeSymbols->appendComment(String8(c->getName()), comment, c->getPos()); - //printf("Type symbol %s comment: %s\n", String8(e->getName()).string(), - // String8(comment).string()); - comment = c->getTypeComment(); - typeSymbols->appendTypeComment(String8(c->getName()), comment); - } else { -#if 0 - printf("**** NO MATCH: 0x%08x vs 0x%08x\n", - Res_GETPACKAGE(rid), p->getAssignedId()); -#endif - } - } - } - } - return NO_ERROR; -} - - -void -ResourceTable::addLocalization(const String16& name, const String8& locale) -{ - mLocalizations[name].insert(locale); -} - - -/*! - * Flag various sorts of localization problems. '+' indicates checks already implemented; - * '-' indicates checks that will be implemented in the future. - * - * + A localized string for which no default-locale version exists => warning - * + A string for which no version in an explicitly-requested locale exists => warning - * + A localized translation of an translateable="false" string => warning - * - A localized string not provided in every locale used by the table - */ -status_t -ResourceTable::validateLocalizations(void) -{ - status_t err = NO_ERROR; - const String8 defaultLocale; - - // For all strings... - for (map<String16, set<String8> >::iterator nameIter = mLocalizations.begin(); - nameIter != mLocalizations.end(); - nameIter++) { - const set<String8>& configSet = nameIter->second; // naming convenience - - // Look for strings with no default localization - if (configSet.count(defaultLocale) == 0) { - fprintf(stdout, "aapt: warning: string '%s' has no default translation in %s; found:", - String8(nameIter->first).string(), mBundle->getResourceSourceDirs()[0]); - for (set<String8>::const_iterator locales = configSet.begin(); - locales != configSet.end(); - locales++) { - fprintf(stdout, " %s", (*locales).string()); - } - fprintf(stdout, "\n"); - // !!! TODO: throw an error here in some circumstances - } - - // Check that all requested localizations are present for this string - if (mBundle->getConfigurations() != NULL && mBundle->getRequireLocalization()) { - const char* allConfigs = mBundle->getConfigurations(); - const char* start = allConfigs; - const char* comma; - - do { - String8 config; - comma = strchr(start, ','); - if (comma != NULL) { - config.setTo(start, comma - start); - start = comma + 1; - } else { - config.setTo(start); - } - - // don't bother with the pseudolocale "zz_ZZ" - if (config != "zz_ZZ") { - if (configSet.find(config) == configSet.end()) { - // okay, no specific localization found. it's possible that we are - // requiring a specific regional localization [e.g. de_DE] but there is an - // available string in the generic language localization [e.g. de]; - // consider that string to have fulfilled the localization requirement. - String8 region(config.string(), 2); - if (configSet.find(region) == configSet.end()) { - if (configSet.count(defaultLocale) == 0) { - fprintf(stdout, "aapt: warning: " - "**** string '%s' has no default or required localization " - "for '%s' in %s\n", - String8(nameIter->first).string(), - config.string(), - mBundle->getResourceSourceDirs()[0]); - } - } - } - } - } while (comma != NULL); - } - } - - return err; -} - -status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest) -{ - ResourceFilter filter; - status_t err = filter.parse(bundle->getConfigurations()); - if (err != NO_ERROR) { - return err; - } - - const ConfigDescription nullConfig; - - const size_t N = mOrderedPackages.size(); - size_t pi; - - const static String16 mipmap16("mipmap"); - - bool useUTF8 = !bundle->getUTF16StringsOption(); - - // Iterate through all data, collecting all values (strings, - // references, etc). - StringPool valueStrings(useUTF8); - Vector<sp<Entry> > allEntries; - for (pi=0; pi<N; pi++) { - sp<Package> p = mOrderedPackages.itemAt(pi); - if (p->getTypes().size() == 0) { - // Empty, skip! - continue; - } - - StringPool typeStrings(useUTF8); - StringPool keyStrings(useUTF8); - - const size_t N = p->getOrderedTypes().size(); - for (size_t ti=0; ti<N; ti++) { - sp<Type> t = p->getOrderedTypes().itemAt(ti); - if (t == NULL) { - typeStrings.add(String16("<empty>"), false); - continue; - } - const String16 typeName(t->getName()); - typeStrings.add(typeName, false); - - // This is a hack to tweak the sorting order of the final strings, - // to put stuff that is generally not language-specific first. - String8 configTypeName(typeName); - if (configTypeName == "drawable" || configTypeName == "layout" - || configTypeName == "color" || configTypeName == "anim" - || configTypeName == "interpolator" || configTypeName == "animator" - || configTypeName == "xml" || configTypeName == "menu" - || configTypeName == "mipmap" || configTypeName == "raw") { - configTypeName = "1complex"; - } else { - configTypeName = "2value"; - } - - const bool filterable = (typeName != mipmap16); - - const size_t N = t->getOrderedConfigs().size(); - for (size_t ci=0; ci<N; ci++) { - sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci); - if (c == NULL) { - continue; - } - const size_t N = c->getEntries().size(); - for (size_t ei=0; ei<N; ei++) { - ConfigDescription config = c->getEntries().keyAt(ei); - if (filterable && !filter.match(config)) { - continue; - } - sp<Entry> e = c->getEntries().valueAt(ei); - if (e == NULL) { - continue; - } - e->setNameIndex(keyStrings.add(e->getName(), true)); - - // If this entry has no values for other configs, - // and is the default config, then it is special. Otherwise - // we want to add it with the config info. - ConfigDescription* valueConfig = NULL; - if (N != 1 || config == nullConfig) { - valueConfig = &config; - } - - status_t err = e->prepareFlatten(&valueStrings, this, - &configTypeName, &config); - if (err != NO_ERROR) { - return err; - } - allEntries.add(e); - } - } - } - - p->setTypeStrings(typeStrings.createStringBlock()); - p->setKeyStrings(keyStrings.createStringBlock()); - } - - if (bundle->getOutputAPKFile() != NULL) { - // Now we want to sort the value strings for better locality. This will - // cause the positions of the strings to change, so we need to go back - // through out resource entries and update them accordingly. Only need - // to do this if actually writing the output file. - valueStrings.sortByConfig(); - for (pi=0; pi<allEntries.size(); pi++) { - allEntries[pi]->remapStringValue(&valueStrings); - } - } - - ssize_t strAmt = 0; - - // Now build the array of package chunks. - Vector<sp<AaptFile> > flatPackages; - for (pi=0; pi<N; pi++) { - sp<Package> p = mOrderedPackages.itemAt(pi); - if (p->getTypes().size() == 0) { - // Empty, skip! - continue; - } - - const size_t N = p->getTypeStrings().size(); - - const size_t baseSize = sizeof(ResTable_package); - - // Start the package data. - sp<AaptFile> data = new AaptFile(String8(), AaptGroupEntry(), String8()); - ResTable_package* header = (ResTable_package*)data->editData(baseSize); - if (header == NULL) { - fprintf(stderr, "ERROR: out of memory creating ResTable_package\n"); - return NO_MEMORY; - } - memset(header, 0, sizeof(*header)); - header->header.type = htods(RES_TABLE_PACKAGE_TYPE); - header->header.headerSize = htods(sizeof(*header)); - header->id = htodl(p->getAssignedId()); - strcpy16_htod(header->name, p->getName().string()); - - // Write the string blocks. - const size_t typeStringsStart = data->getSize(); - sp<AaptFile> strFile = p->getTypeStringsData(); - ssize_t amt = data->writeData(strFile->getData(), strFile->getSize()); - #if PRINT_STRING_METRICS - fprintf(stderr, "**** type strings: %d\n", amt); - #endif - strAmt += amt; - if (amt < 0) { - return amt; - } - const size_t keyStringsStart = data->getSize(); - strFile = p->getKeyStringsData(); - amt = data->writeData(strFile->getData(), strFile->getSize()); - #if PRINT_STRING_METRICS - fprintf(stderr, "**** key strings: %d\n", amt); - #endif - strAmt += amt; - if (amt < 0) { - return amt; - } - - // Build the type chunks inside of this package. - for (size_t ti=0; ti<N; ti++) { - // Retrieve them in the same order as the type string block. - size_t len; - String16 typeName(p->getTypeStrings().stringAt(ti, &len)); - sp<Type> t = p->getTypes().valueFor(typeName); - LOG_ALWAYS_FATAL_IF(t == NULL && typeName != String16("<empty>"), - "Type name %s not found", - String8(typeName).string()); - - const bool filterable = (typeName != mipmap16); - - const size_t N = t != NULL ? t->getOrderedConfigs().size() : 0; - - // Until a non-NO_ENTRY value has been written for a resource, - // that resource is invalid; validResources[i] represents - // the item at t->getOrderedConfigs().itemAt(i). - Vector<bool> validResources; - validResources.insertAt(false, 0, N); - - // First write the typeSpec chunk, containing information about - // each resource entry in this type. - { - const size_t typeSpecSize = sizeof(ResTable_typeSpec) + sizeof(uint32_t)*N; - const size_t typeSpecStart = data->getSize(); - ResTable_typeSpec* tsHeader = (ResTable_typeSpec*) - (((uint8_t*)data->editData(typeSpecStart+typeSpecSize)) + typeSpecStart); - if (tsHeader == NULL) { - fprintf(stderr, "ERROR: out of memory creating ResTable_typeSpec\n"); - return NO_MEMORY; - } - memset(tsHeader, 0, sizeof(*tsHeader)); - tsHeader->header.type = htods(RES_TABLE_TYPE_SPEC_TYPE); - tsHeader->header.headerSize = htods(sizeof(*tsHeader)); - tsHeader->header.size = htodl(typeSpecSize); - tsHeader->id = ti+1; - tsHeader->entryCount = htodl(N); - - uint32_t* typeSpecFlags = (uint32_t*) - (((uint8_t*)data->editData()) - + typeSpecStart + sizeof(ResTable_typeSpec)); - memset(typeSpecFlags, 0, sizeof(uint32_t)*N); - - for (size_t ei=0; ei<N; ei++) { - sp<ConfigList> cl = t->getOrderedConfigs().itemAt(ei); - if (cl->getPublic()) { - typeSpecFlags[ei] |= htodl(ResTable_typeSpec::SPEC_PUBLIC); - } - const size_t CN = cl->getEntries().size(); - for (size_t ci=0; ci<CN; ci++) { - if (filterable && !filter.match(cl->getEntries().keyAt(ci))) { - continue; - } - for (size_t cj=ci+1; cj<CN; cj++) { - if (filterable && !filter.match(cl->getEntries().keyAt(cj))) { - continue; - } - typeSpecFlags[ei] |= htodl( - cl->getEntries().keyAt(ci).diff(cl->getEntries().keyAt(cj))); - } - } - } - } - - // We need to write one type chunk for each configuration for - // which we have entries in this type. - const size_t NC = t->getUniqueConfigs().size(); - - const size_t typeSize = sizeof(ResTable_type) + sizeof(uint32_t)*N; - - for (size_t ci=0; ci<NC; ci++) { - ConfigDescription config = t->getUniqueConfigs().itemAt(ci); - - NOISY(printf("Writing config %d config: imsi:%d/%d lang:%c%c cnt:%c%c " - "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d " - "sw%ddp w%ddp h%ddp dir:%d\n", - ti+1, - config.mcc, config.mnc, - config.language[0] ? config.language[0] : '-', - config.language[1] ? config.language[1] : '-', - config.country[0] ? config.country[0] : '-', - config.country[1] ? config.country[1] : '-', - config.orientation, - config.uiMode, - config.touchscreen, - config.density, - config.keyboard, - config.inputFlags, - config.navigation, - config.screenWidth, - config.screenHeight, - config.smallestScreenWidthDp, - config.screenWidthDp, - config.screenHeightDp, - config.layoutDirection)); - - if (filterable && !filter.match(config)) { - continue; - } - - const size_t typeStart = data->getSize(); - - ResTable_type* tHeader = (ResTable_type*) - (((uint8_t*)data->editData(typeStart+typeSize)) + typeStart); - if (tHeader == NULL) { - fprintf(stderr, "ERROR: out of memory creating ResTable_type\n"); - return NO_MEMORY; - } - - memset(tHeader, 0, sizeof(*tHeader)); - tHeader->header.type = htods(RES_TABLE_TYPE_TYPE); - tHeader->header.headerSize = htods(sizeof(*tHeader)); - tHeader->id = ti+1; - tHeader->entryCount = htodl(N); - tHeader->entriesStart = htodl(typeSize); - tHeader->config = config; - NOISY(printf("Writing type %d config: imsi:%d/%d lang:%c%c cnt:%c%c " - "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d " - "sw%ddp w%ddp h%ddp dir:%d\n", - ti+1, - tHeader->config.mcc, tHeader->config.mnc, - tHeader->config.language[0] ? tHeader->config.language[0] : '-', - tHeader->config.language[1] ? tHeader->config.language[1] : '-', - tHeader->config.country[0] ? tHeader->config.country[0] : '-', - tHeader->config.country[1] ? tHeader->config.country[1] : '-', - tHeader->config.orientation, - tHeader->config.uiMode, - tHeader->config.touchscreen, - tHeader->config.density, - tHeader->config.keyboard, - tHeader->config.inputFlags, - tHeader->config.navigation, - tHeader->config.screenWidth, - tHeader->config.screenHeight, - tHeader->config.smallestScreenWidthDp, - tHeader->config.screenWidthDp, - tHeader->config.screenHeightDp, - tHeader->config.layoutDirection)); - tHeader->config.swapHtoD(); - - // Build the entries inside of this type. - for (size_t ei=0; ei<N; ei++) { - sp<ConfigList> cl = t->getOrderedConfigs().itemAt(ei); - sp<Entry> e = cl->getEntries().valueFor(config); - - // Set the offset for this entry in its type. - uint32_t* index = (uint32_t*) - (((uint8_t*)data->editData()) - + typeStart + sizeof(ResTable_type)); - if (e != NULL) { - index[ei] = htodl(data->getSize()-typeStart-typeSize); - - // Create the entry. - ssize_t amt = e->flatten(bundle, data, cl->getPublic()); - if (amt < 0) { - return amt; - } - validResources.editItemAt(ei) = true; - } else { - index[ei] = htodl(ResTable_type::NO_ENTRY); - } - } - - // Fill in the rest of the type information. - tHeader = (ResTable_type*) - (((uint8_t*)data->editData()) + typeStart); - tHeader->header.size = htodl(data->getSize()-typeStart); - } - - for (size_t i = 0; i < N; ++i) { - if (!validResources[i]) { - sp<ConfigList> c = t->getOrderedConfigs().itemAt(i); - fprintf(stderr, "warning: no entries written for %s/%s\n", - String8(typeName).string(), String8(c->getName()).string()); - } - } - } - - // Fill in the rest of the package information. - header = (ResTable_package*)data->editData(); - header->header.size = htodl(data->getSize()); - header->typeStrings = htodl(typeStringsStart); - header->lastPublicType = htodl(p->getTypeStrings().size()); - header->keyStrings = htodl(keyStringsStart); - header->lastPublicKey = htodl(p->getKeyStrings().size()); - - flatPackages.add(data); - } - - // And now write out the final chunks. - const size_t dataStart = dest->getSize(); - - { - // blah - ResTable_header header; - memset(&header, 0, sizeof(header)); - header.header.type = htods(RES_TABLE_TYPE); - header.header.headerSize = htods(sizeof(header)); - header.packageCount = htodl(flatPackages.size()); - status_t err = dest->writeData(&header, sizeof(header)); - if (err != NO_ERROR) { - fprintf(stderr, "ERROR: out of memory creating ResTable_header\n"); - return err; - } - } - - ssize_t strStart = dest->getSize(); - err = valueStrings.writeStringBlock(dest); - if (err != NO_ERROR) { - return err; - } - - ssize_t amt = (dest->getSize()-strStart); - strAmt += amt; - #if PRINT_STRING_METRICS - fprintf(stderr, "**** value strings: %d\n", amt); - fprintf(stderr, "**** total strings: %d\n", strAmt); - #endif - - for (pi=0; pi<flatPackages.size(); pi++) { - err = dest->writeData(flatPackages[pi]->getData(), - flatPackages[pi]->getSize()); - if (err != NO_ERROR) { - fprintf(stderr, "ERROR: out of memory creating package chunk for ResTable_header\n"); - return err; - } - } - - ResTable_header* header = (ResTable_header*) - (((uint8_t*)dest->getData()) + dataStart); - header->header.size = htodl(dest->getSize() - dataStart); - - NOISY(aout << "Resource table:" - << HexDump(dest->getData(), dest->getSize()) << endl); - - #if PRINT_STRING_METRICS - fprintf(stderr, "**** total resource table size: %d / %d%% strings\n", - dest->getSize(), (strAmt*100)/dest->getSize()); - #endif - - return NO_ERROR; -} - -void ResourceTable::writePublicDefinitions(const String16& package, FILE* fp) -{ - fprintf(fp, - "<!-- This file contains <public> resource definitions for all\n" - " resources that were generated from the source data. -->\n" - "\n" - "<resources>\n"); - - writePublicDefinitions(package, fp, true); - writePublicDefinitions(package, fp, false); - - fprintf(fp, - "\n" - "</resources>\n"); -} - -void ResourceTable::writePublicDefinitions(const String16& package, FILE* fp, bool pub) -{ - bool didHeader = false; - - sp<Package> pkg = mPackages.valueFor(package); - if (pkg != NULL) { - const size_t NT = pkg->getOrderedTypes().size(); - for (size_t i=0; i<NT; i++) { - sp<Type> t = pkg->getOrderedTypes().itemAt(i); - if (t == NULL) { - continue; - } - - bool didType = false; - - const size_t NC = t->getOrderedConfigs().size(); - for (size_t j=0; j<NC; j++) { - sp<ConfigList> c = t->getOrderedConfigs().itemAt(j); - if (c == NULL) { - continue; - } - - if (c->getPublic() != pub) { - continue; - } - - if (!didType) { - fprintf(fp, "\n"); - didType = true; - } - if (!didHeader) { - if (pub) { - fprintf(fp," <!-- PUBLIC SECTION. These resources have been declared public.\n"); - fprintf(fp," Changes to these definitions will break binary compatibility. -->\n\n"); - } else { - fprintf(fp," <!-- PRIVATE SECTION. These resources have not been declared public.\n"); - fprintf(fp," You can make them public my moving these lines into a file in res/values. -->\n\n"); - } - didHeader = true; - } - if (!pub) { - const size_t NE = c->getEntries().size(); - for (size_t k=0; k<NE; k++) { - const SourcePos& pos = c->getEntries().valueAt(k)->getPos(); - if (pos.file != "") { - fprintf(fp," <!-- Declared at %s:%d -->\n", - pos.file.string(), pos.line); - } - } - } - fprintf(fp, " <public type=\"%s\" name=\"%s\" id=\"0x%08x\" />\n", - String8(t->getName()).string(), - String8(c->getName()).string(), - getResId(pkg, t, c->getEntryIndex())); - } - } - } -} - -ResourceTable::Item::Item(const SourcePos& _sourcePos, - bool _isId, - const String16& _value, - const Vector<StringPool::entry_style_span>* _style, - int32_t _format) - : sourcePos(_sourcePos) - , isId(_isId) - , value(_value) - , format(_format) - , bagKeyId(0) - , evaluating(false) -{ - if (_style) { - style = *_style; - } -} - -status_t ResourceTable::Entry::makeItABag(const SourcePos& sourcePos) -{ - if (mType == TYPE_BAG) { - return NO_ERROR; - } - if (mType == TYPE_UNKNOWN) { - mType = TYPE_BAG; - return NO_ERROR; - } - sourcePos.error("Resource entry %s is already defined as a single item.\n" - "%s:%d: Originally defined here.\n", - String8(mName).string(), - mItem.sourcePos.file.string(), mItem.sourcePos.line); - return UNKNOWN_ERROR; -} - -status_t ResourceTable::Entry::setItem(const SourcePos& sourcePos, - const String16& value, - const Vector<StringPool::entry_style_span>* style, - int32_t format, - const bool overwrite) -{ - Item item(sourcePos, false, value, style); - - if (mType == TYPE_BAG) { - const Item& item(mBag.valueAt(0)); - sourcePos.error("Resource entry %s is already defined as a bag.\n" - "%s:%d: Originally defined here.\n", - String8(mName).string(), - item.sourcePos.file.string(), item.sourcePos.line); - return UNKNOWN_ERROR; - } - if ( (mType != TYPE_UNKNOWN) && (overwrite == false) ) { - sourcePos.error("Resource entry %s is already defined.\n" - "%s:%d: Originally defined here.\n", - String8(mName).string(), - mItem.sourcePos.file.string(), mItem.sourcePos.line); - return UNKNOWN_ERROR; - } - - mType = TYPE_ITEM; - mItem = item; - mItemFormat = format; - return NO_ERROR; -} - -status_t ResourceTable::Entry::addToBag(const SourcePos& sourcePos, - const String16& key, const String16& value, - const Vector<StringPool::entry_style_span>* style, - bool replace, bool isId, int32_t format) -{ - status_t err = makeItABag(sourcePos); - if (err != NO_ERROR) { - return err; - } - - Item item(sourcePos, isId, value, style, format); - - // XXX NOTE: there is an error if you try to have a bag with two keys, - // one an attr and one an id, with the same name. Not something we - // currently ever have to worry about. - ssize_t origKey = mBag.indexOfKey(key); - if (origKey >= 0) { - if (!replace) { - const Item& item(mBag.valueAt(origKey)); - sourcePos.error("Resource entry %s already has bag item %s.\n" - "%s:%d: Originally defined here.\n", - String8(mName).string(), String8(key).string(), - item.sourcePos.file.string(), item.sourcePos.line); - return UNKNOWN_ERROR; - } - //printf("Replacing %s with %s\n", - // String8(mBag.valueFor(key).value).string(), String8(value).string()); - mBag.replaceValueFor(key, item); - } - - mBag.add(key, item); - return NO_ERROR; -} - -status_t ResourceTable::Entry::emptyBag(const SourcePos& sourcePos) -{ - status_t err = makeItABag(sourcePos); - if (err != NO_ERROR) { - return err; - } - - mBag.clear(); - return NO_ERROR; -} - -status_t ResourceTable::Entry::generateAttributes(ResourceTable* table, - const String16& package) -{ - const String16 attr16("attr"); - const String16 id16("id"); - const size_t N = mBag.size(); - for (size_t i=0; i<N; i++) { - const String16& key = mBag.keyAt(i); - const Item& it = mBag.valueAt(i); - if (it.isId) { - if (!table->hasBagOrEntry(key, &id16, &package)) { - String16 value("false"); - status_t err = table->addEntry(SourcePos(String8("<generated>"), 0), package, - id16, key, value); - if (err != NO_ERROR) { - return err; - } - } - } else if (!table->hasBagOrEntry(key, &attr16, &package)) { - -#if 1 -// fprintf(stderr, "ERROR: Bag attribute '%s' has not been defined.\n", -// String8(key).string()); -// const Item& item(mBag.valueAt(i)); -// fprintf(stderr, "Referenced from file %s line %d\n", -// item.sourcePos.file.string(), item.sourcePos.line); -// return UNKNOWN_ERROR; -#else - char numberStr[16]; - sprintf(numberStr, "%d", ResTable_map::TYPE_ANY); - status_t err = table->addBag(SourcePos("<generated>", 0), package, - attr16, key, String16(""), - String16("^type"), - String16(numberStr), NULL, NULL); - if (err != NO_ERROR) { - return err; - } -#endif - } - } - return NO_ERROR; -} - -status_t ResourceTable::Entry::assignResourceIds(ResourceTable* table, - const String16& package) -{ - bool hasErrors = false; - - if (mType == TYPE_BAG) { - const char* errorMsg; - const String16 style16("style"); - const String16 attr16("attr"); - const String16 id16("id"); - mParentId = 0; - if (mParent.size() > 0) { - mParentId = table->getResId(mParent, &style16, NULL, &errorMsg); - if (mParentId == 0) { - mPos.error("Error retrieving parent for item: %s '%s'.\n", - errorMsg, String8(mParent).string()); - hasErrors = true; - } - } - const size_t N = mBag.size(); - for (size_t i=0; i<N; i++) { - const String16& key = mBag.keyAt(i); - Item& it = mBag.editValueAt(i); - it.bagKeyId = table->getResId(key, - it.isId ? &id16 : &attr16, NULL, &errorMsg); - //printf("Bag key of %s: #%08x\n", String8(key).string(), it.bagKeyId); - if (it.bagKeyId == 0) { - it.sourcePos.error("Error: %s: %s '%s'.\n", errorMsg, - String8(it.isId ? id16 : attr16).string(), - String8(key).string()); - hasErrors = true; - } - } - } - return hasErrors ? UNKNOWN_ERROR : NO_ERROR; -} - -status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable* table, - const String8* configTypeName, const ConfigDescription* config) -{ - if (mType == TYPE_ITEM) { - Item& it = mItem; - AccessorCookie ac(it.sourcePos, String8(mName), String8(it.value)); - if (!table->stringToValue(&it.parsedValue, strings, - it.value, false, true, 0, - &it.style, NULL, &ac, mItemFormat, - configTypeName, config)) { - return UNKNOWN_ERROR; - } - } else if (mType == TYPE_BAG) { - const size_t N = mBag.size(); - for (size_t i=0; i<N; i++) { - const String16& key = mBag.keyAt(i); - Item& it = mBag.editValueAt(i); - AccessorCookie ac(it.sourcePos, String8(key), String8(it.value)); - if (!table->stringToValue(&it.parsedValue, strings, - it.value, false, true, it.bagKeyId, - &it.style, NULL, &ac, it.format, - configTypeName, config)) { - return UNKNOWN_ERROR; - } - } - } else { - mPos.error("Error: entry %s is not a single item or a bag.\n", - String8(mName).string()); - return UNKNOWN_ERROR; - } - return NO_ERROR; -} - -status_t ResourceTable::Entry::remapStringValue(StringPool* strings) -{ - if (mType == TYPE_ITEM) { - Item& it = mItem; - if (it.parsedValue.dataType == Res_value::TYPE_STRING) { - it.parsedValue.data = strings->mapOriginalPosToNewPos(it.parsedValue.data); - } - } else if (mType == TYPE_BAG) { - const size_t N = mBag.size(); - for (size_t i=0; i<N; i++) { - Item& it = mBag.editValueAt(i); - if (it.parsedValue.dataType == Res_value::TYPE_STRING) { - it.parsedValue.data = strings->mapOriginalPosToNewPos(it.parsedValue.data); - } - } - } else { - mPos.error("Error: entry %s is not a single item or a bag.\n", - String8(mName).string()); - return UNKNOWN_ERROR; - } - return NO_ERROR; -} - -ssize_t ResourceTable::Entry::flatten(Bundle* bundle, const sp<AaptFile>& data, bool isPublic) -{ - size_t amt = 0; - ResTable_entry header; - memset(&header, 0, sizeof(header)); - header.size = htods(sizeof(header)); - const type ty = this != NULL ? mType : TYPE_ITEM; - if (this != NULL) { - if (ty == TYPE_BAG) { - header.flags |= htods(header.FLAG_COMPLEX); - } - if (isPublic) { - header.flags |= htods(header.FLAG_PUBLIC); - } - header.key.index = htodl(mNameIndex); - } - if (ty != TYPE_BAG) { - status_t err = data->writeData(&header, sizeof(header)); - if (err != NO_ERROR) { - fprintf(stderr, "ERROR: out of memory creating ResTable_entry\n"); - return err; - } - - const Item& it = mItem; - Res_value par; - memset(&par, 0, sizeof(par)); - par.size = htods(it.parsedValue.size); - par.dataType = it.parsedValue.dataType; - par.res0 = it.parsedValue.res0; - par.data = htodl(it.parsedValue.data); - #if 0 - printf("Writing item (%s): type=%d, data=0x%x, res0=0x%x\n", - String8(mName).string(), it.parsedValue.dataType, - it.parsedValue.data, par.res0); - #endif - err = data->writeData(&par, it.parsedValue.size); - if (err != NO_ERROR) { - fprintf(stderr, "ERROR: out of memory creating Res_value\n"); - return err; - } - amt += it.parsedValue.size; - } else { - size_t N = mBag.size(); - size_t i; - // Create correct ordering of items. - KeyedVector<uint32_t, const Item*> items; - for (i=0; i<N; i++) { - const Item& it = mBag.valueAt(i); - items.add(it.bagKeyId, &it); - } - N = items.size(); - - ResTable_map_entry mapHeader; - memcpy(&mapHeader, &header, sizeof(header)); - mapHeader.size = htods(sizeof(mapHeader)); - mapHeader.parent.ident = htodl(mParentId); - mapHeader.count = htodl(N); - status_t err = data->writeData(&mapHeader, sizeof(mapHeader)); - if (err != NO_ERROR) { - fprintf(stderr, "ERROR: out of memory creating ResTable_entry\n"); - return err; - } - - for (i=0; i<N; i++) { - const Item& it = *items.valueAt(i); - ResTable_map map; - map.name.ident = htodl(it.bagKeyId); - map.value.size = htods(it.parsedValue.size); - map.value.dataType = it.parsedValue.dataType; - map.value.res0 = it.parsedValue.res0; - map.value.data = htodl(it.parsedValue.data); - err = data->writeData(&map, sizeof(map)); - if (err != NO_ERROR) { - fprintf(stderr, "ERROR: out of memory creating Res_value\n"); - return err; - } - amt += sizeof(map); - } - } - return amt; -} - -void ResourceTable::ConfigList::appendComment(const String16& comment, - bool onlyIfEmpty) -{ - if (comment.size() <= 0) { - return; - } - if (onlyIfEmpty && mComment.size() > 0) { - return; - } - if (mComment.size() > 0) { - mComment.append(String16("\n")); - } - mComment.append(comment); -} - -void ResourceTable::ConfigList::appendTypeComment(const String16& comment) -{ - if (comment.size() <= 0) { - return; - } - if (mTypeComment.size() > 0) { - mTypeComment.append(String16("\n")); - } - mTypeComment.append(comment); -} - -status_t ResourceTable::Type::addPublic(const SourcePos& sourcePos, - const String16& name, - const uint32_t ident) -{ - #if 0 - int32_t entryIdx = Res_GETENTRY(ident); - if (entryIdx < 0) { - sourcePos.error("Public resource %s/%s has an invalid 0 identifier (0x%08x).\n", - String8(mName).string(), String8(name).string(), ident); - return UNKNOWN_ERROR; - } - #endif - - int32_t typeIdx = Res_GETTYPE(ident); - if (typeIdx >= 0) { - typeIdx++; - if (mPublicIndex > 0 && mPublicIndex != typeIdx) { - sourcePos.error("Public resource %s/%s has conflicting type codes for its" - " public identifiers (0x%x vs 0x%x).\n", - String8(mName).string(), String8(name).string(), - mPublicIndex, typeIdx); - return UNKNOWN_ERROR; - } - mPublicIndex = typeIdx; - } - - if (mFirstPublicSourcePos == NULL) { - mFirstPublicSourcePos = new SourcePos(sourcePos); - } - - if (mPublic.indexOfKey(name) < 0) { - mPublic.add(name, Public(sourcePos, String16(), ident)); - } else { - Public& p = mPublic.editValueFor(name); - if (p.ident != ident) { - sourcePos.error("Public resource %s/%s has conflicting public identifiers" - " (0x%08x vs 0x%08x).\n" - "%s:%d: Originally defined here.\n", - String8(mName).string(), String8(name).string(), p.ident, ident, - p.sourcePos.file.string(), p.sourcePos.line); - return UNKNOWN_ERROR; - } - } - - return NO_ERROR; -} - -void ResourceTable::Type::canAddEntry(const String16& name) -{ - mCanAddEntries.add(name); -} - -sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry, - const SourcePos& sourcePos, - const ResTable_config* config, - bool doSetIndex, - bool overlay, - bool autoAddOverlay) -{ - int pos = -1; - sp<ConfigList> c = mConfigs.valueFor(entry); - if (c == NULL) { - if (overlay && !autoAddOverlay && mCanAddEntries.indexOf(entry) < 0) { - sourcePos.error("Resource at %s appears in overlay but not" - " in the base package; use <add-resource> to add.\n", - String8(entry).string()); - return NULL; - } - c = new ConfigList(entry, sourcePos); - mConfigs.add(entry, c); - pos = (int)mOrderedConfigs.size(); - mOrderedConfigs.add(c); - if (doSetIndex) { - c->setEntryIndex(pos); - } - } - - ConfigDescription cdesc; - if (config) cdesc = *config; - - sp<Entry> e = c->getEntries().valueFor(cdesc); - if (e == NULL) { - if (config != NULL) { - NOISY(printf("New entry at %s:%d: imsi:%d/%d lang:%c%c cnt:%c%c " - "orien:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d " - "sw%ddp w%ddp h%ddp dir:%d\n", - sourcePos.file.string(), sourcePos.line, - config->mcc, config->mnc, - config->language[0] ? config->language[0] : '-', - config->language[1] ? config->language[1] : '-', - config->country[0] ? config->country[0] : '-', - config->country[1] ? config->country[1] : '-', - config->orientation, - config->touchscreen, - config->density, - config->keyboard, - config->inputFlags, - config->navigation, - config->screenWidth, - config->screenHeight, - config->smallestScreenWidthDp, - config->screenWidthDp, - config->screenHeightDp, - config->layoutDirection)); - } else { - NOISY(printf("New entry at %s:%d: NULL config\n", - sourcePos.file.string(), sourcePos.line)); - } - e = new Entry(entry, sourcePos); - c->addEntry(cdesc, e); - /* - if (doSetIndex) { - if (pos < 0) { - for (pos=0; pos<(int)mOrderedConfigs.size(); pos++) { - if (mOrderedConfigs[pos] == c) { - break; - } - } - if (pos >= (int)mOrderedConfigs.size()) { - sourcePos.error("Internal error: config not found in mOrderedConfigs when adding entry"); - return NULL; - } - } - e->setEntryIndex(pos); - } - */ - } - - mUniqueConfigs.add(cdesc); - - return e; -} - -status_t ResourceTable::Type::applyPublicEntryOrder() -{ - size_t N = mOrderedConfigs.size(); - Vector<sp<ConfigList> > origOrder(mOrderedConfigs); - bool hasError = false; - - size_t i; - for (i=0; i<N; i++) { - mOrderedConfigs.replaceAt(NULL, i); - } - - const size_t NP = mPublic.size(); - //printf("Ordering %d configs from %d public defs\n", N, NP); - size_t j; - for (j=0; j<NP; j++) { - const String16& name = mPublic.keyAt(j); - const Public& p = mPublic.valueAt(j); - int32_t idx = Res_GETENTRY(p.ident); - //printf("Looking for entry \"%s\"/\"%s\" (0x%08x) in %d...\n", - // String8(mName).string(), String8(name).string(), p.ident, N); - bool found = false; - for (i=0; i<N; i++) { - sp<ConfigList> e = origOrder.itemAt(i); - //printf("#%d: \"%s\"\n", i, String8(e->getName()).string()); - if (e->getName() == name) { - if (idx >= (int32_t)mOrderedConfigs.size()) { - p.sourcePos.error("Public entry identifier 0x%x entry index " - "is larger than available symbols (index %d, total symbols %d).\n", - p.ident, idx, mOrderedConfigs.size()); - hasError = true; - } else if (mOrderedConfigs.itemAt(idx) == NULL) { - e->setPublic(true); - e->setPublicSourcePos(p.sourcePos); - mOrderedConfigs.replaceAt(e, idx); - origOrder.removeAt(i); - N--; - found = true; - break; - } else { - sp<ConfigList> oe = mOrderedConfigs.itemAt(idx); - - p.sourcePos.error("Multiple entry names declared for public entry" - " identifier 0x%x in type %s (%s vs %s).\n" - "%s:%d: Originally defined here.", - idx+1, String8(mName).string(), - String8(oe->getName()).string(), - String8(name).string(), - oe->getPublicSourcePos().file.string(), - oe->getPublicSourcePos().line); - hasError = true; - } - } - } - - if (!found) { - p.sourcePos.error("Public symbol %s/%s declared here is not defined.", - String8(mName).string(), String8(name).string()); - hasError = true; - } - } - - //printf("Copying back in %d non-public configs, have %d\n", N, origOrder.size()); - - if (N != origOrder.size()) { - printf("Internal error: remaining private symbol count mismatch\n"); - N = origOrder.size(); - } - - j = 0; - for (i=0; i<N; i++) { - sp<ConfigList> e = origOrder.itemAt(i); - // There will always be enough room for the remaining entries. - while (mOrderedConfigs.itemAt(j) != NULL) { - j++; - } - mOrderedConfigs.replaceAt(e, j); - j++; - } - - return hasError ? UNKNOWN_ERROR : NO_ERROR; -} - -ResourceTable::Package::Package(const String16& name, ssize_t includedId) - : mName(name), mIncludedId(includedId), - mTypeStringsMapping(0xffffffff), - mKeyStringsMapping(0xffffffff) -{ -} - -sp<ResourceTable::Type> ResourceTable::Package::getType(const String16& type, - const SourcePos& sourcePos, - bool doSetIndex) -{ - sp<Type> t = mTypes.valueFor(type); - if (t == NULL) { - t = new Type(type, sourcePos); - mTypes.add(type, t); - mOrderedTypes.add(t); - if (doSetIndex) { - // For some reason the type's index is set to one plus the index - // in the mOrderedTypes list, rather than just the index. - t->setIndex(mOrderedTypes.size()); - } - } - return t; -} - -status_t ResourceTable::Package::setTypeStrings(const sp<AaptFile>& data) -{ - mTypeStringsData = data; - status_t err = setStrings(data, &mTypeStrings, &mTypeStringsMapping); - if (err != NO_ERROR) { - fprintf(stderr, "ERROR: Type string data is corrupt!\n"); - } - return err; -} - -status_t ResourceTable::Package::setKeyStrings(const sp<AaptFile>& data) -{ - mKeyStringsData = data; - status_t err = setStrings(data, &mKeyStrings, &mKeyStringsMapping); - if (err != NO_ERROR) { - fprintf(stderr, "ERROR: Key string data is corrupt!\n"); - } - return err; -} - -status_t ResourceTable::Package::setStrings(const sp<AaptFile>& data, - ResStringPool* strings, - DefaultKeyedVector<String16, uint32_t>* mappings) -{ - if (data->getData() == NULL) { - return UNKNOWN_ERROR; - } - - NOISY(aout << "Setting restable string pool: " - << HexDump(data->getData(), data->getSize()) << endl); - - status_t err = strings->setTo(data->getData(), data->getSize()); - if (err == NO_ERROR) { - const size_t N = strings->size(); - for (size_t i=0; i<N; i++) { - size_t len; - mappings->add(String16(strings->stringAt(i, &len)), i); - } - } - return err; -} - -status_t ResourceTable::Package::applyPublicTypeOrder() -{ - size_t N = mOrderedTypes.size(); - Vector<sp<Type> > origOrder(mOrderedTypes); - - size_t i; - for (i=0; i<N; i++) { - mOrderedTypes.replaceAt(NULL, i); - } - - for (i=0; i<N; i++) { - sp<Type> t = origOrder.itemAt(i); - int32_t idx = t->getPublicIndex(); - if (idx > 0) { - idx--; - while (idx >= (int32_t)mOrderedTypes.size()) { - mOrderedTypes.add(); - } - if (mOrderedTypes.itemAt(idx) != NULL) { - sp<Type> ot = mOrderedTypes.itemAt(idx); - t->getFirstPublicSourcePos().error("Multiple type names declared for public type" - " identifier 0x%x (%s vs %s).\n" - "%s:%d: Originally defined here.", - idx, String8(ot->getName()).string(), - String8(t->getName()).string(), - ot->getFirstPublicSourcePos().file.string(), - ot->getFirstPublicSourcePos().line); - return UNKNOWN_ERROR; - } - mOrderedTypes.replaceAt(t, idx); - origOrder.removeAt(i); - i--; - N--; - } - } - - size_t j=0; - for (i=0; i<N; i++) { - sp<Type> t = origOrder.itemAt(i); - // There will always be enough room for the remaining types. - while (mOrderedTypes.itemAt(j) != NULL) { - j++; - } - mOrderedTypes.replaceAt(t, j); - } - - return NO_ERROR; -} - -sp<ResourceTable::Package> ResourceTable::getPackage(const String16& package) -{ - sp<Package> p = mPackages.valueFor(package); - if (p == NULL) { - if (mIsAppPackage) { - if (mHaveAppPackage) { - fprintf(stderr, "Adding multiple application package resources; only one is allowed.\n" - "Use -x to create extended resources.\n"); - return NULL; - } - mHaveAppPackage = true; - p = new Package(package, 127); - } else { - p = new Package(package, mNextPackageId); - } - //printf("*** NEW PACKAGE: \"%s\" id=%d\n", - // String8(package).string(), p->getAssignedId()); - mPackages.add(package, p); - mOrderedPackages.add(p); - mNextPackageId++; - } - return p; -} - -sp<ResourceTable::Type> ResourceTable::getType(const String16& package, - const String16& type, - const SourcePos& sourcePos, - bool doSetIndex) -{ - sp<Package> p = getPackage(package); - if (p == NULL) { - return NULL; - } - return p->getType(type, sourcePos, doSetIndex); -} - -sp<ResourceTable::Entry> ResourceTable::getEntry(const String16& package, - const String16& type, - const String16& name, - const SourcePos& sourcePos, - bool overlay, - const ResTable_config* config, - bool doSetIndex) -{ - sp<Type> t = getType(package, type, sourcePos, doSetIndex); - if (t == NULL) { - return NULL; - } - return t->getEntry(name, sourcePos, config, doSetIndex, overlay, mBundle->getAutoAddOverlay()); -} - -sp<const ResourceTable::Entry> ResourceTable::getEntry(uint32_t resID, - const ResTable_config* config) const -{ - int pid = Res_GETPACKAGE(resID)+1; - const size_t N = mOrderedPackages.size(); - size_t i; - sp<Package> p; - for (i=0; i<N; i++) { - sp<Package> check = mOrderedPackages[i]; - if (check->getAssignedId() == pid) { - p = check; - break; - } - - } - if (p == NULL) { - fprintf(stderr, "warning: Package not found for resource #%08x\n", resID); - return NULL; - } - - int tid = Res_GETTYPE(resID); - if (tid < 0 || tid >= (int)p->getOrderedTypes().size()) { - fprintf(stderr, "warning: Type not found for resource #%08x\n", resID); - return NULL; - } - sp<Type> t = p->getOrderedTypes()[tid]; - - int eid = Res_GETENTRY(resID); - if (eid < 0 || eid >= (int)t->getOrderedConfigs().size()) { - fprintf(stderr, "warning: Entry not found for resource #%08x\n", resID); - return NULL; - } - - sp<ConfigList> c = t->getOrderedConfigs()[eid]; - if (c == NULL) { - fprintf(stderr, "warning: Entry not found for resource #%08x\n", resID); - return NULL; - } - - ConfigDescription cdesc; - if (config) cdesc = *config; - sp<Entry> e = c->getEntries().valueFor(cdesc); - if (c == NULL) { - fprintf(stderr, "warning: Entry configuration not found for resource #%08x\n", resID); - return NULL; - } - - return e; -} - -const ResourceTable::Item* ResourceTable::getItem(uint32_t resID, uint32_t attrID) const -{ - sp<const Entry> e = getEntry(resID); - if (e == NULL) { - return NULL; - } - - const size_t N = e->getBag().size(); - for (size_t i=0; i<N; i++) { - const Item& it = e->getBag().valueAt(i); - if (it.bagKeyId == 0) { - fprintf(stderr, "warning: ID not yet assigned to '%s' in bag '%s'\n", - String8(e->getName()).string(), - String8(e->getBag().keyAt(i)).string()); - } - if (it.bagKeyId == attrID) { - return ⁢ - } - } - - return NULL; -} - -bool ResourceTable::getItemValue( - uint32_t resID, uint32_t attrID, Res_value* outValue) -{ - const Item* item = getItem(resID, attrID); - - bool res = false; - if (item != NULL) { - if (item->evaluating) { - sp<const Entry> e = getEntry(resID); - const size_t N = e->getBag().size(); - size_t i; - for (i=0; i<N; i++) { - if (&e->getBag().valueAt(i) == item) { - break; - } - } - fprintf(stderr, "warning: Circular reference detected in key '%s' of bag '%s'\n", - String8(e->getName()).string(), - String8(e->getBag().keyAt(i)).string()); - return false; - } - item->evaluating = true; - res = stringToValue(outValue, NULL, item->value, false, false, item->bagKeyId); - NOISY( - if (res) { - printf("getItemValue of #%08x[#%08x] (%s): type=#%08x, data=#%08x\n", - resID, attrID, String8(getEntry(resID)->getName()).string(), - outValue->dataType, outValue->data); - } else { - printf("getItemValue of #%08x[#%08x]: failed\n", - resID, attrID); - } - ); - item->evaluating = false; - } - return res; -} diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h deleted file mode 100644 index a3e0666..0000000 --- a/tools/aapt/ResourceTable.h +++ /dev/null @@ -1,557 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Build resource files from raw assets. -// - -#ifndef RESOURCE_TABLE_H -#define RESOURCE_TABLE_H - -#include "StringPool.h" -#include "SourcePos.h" - -#include <set> -#include <map> - -using namespace std; - -class XMLNode; -class ResourceTable; - -enum { - XML_COMPILE_STRIP_COMMENTS = 1<<0, - XML_COMPILE_ASSIGN_ATTRIBUTE_IDS = 1<<1, - XML_COMPILE_COMPACT_WHITESPACE = 1<<2, - XML_COMPILE_STRIP_WHITESPACE = 1<<3, - XML_COMPILE_STRIP_RAW_VALUES = 1<<4, - XML_COMPILE_UTF8 = 1<<5, - - XML_COMPILE_STANDARD_RESOURCE = - XML_COMPILE_STRIP_COMMENTS | XML_COMPILE_ASSIGN_ATTRIBUTE_IDS - | XML_COMPILE_STRIP_WHITESPACE | XML_COMPILE_STRIP_RAW_VALUES -}; - -status_t compileXmlFile(const sp<AaptAssets>& assets, - const sp<AaptFile>& target, - ResourceTable* table, - int options = XML_COMPILE_STANDARD_RESOURCE); - -status_t compileXmlFile(const sp<AaptAssets>& assets, - const sp<AaptFile>& target, - const sp<AaptFile>& outTarget, - ResourceTable* table, - int options = XML_COMPILE_STANDARD_RESOURCE); - -status_t compileXmlFile(const sp<AaptAssets>& assets, - const sp<XMLNode>& xmlTree, - const sp<AaptFile>& target, - ResourceTable* table, - int options = XML_COMPILE_STANDARD_RESOURCE); - -status_t compileResourceFile(Bundle* bundle, - const sp<AaptAssets>& assets, - const sp<AaptFile>& in, - const ResTable_config& defParams, - const bool overwrite, - ResourceTable* outTable); - -struct AccessorCookie -{ - SourcePos sourcePos; - String8 attr; - String8 value; - - AccessorCookie(const SourcePos&p, const String8& a, const String8& v) - :sourcePos(p), - attr(a), - value(v) - { - } -}; - -class ResourceTable : public ResTable::Accessor -{ -public: - class Package; - class Type; - class Entry; - - struct ConfigDescription : public ResTable_config { - ConfigDescription() { - memset(this, 0, sizeof(*this)); - size = sizeof(ResTable_config); - } - ConfigDescription(const ResTable_config&o) { - *static_cast<ResTable_config*>(this) = o; - size = sizeof(ResTable_config); - } - ConfigDescription(const ConfigDescription&o) { - *static_cast<ResTable_config*>(this) = o; - } - - ConfigDescription& operator=(const ResTable_config& o) { - *static_cast<ResTable_config*>(this) = o; - size = sizeof(ResTable_config); - return *this; - } - ConfigDescription& operator=(const ConfigDescription& o) { - *static_cast<ResTable_config*>(this) = o; - return *this; - } - - inline bool operator<(const ConfigDescription& o) const { return compare(o) < 0; } - inline bool operator<=(const ConfigDescription& o) const { return compare(o) <= 0; } - inline bool operator==(const ConfigDescription& o) const { return compare(o) == 0; } - inline bool operator!=(const ConfigDescription& o) const { return compare(o) != 0; } - inline bool operator>=(const ConfigDescription& o) const { return compare(o) >= 0; } - inline bool operator>(const ConfigDescription& o) const { return compare(o) > 0; } - }; - - ResourceTable(Bundle* bundle, const String16& assetsPackage); - - status_t addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets); - - status_t addPublic(const SourcePos& pos, - const String16& package, - const String16& type, - const String16& name, - const uint32_t ident); - - status_t addEntry(const SourcePos& pos, - const String16& package, - const String16& type, - const String16& name, - const String16& value, - const Vector<StringPool::entry_style_span>* style = NULL, - const ResTable_config* params = NULL, - const bool doSetIndex = false, - const int32_t format = ResTable_map::TYPE_ANY, - const bool overwrite = false); - - status_t startBag(const SourcePos& pos, - const String16& package, - const String16& type, - const String16& name, - const String16& bagParent, - const ResTable_config* params = NULL, - bool overlay = false, - bool replace = false, - bool isId = false); - - status_t addBag(const SourcePos& pos, - const String16& package, - const String16& type, - const String16& name, - const String16& bagParent, - const String16& bagKey, - const String16& value, - const Vector<StringPool::entry_style_span>* style = NULL, - const ResTable_config* params = NULL, - bool replace = false, - bool isId = false, - const int32_t format = ResTable_map::TYPE_ANY); - - bool hasBagOrEntry(const String16& package, - const String16& type, - const String16& name) const; - - bool hasBagOrEntry(const String16& package, - const String16& type, - const String16& name, - const ResTable_config& config) const; - - bool hasBagOrEntry(const String16& ref, - const String16* defType = NULL, - const String16* defPackage = NULL); - - bool appendComment(const String16& package, - const String16& type, - const String16& name, - const String16& comment, - bool onlyIfEmpty = false); - - bool appendTypeComment(const String16& package, - const String16& type, - const String16& name, - const String16& comment); - - void canAddEntry(const SourcePos& pos, - const String16& package, const String16& type, const String16& name); - - size_t size() const; - size_t numLocalResources() const; - bool hasResources() const; - - sp<AaptFile> flatten(Bundle*); - - static inline uint32_t makeResId(uint32_t packageId, - uint32_t typeId, - uint32_t nameId) - { - return nameId | (typeId<<16) | (packageId<<24); - } - - static inline uint32_t getResId(const sp<Package>& p, - const sp<Type>& t, - uint32_t nameId); - - uint32_t getResId(const String16& package, - const String16& type, - const String16& name, - bool onlyPublic = true) const; - - uint32_t getResId(const String16& ref, - const String16* defType = NULL, - const String16* defPackage = NULL, - const char** outErrorMsg = NULL, - bool onlyPublic = true) const; - - static bool isValidResourceName(const String16& s); - - bool stringToValue(Res_value* outValue, StringPool* pool, - const String16& str, - bool preserveSpaces, bool coerceType, - uint32_t attrID, - const Vector<StringPool::entry_style_span>* style = NULL, - String16* outStr = NULL, void* accessorCookie = NULL, - uint32_t attrType = ResTable_map::TYPE_ANY, - const String8* configTypeName = NULL, - const ConfigDescription* config = NULL); - - status_t assignResourceIds(); - status_t addSymbols(const sp<AaptSymbols>& outSymbols = NULL); - void addLocalization(const String16& name, const String8& locale); - status_t validateLocalizations(void); - - status_t flatten(Bundle*, const sp<AaptFile>& dest); - - void writePublicDefinitions(const String16& package, FILE* fp); - - virtual uint32_t getCustomResource(const String16& package, - const String16& type, - const String16& name) const; - virtual uint32_t getCustomResourceWithCreation(const String16& package, - const String16& type, - const String16& name, - const bool createIfNeeded); - virtual uint32_t getRemappedPackage(uint32_t origPackage) const; - virtual bool getAttributeType(uint32_t attrID, uint32_t* outType); - virtual bool getAttributeMin(uint32_t attrID, uint32_t* outMin); - virtual bool getAttributeMax(uint32_t attrID, uint32_t* outMax); - virtual bool getAttributeKeys(uint32_t attrID, Vector<String16>* outKeys); - virtual bool getAttributeEnum(uint32_t attrID, - const char16_t* name, size_t nameLen, - Res_value* outValue); - virtual bool getAttributeFlags(uint32_t attrID, - const char16_t* name, size_t nameLen, - Res_value* outValue); - virtual uint32_t getAttributeL10N(uint32_t attrID); - - virtual bool getLocalizationSetting(); - virtual void reportError(void* accessorCookie, const char* fmt, ...); - - void setCurrentXmlPos(const SourcePos& pos) { mCurrentXmlPos = pos; } - - class Item { - public: - Item() : isId(false), format(ResTable_map::TYPE_ANY), bagKeyId(0), evaluating(false) - { memset(&parsedValue, 0, sizeof(parsedValue)); } - Item(const SourcePos& pos, - bool _isId, - const String16& _value, - const Vector<StringPool::entry_style_span>* _style = NULL, - int32_t format = ResTable_map::TYPE_ANY); - Item(const Item& o) : sourcePos(o.sourcePos), - isId(o.isId), value(o.value), style(o.style), - format(o.format), bagKeyId(o.bagKeyId), evaluating(false) { - memset(&parsedValue, 0, sizeof(parsedValue)); - } - ~Item() { } - - Item& operator=(const Item& o) { - sourcePos = o.sourcePos; - isId = o.isId; - value = o.value; - style = o.style; - format = o.format; - bagKeyId = o.bagKeyId; - parsedValue = o.parsedValue; - return *this; - } - - SourcePos sourcePos; - mutable bool isId; - String16 value; - Vector<StringPool::entry_style_span> style; - int32_t format; - uint32_t bagKeyId; - mutable bool evaluating; - Res_value parsedValue; - }; - - class Entry : public RefBase { - public: - Entry(const String16& name, const SourcePos& pos) - : mName(name), mType(TYPE_UNKNOWN), - mItemFormat(ResTable_map::TYPE_ANY), mNameIndex(-1), mPos(pos) - { } - virtual ~Entry() { } - - enum type { - TYPE_UNKNOWN = 0, - TYPE_ITEM, - TYPE_BAG - }; - - String16 getName() const { return mName; } - type getType() const { return mType; } - - void setParent(const String16& parent) { mParent = parent; } - String16 getParent() const { return mParent; } - - status_t makeItABag(const SourcePos& sourcePos); - - status_t emptyBag(const SourcePos& sourcePos); - - status_t setItem(const SourcePos& pos, - const String16& value, - const Vector<StringPool::entry_style_span>* style = NULL, - int32_t format = ResTable_map::TYPE_ANY, - const bool overwrite = false); - - status_t addToBag(const SourcePos& pos, - const String16& key, const String16& value, - const Vector<StringPool::entry_style_span>* style = NULL, - bool replace=false, bool isId = false, - int32_t format = ResTable_map::TYPE_ANY); - - // Index of the entry's name string in the key pool. - int32_t getNameIndex() const { return mNameIndex; } - void setNameIndex(int32_t index) { mNameIndex = index; } - - const Item* getItem() const { return mType == TYPE_ITEM ? &mItem : NULL; } - const KeyedVector<String16, Item>& getBag() const { return mBag; } - - status_t generateAttributes(ResourceTable* table, - const String16& package); - - status_t assignResourceIds(ResourceTable* table, - const String16& package); - - status_t prepareFlatten(StringPool* strings, ResourceTable* table, - const String8* configTypeName, const ConfigDescription* config); - - status_t remapStringValue(StringPool* strings); - - ssize_t flatten(Bundle*, const sp<AaptFile>& data, bool isPublic); - - const SourcePos& getPos() const { return mPos; } - - private: - String16 mName; - String16 mParent; - type mType; - Item mItem; - int32_t mItemFormat; - KeyedVector<String16, Item> mBag; - int32_t mNameIndex; - uint32_t mParentId; - SourcePos mPos; - }; - - class ConfigList : public RefBase { - public: - ConfigList(const String16& name, const SourcePos& pos) - : mName(name), mPos(pos), mPublic(false), mEntryIndex(-1) { } - virtual ~ConfigList() { } - - String16 getName() const { return mName; } - const SourcePos& getPos() const { return mPos; } - - void appendComment(const String16& comment, bool onlyIfEmpty = false); - const String16& getComment() const { return mComment; } - - void appendTypeComment(const String16& comment); - const String16& getTypeComment() const { return mTypeComment; } - - // Index of this entry in its Type. - int32_t getEntryIndex() const { return mEntryIndex; } - void setEntryIndex(int32_t index) { mEntryIndex = index; } - - void setPublic(bool pub) { mPublic = pub; } - bool getPublic() const { return mPublic; } - void setPublicSourcePos(const SourcePos& pos) { mPublicSourcePos = pos; } - const SourcePos& getPublicSourcePos() { return mPublicSourcePos; } - - void addEntry(const ResTable_config& config, const sp<Entry>& entry) { - mEntries.add(config, entry); - } - - const DefaultKeyedVector<ConfigDescription, sp<Entry> >& getEntries() const { return mEntries; } - private: - const String16 mName; - const SourcePos mPos; - String16 mComment; - String16 mTypeComment; - bool mPublic; - SourcePos mPublicSourcePos; - int32_t mEntryIndex; - DefaultKeyedVector<ConfigDescription, sp<Entry> > mEntries; - }; - - class Public { - public: - Public() : sourcePos(), ident(0) { } - Public(const SourcePos& pos, - const String16& _comment, - uint32_t _ident) - : sourcePos(pos), - comment(_comment), ident(_ident) { } - Public(const Public& o) : sourcePos(o.sourcePos), - comment(o.comment), ident(o.ident) { } - ~Public() { } - - Public& operator=(const Public& o) { - sourcePos = o.sourcePos; - comment = o.comment; - ident = o.ident; - return *this; - } - - SourcePos sourcePos; - String16 comment; - uint32_t ident; - }; - - class Type : public RefBase { - public: - Type(const String16& name, const SourcePos& pos) - : mName(name), mFirstPublicSourcePos(NULL), mPublicIndex(-1), mIndex(-1), mPos(pos) - { } - virtual ~Type() { delete mFirstPublicSourcePos; } - - status_t addPublic(const SourcePos& pos, - const String16& name, - const uint32_t ident); - - void canAddEntry(const String16& name); - - String16 getName() const { return mName; } - sp<Entry> getEntry(const String16& entry, - const SourcePos& pos, - const ResTable_config* config = NULL, - bool doSetIndex = false, - bool overlay = false, - bool autoAddOverlay = false); - - const SourcePos& getFirstPublicSourcePos() const { return *mFirstPublicSourcePos; } - - int32_t getPublicIndex() const { return mPublicIndex; } - - int32_t getIndex() const { return mIndex; } - void setIndex(int32_t index) { mIndex = index; } - - status_t applyPublicEntryOrder(); - - const SortedVector<ConfigDescription>& getUniqueConfigs() const { return mUniqueConfigs; } - - const DefaultKeyedVector<String16, sp<ConfigList> >& getConfigs() const { return mConfigs; } - const Vector<sp<ConfigList> >& getOrderedConfigs() const { return mOrderedConfigs; } - - const SortedVector<String16>& getCanAddEntries() const { return mCanAddEntries; } - - const SourcePos& getPos() const { return mPos; } - private: - String16 mName; - SourcePos* mFirstPublicSourcePos; - DefaultKeyedVector<String16, Public> mPublic; - SortedVector<ConfigDescription> mUniqueConfigs; - DefaultKeyedVector<String16, sp<ConfigList> > mConfigs; - Vector<sp<ConfigList> > mOrderedConfigs; - SortedVector<String16> mCanAddEntries; - int32_t mPublicIndex; - int32_t mIndex; - SourcePos mPos; - }; - - class Package : public RefBase { - public: - Package(const String16& name, ssize_t includedId=-1); - virtual ~Package() { } - - String16 getName() const { return mName; } - sp<Type> getType(const String16& type, - const SourcePos& pos, - bool doSetIndex = false); - - ssize_t getAssignedId() const { return mIncludedId; } - - const ResStringPool& getTypeStrings() const { return mTypeStrings; } - uint32_t indexOfTypeString(const String16& s) const { return mTypeStringsMapping.valueFor(s); } - const sp<AaptFile> getTypeStringsData() const { return mTypeStringsData; } - status_t setTypeStrings(const sp<AaptFile>& data); - - const ResStringPool& getKeyStrings() const { return mKeyStrings; } - uint32_t indexOfKeyString(const String16& s) const { return mKeyStringsMapping.valueFor(s); } - const sp<AaptFile> getKeyStringsData() const { return mKeyStringsData; } - status_t setKeyStrings(const sp<AaptFile>& data); - - status_t applyPublicTypeOrder(); - - const DefaultKeyedVector<String16, sp<Type> >& getTypes() const { return mTypes; } - const Vector<sp<Type> >& getOrderedTypes() const { return mOrderedTypes; } - - private: - status_t setStrings(const sp<AaptFile>& data, - ResStringPool* strings, - DefaultKeyedVector<String16, uint32_t>* mappings); - - const String16 mName; - const ssize_t mIncludedId; - DefaultKeyedVector<String16, sp<Type> > mTypes; - Vector<sp<Type> > mOrderedTypes; - sp<AaptFile> mTypeStringsData; - sp<AaptFile> mKeyStringsData; - ResStringPool mTypeStrings; - ResStringPool mKeyStrings; - DefaultKeyedVector<String16, uint32_t> mTypeStringsMapping; - DefaultKeyedVector<String16, uint32_t> mKeyStringsMapping; - }; - -private: - void writePublicDefinitions(const String16& package, FILE* fp, bool pub); - sp<Package> getPackage(const String16& package); - sp<Type> getType(const String16& package, - const String16& type, - const SourcePos& pos, - bool doSetIndex = false); - sp<Entry> getEntry(const String16& package, - const String16& type, - const String16& name, - const SourcePos& pos, - bool overlay, - const ResTable_config* config = NULL, - bool doSetIndex = false); - sp<const Entry> getEntry(uint32_t resID, - const ResTable_config* config = NULL) const; - const Item* getItem(uint32_t resID, uint32_t attrID) const; - bool getItemValue(uint32_t resID, uint32_t attrID, - Res_value* outValue); - - - String16 mAssetsPackage; - sp<AaptAssets> mAssets; - DefaultKeyedVector<String16, sp<Package> > mPackages; - Vector<sp<Package> > mOrderedPackages; - uint32_t mNextPackageId; - bool mHaveAppPackage; - bool mIsAppPackage; - size_t mNumLocal; - SourcePos mCurrentXmlPos; - Bundle* mBundle; - - // key = string resource name, value = set of locales in which that name is defined - map<String16, set<String8> > mLocalizations; -}; - -#endif diff --git a/tools/aapt/SourcePos.cpp b/tools/aapt/SourcePos.cpp deleted file mode 100644 index e2a921c..0000000 --- a/tools/aapt/SourcePos.cpp +++ /dev/null @@ -1,171 +0,0 @@ -#include "SourcePos.h" - -#include <stdarg.h> -#include <vector> - -using namespace std; - - -// ErrorPos -// ============================================================================= -struct ErrorPos -{ - String8 file; - int line; - String8 error; - bool fatal; - - ErrorPos(); - ErrorPos(const ErrorPos& that); - ErrorPos(const String8& file, int line, const String8& error, bool fatal); - ~ErrorPos(); - bool operator<(const ErrorPos& rhs) const; - bool operator==(const ErrorPos& rhs) const; - ErrorPos& operator=(const ErrorPos& rhs); - - void print(FILE* to) const; -}; - -static vector<ErrorPos> g_errors; - -ErrorPos::ErrorPos() - :line(-1), fatal(false) -{ -} - -ErrorPos::ErrorPos(const ErrorPos& that) - :file(that.file), - line(that.line), - error(that.error), - fatal(that.fatal) -{ -} - -ErrorPos::ErrorPos(const String8& f, int l, const String8& e, bool fat) - :file(f), - line(l), - error(e), - fatal(fat) -{ -} - -ErrorPos::~ErrorPos() -{ -} - -bool -ErrorPos::operator<(const ErrorPos& rhs) const -{ - if (this->file < rhs.file) return true; - if (this->file == rhs.file) { - if (this->line < rhs.line) return true; - if (this->line == rhs.line) { - if (this->error < rhs.error) return true; - } - } - return false; -} - -bool -ErrorPos::operator==(const ErrorPos& rhs) const -{ - return this->file == rhs.file - && this->line == rhs.line - && this->error == rhs.error; -} - -ErrorPos& -ErrorPos::operator=(const ErrorPos& rhs) -{ - this->file = rhs.file; - this->line = rhs.line; - this->error = rhs.error; - return *this; -} - -void -ErrorPos::print(FILE* to) const -{ - const char* type = fatal ? "error:" : "warning:"; - - if (this->line >= 0) { - fprintf(to, "%s:%d: %s %s\n", this->file.string(), this->line, type, this->error.string()); - } else { - fprintf(to, "%s: %s %s\n", this->file.string(), type, this->error.string()); - } -} - -// SourcePos -// ============================================================================= -SourcePos::SourcePos(const String8& f, int l) - : file(f), line(l) -{ -} - -SourcePos::SourcePos(const SourcePos& that) - : file(that.file), line(that.line) -{ -} - -SourcePos::SourcePos() - : file("???", 0), line(-1) -{ -} - -SourcePos::~SourcePos() -{ -} - -int -SourcePos::error(const char* fmt, ...) const -{ - int retval=0; - char buf[1024]; - va_list ap; - va_start(ap, fmt); - retval = vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - char* p = buf + retval - 1; - while (p > buf && *p == '\n') { - *p = '\0'; - p--; - } - g_errors.push_back(ErrorPos(this->file, this->line, String8(buf), true)); - return retval; -} - -int -SourcePos::warning(const char* fmt, ...) const -{ - int retval=0; - char buf[1024]; - va_list ap; - va_start(ap, fmt); - retval = vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - char* p = buf + retval - 1; - while (p > buf && *p == '\n') { - *p = '\0'; - p--; - } - ErrorPos(this->file, this->line, String8(buf), false).print(stderr); - return retval; -} - -bool -SourcePos::hasErrors() -{ - return g_errors.size() > 0; -} - -void -SourcePos::printErrors(FILE* to) -{ - vector<ErrorPos>::const_iterator it; - for (it=g_errors.begin(); it!=g_errors.end(); it++) { - it->print(to); - } -} - - - diff --git a/tools/aapt/SourcePos.h b/tools/aapt/SourcePos.h deleted file mode 100644 index 33f72a9..0000000 --- a/tools/aapt/SourcePos.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef SOURCEPOS_H -#define SOURCEPOS_H - -#include <utils/String8.h> -#include <stdio.h> - -using namespace android; - -class SourcePos -{ -public: - String8 file; - int line; - - SourcePos(const String8& f, int l); - SourcePos(const SourcePos& that); - SourcePos(); - ~SourcePos(); - - int error(const char* fmt, ...) const; - int warning(const char* fmt, ...) const; - - static bool hasErrors(); - static void printErrors(FILE* to); -}; - - -#endif // SOURCEPOS_H diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp deleted file mode 100644 index 158b391..0000000 --- a/tools/aapt/StringPool.cpp +++ /dev/null @@ -1,574 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Build resource files from raw assets. -// - -#include "StringPool.h" -#include "ResourceTable.h" - -#include <utils/ByteOrder.h> -#include <utils/SortedVector.h> -#include "qsort_r_compat.h" - -#if HAVE_PRINTF_ZD -# define ZD "%zd" -# define ZD_TYPE ssize_t -#else -# define ZD "%ld" -# define ZD_TYPE long -#endif - -#define NOISY(x) //x - -void strcpy16_htod(uint16_t* dst, const uint16_t* src) -{ - while (*src) { - char16_t s = htods(*src); - *dst++ = s; - src++; - } - *dst = 0; -} - -void printStringPool(const ResStringPool* pool) -{ - SortedVector<const void*> uniqueStrings; - const size_t N = pool->size(); - for (size_t i=0; i<N; i++) { - size_t len; - if (pool->isUTF8()) { - uniqueStrings.add(pool->string8At(i, &len)); - } else { - uniqueStrings.add(pool->stringAt(i, &len)); - } - } - - printf("String pool of " ZD " unique %s %s strings, " ZD " entries and " - ZD " styles using " ZD " bytes:\n", - (ZD_TYPE)uniqueStrings.size(), pool->isUTF8() ? "UTF-8" : "UTF-16", - pool->isSorted() ? "sorted" : "non-sorted", - (ZD_TYPE)N, (ZD_TYPE)pool->styleCount(), (ZD_TYPE)pool->bytes()); - - const size_t NS = pool->size(); - for (size_t s=0; s<NS; s++) { - String8 str = pool->string8ObjectAt(s); - printf("String #" ZD ": %s\n", (ZD_TYPE) s, str.string()); - } -} - -String8 StringPool::entry::makeConfigsString() const { - String8 configStr(configTypeName); - if (configStr.size() > 0) configStr.append(" "); - if (configs.size() > 0) { - for (size_t j=0; j<configs.size(); j++) { - if (j > 0) configStr.append(", "); - configStr.append(configs[j].toString()); - } - } else { - configStr = "(none)"; - } - return configStr; -} - -int StringPool::entry::compare(const entry& o) const { - // Strings with styles go first, to reduce the size of the styles array. - // We don't care about the relative order of these strings. - if (hasStyles) { - return o.hasStyles ? 0 : -1; - } - if (o.hasStyles) { - return 1; - } - - // Sort unstyled strings by type, then by logical configuration. - int comp = configTypeName.compare(o.configTypeName); - if (comp != 0) { - return comp; - } - const size_t LHN = configs.size(); - const size_t RHN = o.configs.size(); - size_t i=0; - while (i < LHN && i < RHN) { - comp = configs[i].compareLogical(o.configs[i]); - if (comp != 0) { - return comp; - } - i++; - } - if (LHN < RHN) return -1; - else if (LHN > RHN) return 1; - return 0; -} - -StringPool::StringPool(bool utf8) : - mUTF8(utf8), mValues(-1) -{ -} - -ssize_t StringPool::add(const String16& value, const Vector<entry_style_span>& spans, - const String8* configTypeName, const ResTable_config* config) -{ - ssize_t res = add(value, false, configTypeName, config); - if (res >= 0) { - addStyleSpans(res, spans); - } - return res; -} - -ssize_t StringPool::add(const String16& value, - bool mergeDuplicates, const String8* configTypeName, const ResTable_config* config) -{ - ssize_t vidx = mValues.indexOfKey(value); - ssize_t pos = vidx >= 0 ? mValues.valueAt(vidx) : -1; - ssize_t eidx = pos >= 0 ? mEntryArray.itemAt(pos) : -1; - if (eidx < 0) { - eidx = mEntries.add(entry(value)); - if (eidx < 0) { - fprintf(stderr, "Failure adding string %s\n", String8(value).string()); - return eidx; - } - } - - if (configTypeName != NULL) { - entry& ent = mEntries.editItemAt(eidx); - NOISY(printf("*** adding config type name %s, was %s\n", - configTypeName->string(), ent.configTypeName.string())); - if (ent.configTypeName.size() <= 0) { - ent.configTypeName = *configTypeName; - } else if (ent.configTypeName != *configTypeName) { - ent.configTypeName = " "; - } - } - - if (config != NULL) { - // Add this to the set of configs associated with the string. - entry& ent = mEntries.editItemAt(eidx); - size_t addPos; - for (addPos=0; addPos<ent.configs.size(); addPos++) { - int cmp = ent.configs.itemAt(addPos).compareLogical(*config); - if (cmp >= 0) { - if (cmp > 0) { - NOISY(printf("*** inserting config: %s\n", config->toString().string())); - ent.configs.insertAt(*config, addPos); - } - break; - } - } - if (addPos >= ent.configs.size()) { - NOISY(printf("*** adding config: %s\n", config->toString().string())); - ent.configs.add(*config); - } - } - - const bool first = vidx < 0; - const bool styled = (pos >= 0 && (size_t)pos < mEntryStyleArray.size()) ? - mEntryStyleArray[pos].spans.size() : 0; - if (first || styled || !mergeDuplicates) { - pos = mEntryArray.add(eidx); - if (first) { - vidx = mValues.add(value, pos); - } - entry& ent = mEntries.editItemAt(eidx); - ent.indices.add(pos); - } - - NOISY(printf("Adding string %s to pool: pos=%d eidx=%d vidx=%d\n", - String8(value).string(), pos, eidx, vidx)); - - return pos; -} - -status_t StringPool::addStyleSpan(size_t idx, const String16& name, - uint32_t start, uint32_t end) -{ - entry_style_span span; - span.name = name; - span.span.firstChar = start; - span.span.lastChar = end; - return addStyleSpan(idx, span); -} - -status_t StringPool::addStyleSpans(size_t idx, const Vector<entry_style_span>& spans) -{ - const size_t N=spans.size(); - for (size_t i=0; i<N; i++) { - status_t err = addStyleSpan(idx, spans[i]); - if (err != NO_ERROR) { - return err; - } - } - return NO_ERROR; -} - -status_t StringPool::addStyleSpan(size_t idx, const entry_style_span& span) -{ - // Place blank entries in the span array up to this index. - while (mEntryStyleArray.size() <= idx) { - mEntryStyleArray.add(); - } - - entry_style& style = mEntryStyleArray.editItemAt(idx); - style.spans.add(span); - mEntries.editItemAt(mEntryArray[idx]).hasStyles = true; - return NO_ERROR; -} - -int StringPool::config_sort(void* state, const void* lhs, const void* rhs) -{ - StringPool* pool = (StringPool*)state; - const entry& lhe = pool->mEntries[pool->mEntryArray[*static_cast<const size_t*>(lhs)]]; - const entry& rhe = pool->mEntries[pool->mEntryArray[*static_cast<const size_t*>(rhs)]]; - return lhe.compare(rhe); -} - -void StringPool::sortByConfig() -{ - LOG_ALWAYS_FATAL_IF(mOriginalPosToNewPos.size() > 0, "Can't sort string pool after already sorted."); - - const size_t N = mEntryArray.size(); - - // This is a vector that starts out with a 1:1 mapping to entries - // in the array, which we will sort to come up with the desired order. - // At that point it maps from the new position in the array to the - // original position the entry appeared. - Vector<size_t> newPosToOriginalPos; - newPosToOriginalPos.setCapacity(N); - for (size_t i=0; i < N; i++) { - newPosToOriginalPos.add(i); - } - - // Sort the array. - NOISY(printf("SORTING STRINGS BY CONFIGURATION...\n")); - // Vector::sort uses insertion sort, which is very slow for this data set. - // Use quicksort instead because we don't need a stable sort here. - qsort_r_compat(newPosToOriginalPos.editArray(), N, sizeof(size_t), this, config_sort); - //newPosToOriginalPos.sort(config_sort, this); - NOISY(printf("DONE SORTING STRINGS BY CONFIGURATION.\n")); - - // Create the reverse mapping from the original position in the array - // to the new position where it appears in the sorted array. This is - // so that clients can re-map any positions they had previously stored. - mOriginalPosToNewPos = newPosToOriginalPos; - for (size_t i=0; i<N; i++) { - mOriginalPosToNewPos.editItemAt(newPosToOriginalPos[i]) = i; - } - -#if 0 - SortedVector<entry> entries; - - for (size_t i=0; i<N; i++) { - printf("#%d was %d: %s\n", i, newPosToOriginalPos[i], - mEntries[mEntryArray[newPosToOriginalPos[i]]].makeConfigsString().string()); - entries.add(mEntries[mEntryArray[i]]); - } - - for (size_t i=0; i<entries.size(); i++) { - printf("Sorted config #%d: %s\n", i, - entries[i].makeConfigsString().string()); - } -#endif - - // Now we rebuild the arrays. - Vector<entry> newEntries; - Vector<size_t> newEntryArray; - Vector<entry_style> newEntryStyleArray; - DefaultKeyedVector<size_t, size_t> origOffsetToNewOffset; - - for (size_t i=0; i<N; i++) { - // We are filling in new offset 'i'; oldI is where we can find it - // in the original data structure. - size_t oldI = newPosToOriginalPos[i]; - // This is the actual entry associated with the old offset. - const entry& oldEnt = mEntries[mEntryArray[oldI]]; - // This is the same entry the last time we added it to the - // new entry array, if any. - ssize_t newIndexOfOffset = origOffsetToNewOffset.indexOfKey(oldI); - size_t newOffset; - if (newIndexOfOffset < 0) { - // This is the first time we have seen the entry, so add - // it. - newOffset = newEntries.add(oldEnt); - newEntries.editItemAt(newOffset).indices.clear(); - } else { - // We have seen this entry before, use the existing one - // instead of adding it again. - newOffset = origOffsetToNewOffset.valueAt(newIndexOfOffset); - } - // Update the indices to include this new position. - newEntries.editItemAt(newOffset).indices.add(i); - // And add the offset of the entry to the new entry array. - newEntryArray.add(newOffset); - // Add any old style to the new style array. - if (mEntryStyleArray.size() > 0) { - if (oldI < mEntryStyleArray.size()) { - newEntryStyleArray.add(mEntryStyleArray[oldI]); - } else { - newEntryStyleArray.add(entry_style()); - } - } - } - - // Now trim any entries at the end of the new style array that are - // not needed. - for (ssize_t i=newEntryStyleArray.size()-1; i>=0; i--) { - const entry_style& style = newEntryStyleArray[i]; - if (style.spans.size() > 0) { - // That's it. - break; - } - // This one is not needed; remove. - newEntryStyleArray.removeAt(i); - } - - // All done, install the new data structures and upate mValues with - // the new positions. - mEntries = newEntries; - mEntryArray = newEntryArray; - mEntryStyleArray = newEntryStyleArray; - mValues.clear(); - for (size_t i=0; i<mEntries.size(); i++) { - const entry& ent = mEntries[i]; - mValues.add(ent.value, ent.indices[0]); - } - -#if 0 - printf("FINAL SORTED STRING CONFIGS:\n"); - for (size_t i=0; i<mEntries.size(); i++) { - const entry& ent = mEntries[i]; - printf("#" ZD " %s: %s\n", (ZD_TYPE)i, ent.makeConfigsString().string(), - String8(ent.value).string()); - } -#endif -} - -sp<AaptFile> StringPool::createStringBlock() -{ - sp<AaptFile> pool = new AaptFile(String8(), AaptGroupEntry(), - String8()); - status_t err = writeStringBlock(pool); - return err == NO_ERROR ? pool : NULL; -} - -#define ENCODE_LENGTH(str, chrsz, strSize) \ -{ \ - size_t maxMask = 1 << ((chrsz*8)-1); \ - size_t maxSize = maxMask-1; \ - if (strSize > maxSize) { \ - *str++ = maxMask | ((strSize>>(chrsz*8))&maxSize); \ - } \ - *str++ = strSize; \ -} - -status_t StringPool::writeStringBlock(const sp<AaptFile>& pool) -{ - // Allow appending. Sorry this is a little wacky. - if (pool->getSize() > 0) { - sp<AaptFile> block = createStringBlock(); - if (block == NULL) { - return UNKNOWN_ERROR; - } - ssize_t res = pool->writeData(block->getData(), block->getSize()); - return (res >= 0) ? (status_t)NO_ERROR : res; - } - - // First we need to add all style span names to the string pool. - // We do this now (instead of when the span is added) so that these - // will appear at the end of the pool, not disrupting the order - // our client placed their own strings in it. - - const size_t STYLES = mEntryStyleArray.size(); - size_t i; - - for (i=0; i<STYLES; i++) { - entry_style& style = mEntryStyleArray.editItemAt(i); - const size_t N = style.spans.size(); - for (size_t i=0; i<N; i++) { - entry_style_span& span = style.spans.editItemAt(i); - ssize_t idx = add(span.name, true); - if (idx < 0) { - fprintf(stderr, "Error adding span for style tag '%s'\n", - String8(span.name).string()); - return idx; - } - span.span.name.index = (uint32_t)idx; - } - } - - const size_t ENTRIES = mEntryArray.size(); - - // Now build the pool of unique strings. - - const size_t STRINGS = mEntries.size(); - const size_t preSize = sizeof(ResStringPool_header) - + (sizeof(uint32_t)*ENTRIES) - + (sizeof(uint32_t)*STYLES); - if (pool->editData(preSize) == NULL) { - fprintf(stderr, "ERROR: Out of memory for string pool\n"); - return NO_MEMORY; - } - - const size_t charSize = mUTF8 ? sizeof(uint8_t) : sizeof(char16_t); - - size_t strPos = 0; - for (i=0; i<STRINGS; i++) { - entry& ent = mEntries.editItemAt(i); - const size_t strSize = (ent.value.size()); - const size_t lenSize = strSize > (size_t)(1<<((charSize*8)-1))-1 ? - charSize*2 : charSize; - - String8 encStr; - if (mUTF8) { - encStr = String8(ent.value); - } - - const size_t encSize = mUTF8 ? encStr.size() : 0; - const size_t encLenSize = mUTF8 ? - (encSize > (size_t)(1<<((charSize*8)-1))-1 ? - charSize*2 : charSize) : 0; - - ent.offset = strPos; - - const size_t totalSize = lenSize + encLenSize + - ((mUTF8 ? encSize : strSize)+1)*charSize; - - void* dat = (void*)pool->editData(preSize + strPos + totalSize); - if (dat == NULL) { - fprintf(stderr, "ERROR: Out of memory for string pool\n"); - return NO_MEMORY; - } - dat = (uint8_t*)dat + preSize + strPos; - if (mUTF8) { - uint8_t* strings = (uint8_t*)dat; - - ENCODE_LENGTH(strings, sizeof(uint8_t), strSize) - - ENCODE_LENGTH(strings, sizeof(uint8_t), encSize) - - strncpy((char*)strings, encStr, encSize+1); - } else { - uint16_t* strings = (uint16_t*)dat; - - ENCODE_LENGTH(strings, sizeof(uint16_t), strSize) - - strcpy16_htod(strings, ent.value); - } - - strPos += totalSize; - } - - // Pad ending string position up to a uint32_t boundary. - - if (strPos&0x3) { - size_t padPos = ((strPos+3)&~0x3); - uint8_t* dat = (uint8_t*)pool->editData(preSize + padPos); - if (dat == NULL) { - fprintf(stderr, "ERROR: Out of memory padding string pool\n"); - return NO_MEMORY; - } - memset(dat+preSize+strPos, 0, padPos-strPos); - strPos = padPos; - } - - // Build the pool of style spans. - - size_t styPos = strPos; - for (i=0; i<STYLES; i++) { - entry_style& ent = mEntryStyleArray.editItemAt(i); - const size_t N = ent.spans.size(); - const size_t totalSize = (N*sizeof(ResStringPool_span)) - + sizeof(ResStringPool_ref); - - ent.offset = styPos-strPos; - uint8_t* dat = (uint8_t*)pool->editData(preSize + styPos + totalSize); - if (dat == NULL) { - fprintf(stderr, "ERROR: Out of memory for string styles\n"); - return NO_MEMORY; - } - ResStringPool_span* span = (ResStringPool_span*)(dat+preSize+styPos); - for (size_t i=0; i<N; i++) { - span->name.index = htodl(ent.spans[i].span.name.index); - span->firstChar = htodl(ent.spans[i].span.firstChar); - span->lastChar = htodl(ent.spans[i].span.lastChar); - span++; - } - span->name.index = htodl(ResStringPool_span::END); - - styPos += totalSize; - } - - if (STYLES > 0) { - // Add full terminator at the end (when reading we validate that - // the end of the pool is fully terminated to simplify error - // checking). - size_t extra = sizeof(ResStringPool_span)-sizeof(ResStringPool_ref); - uint8_t* dat = (uint8_t*)pool->editData(preSize + styPos + extra); - if (dat == NULL) { - fprintf(stderr, "ERROR: Out of memory for string styles\n"); - return NO_MEMORY; - } - uint32_t* p = (uint32_t*)(dat+preSize+styPos); - while (extra > 0) { - *p++ = htodl(ResStringPool_span::END); - extra -= sizeof(uint32_t); - } - styPos += extra; - } - - // Write header. - - ResStringPool_header* header = - (ResStringPool_header*)pool->padData(sizeof(uint32_t)); - if (header == NULL) { - fprintf(stderr, "ERROR: Out of memory for string pool\n"); - return NO_MEMORY; - } - memset(header, 0, sizeof(*header)); - header->header.type = htods(RES_STRING_POOL_TYPE); - header->header.headerSize = htods(sizeof(*header)); - header->header.size = htodl(pool->getSize()); - header->stringCount = htodl(ENTRIES); - header->styleCount = htodl(STYLES); - if (mUTF8) { - header->flags |= htodl(ResStringPool_header::UTF8_FLAG); - } - header->stringsStart = htodl(preSize); - header->stylesStart = htodl(STYLES > 0 ? (preSize+strPos) : 0); - - // Write string index array. - - uint32_t* index = (uint32_t*)(header+1); - for (i=0; i<ENTRIES; i++) { - entry& ent = mEntries.editItemAt(mEntryArray[i]); - *index++ = htodl(ent.offset); - NOISY(printf("Writing entry #%d: \"%s\" ent=%d off=%d\n", i, - String8(ent.value).string(), - mEntryArray[i], ent.offset)); - } - - // Write style index array. - - for (i=0; i<STYLES; i++) { - *index++ = htodl(mEntryStyleArray[i].offset); - } - - return NO_ERROR; -} - -ssize_t StringPool::offsetForString(const String16& val) const -{ - const Vector<size_t>* indices = offsetsForString(val); - ssize_t res = indices != NULL && indices->size() > 0 ? indices->itemAt(0) : -1; - NOISY(printf("Offset for string %s: %d (%s)\n", String8(val).string(), res, - res >= 0 ? String8(mEntries[mEntryArray[res]].value).string() : String8())); - return res; -} - -const Vector<size_t>* StringPool::offsetsForString(const String16& val) const -{ - ssize_t pos = mValues.valueFor(val); - if (pos < 0) { - return NULL; - } - return &mEntries[mEntryArray[pos]].indices; -} diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h deleted file mode 100644 index 1b3abfd..0000000 --- a/tools/aapt/StringPool.h +++ /dev/null @@ -1,183 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Build resource files from raw assets. -// - -#ifndef STRING_POOL_H -#define STRING_POOL_H - -#include "Main.h" -#include "AaptAssets.h" - -#include <androidfw/ResourceTypes.h> -#include <utils/String16.h> -#include <utils/TypeHelpers.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <ctype.h> -#include <errno.h> - -#include <libexpat/expat.h> - -using namespace android; - -#define PRINT_STRING_METRICS 0 - -void strcpy16_htod(uint16_t* dst, const uint16_t* src); - -void printStringPool(const ResStringPool* pool); - -/** - * The StringPool class is used as an intermediate representation for - * generating the string pool resource data structure that can be parsed with - * ResStringPool in include/utils/ResourceTypes.h. - */ -class StringPool -{ -public: - struct entry { - entry() : offset(0) { } - entry(const String16& _value) : value(_value), offset(0), hasStyles(false) { } - entry(const entry& o) : value(o.value), offset(o.offset), - hasStyles(o.hasStyles), indices(o.indices), - configTypeName(o.configTypeName), configs(o.configs) { } - - String16 value; - size_t offset; - bool hasStyles; - Vector<size_t> indices; - String8 configTypeName; - Vector<ResTable_config> configs; - - String8 makeConfigsString() const; - - int compare(const entry& o) const; - - inline bool operator<(const entry& o) const { return compare(o) < 0; } - inline bool operator<=(const entry& o) const { return compare(o) <= 0; } - inline bool operator==(const entry& o) const { return compare(o) == 0; } - inline bool operator!=(const entry& o) const { return compare(o) != 0; } - inline bool operator>=(const entry& o) const { return compare(o) >= 0; } - inline bool operator>(const entry& o) const { return compare(o) > 0; } - }; - - struct entry_style_span { - String16 name; - ResStringPool_span span; - }; - - struct entry_style { - entry_style() : offset(0) { } - - entry_style(const entry_style& o) : offset(o.offset), spans(o.spans) { } - - size_t offset; - Vector<entry_style_span> spans; - }; - - /** - * If 'utf8' is true, strings will be encoded with UTF-8 instead of - * left in Java's native UTF-16. - */ - explicit StringPool(bool utf8 = false); - - /** - * Add a new string to the pool. If mergeDuplicates is true, thenif - * the string already exists the existing entry for it will be used; - * otherwise, or if the value doesn't already exist, a new entry is - * created. - * - * Returns the index in the entry array of the new string entry. - */ - ssize_t add(const String16& value, bool mergeDuplicates = false, - const String8* configTypeName = NULL, const ResTable_config* config = NULL); - - ssize_t add(const String16& value, const Vector<entry_style_span>& spans, - const String8* configTypeName = NULL, const ResTable_config* config = NULL); - - status_t addStyleSpan(size_t idx, const String16& name, - uint32_t start, uint32_t end); - status_t addStyleSpans(size_t idx, const Vector<entry_style_span>& spans); - status_t addStyleSpan(size_t idx, const entry_style_span& span); - - // Sort the contents of the string block by the configuration associated - // with each item. After doing this you can use mapOriginalPosToNewPos() - // to find out the new position given the position originally returned by - // add(). - void sortByConfig(); - - // For use after sortByConfig() to map from the original position of - // a string to its new sorted position. - size_t mapOriginalPosToNewPos(size_t originalPos) const { - return mOriginalPosToNewPos.itemAt(originalPos); - } - - sp<AaptFile> createStringBlock(); - - status_t writeStringBlock(const sp<AaptFile>& pool); - - /** - * Find out an offset in the pool for a particular string. If the string - * pool is sorted, this can not be called until after createStringBlock() - * or writeStringBlock() has been called - * (which determines the offsets). In the case of a string that appears - * multiple times in the pool, the first offset will be returned. Returns - * -1 if the string does not exist. - */ - ssize_t offsetForString(const String16& val) const; - - /** - * Find all of the offsets in the pool for a particular string. If the - * string pool is sorted, this can not be called until after - * createStringBlock() or writeStringBlock() has been called - * (which determines the offsets). Returns NULL if the string does not exist. - */ - const Vector<size_t>* offsetsForString(const String16& val) const; - -private: - static int config_sort(void* state, const void* lhs, const void* rhs); - - const bool mUTF8; - - // The following data structures represent the actual structures - // that will be generated for the final string pool. - - // Raw array of unique strings, in some arbitrary order. This is the - // actual strings that appear in the final string pool, in the order - // that they will be written. - Vector<entry> mEntries; - // Array of indices into mEntries, in the order they were - // added to the pool. This can be different than mEntries - // if the same string was added multiple times (it will appear - // once in mEntries, with multiple occurrences in this array). - // This is the lookup array that will be written for finding - // the string for each offset/position in the string pool. - Vector<size_t> mEntryArray; - // Optional style span information associated with each index of - // mEntryArray. - Vector<entry_style> mEntryStyleArray; - - // The following data structures are used for book-keeping as the - // string pool is constructed. - - // Unique set of all the strings added to the pool, mapped to - // the first index of mEntryArray where the value was added. - DefaultKeyedVector<String16, ssize_t> mValues; - // This array maps from the original position a string was placed at - // in mEntryArray to its new position after being sorted with sortByConfig(). - Vector<size_t> mOriginalPosToNewPos; -}; - -// The entry types are trivially movable because all fields they contain, including -// the vectors and strings, are trivially movable. -namespace android { - ANDROID_TRIVIAL_MOVE_TRAIT(StringPool::entry); - ANDROID_TRIVIAL_MOVE_TRAIT(StringPool::entry_style_span); - ANDROID_TRIVIAL_MOVE_TRAIT(StringPool::entry_style); -}; - -#endif - diff --git a/tools/aapt/WorkQueue.cpp b/tools/aapt/WorkQueue.cpp deleted file mode 100644 index 24a962f..0000000 --- a/tools/aapt/WorkQueue.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// #define LOG_NDEBUG 0 -#define LOG_TAG "WorkQueue" - -#include <utils/Log.h> -#include "WorkQueue.h" - -namespace android { - -// --- WorkQueue --- - -WorkQueue::WorkQueue(size_t maxThreads, bool canCallJava) : - mMaxThreads(maxThreads), mCanCallJava(canCallJava), - mCanceled(false), mFinished(false), mIdleThreads(0) { -} - -WorkQueue::~WorkQueue() { - if (!cancel()) { - finish(); - } -} - -status_t WorkQueue::schedule(WorkUnit* workUnit, size_t backlog) { - AutoMutex _l(mLock); - - if (mFinished || mCanceled) { - return INVALID_OPERATION; - } - - if (mWorkThreads.size() < mMaxThreads - && mIdleThreads < mWorkUnits.size() + 1) { - sp<WorkThread> workThread = new WorkThread(this, mCanCallJava); - status_t status = workThread->run("WorkQueue::WorkThread"); - if (status) { - return status; - } - mWorkThreads.add(workThread); - mIdleThreads += 1; - } else if (backlog) { - while (mWorkUnits.size() >= mMaxThreads * backlog) { - mWorkDequeuedCondition.wait(mLock); - if (mFinished || mCanceled) { - return INVALID_OPERATION; - } - } - } - - mWorkUnits.add(workUnit); - mWorkChangedCondition.broadcast(); - return OK; -} - -status_t WorkQueue::cancel() { - AutoMutex _l(mLock); - - return cancelLocked(); -} - -status_t WorkQueue::cancelLocked() { - if (mFinished) { - return INVALID_OPERATION; - } - - if (!mCanceled) { - mCanceled = true; - - size_t count = mWorkUnits.size(); - for (size_t i = 0; i < count; i++) { - delete mWorkUnits.itemAt(i); - } - mWorkUnits.clear(); - mWorkChangedCondition.broadcast(); - mWorkDequeuedCondition.broadcast(); - } - return OK; -} - -status_t WorkQueue::finish() { - { // acquire lock - AutoMutex _l(mLock); - - if (mFinished) { - return INVALID_OPERATION; - } - - mFinished = true; - mWorkChangedCondition.broadcast(); - } // release lock - - // It is not possible for the list of work threads to change once the mFinished - // flag has been set, so we can access mWorkThreads outside of the lock here. - size_t count = mWorkThreads.size(); - for (size_t i = 0; i < count; i++) { - mWorkThreads.itemAt(i)->join(); - } - mWorkThreads.clear(); - return OK; -} - -bool WorkQueue::threadLoop() { - WorkUnit* workUnit; - { // acquire lock - AutoMutex _l(mLock); - - for (;;) { - if (mCanceled) { - return false; - } - - if (!mWorkUnits.isEmpty()) { - workUnit = mWorkUnits.itemAt(0); - mWorkUnits.removeAt(0); - mIdleThreads -= 1; - mWorkDequeuedCondition.broadcast(); - break; - } - - if (mFinished) { - return false; - } - - mWorkChangedCondition.wait(mLock); - } - } // release lock - - bool shouldContinue = workUnit->run(); - delete workUnit; - - { // acquire lock - AutoMutex _l(mLock); - - mIdleThreads += 1; - - if (!shouldContinue) { - cancelLocked(); - return false; - } - } // release lock - - return true; -} - -// --- WorkQueue::WorkThread --- - -WorkQueue::WorkThread::WorkThread(WorkQueue* workQueue, bool canCallJava) : - Thread(canCallJava), mWorkQueue(workQueue) { -} - -WorkQueue::WorkThread::~WorkThread() { -} - -bool WorkQueue::WorkThread::threadLoop() { - return mWorkQueue->threadLoop(); -} - -}; // namespace android diff --git a/tools/aapt/WorkQueue.h b/tools/aapt/WorkQueue.h deleted file mode 100644 index d38f05d..0000000 --- a/tools/aapt/WorkQueue.h +++ /dev/null @@ -1,119 +0,0 @@ -/*] - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AAPT_WORK_QUEUE_H -#define AAPT_WORK_QUEUE_H - -#include <utils/Errors.h> -#include <utils/Vector.h> -#include <utils/threads.h> - -namespace android { - -/* - * A threaded work queue. - * - * This class is designed to make it easy to run a bunch of isolated work - * units in parallel, using up to the specified number of threads. - * To use it, write a loop to post work units to the work queue, then synchronize - * on the queue at the end. - */ -class WorkQueue { -public: - class WorkUnit { - public: - WorkUnit() { } - virtual ~WorkUnit() { } - - /* - * Runs the work unit. - * If the result is 'true' then the work queue continues scheduling work as usual. - * If the result is 'false' then the work queue is canceled. - */ - virtual bool run() = 0; - }; - - /* Creates a work queue with the specified maximum number of work threads. */ - WorkQueue(size_t maxThreads, bool canCallJava = true); - - /* Destroys the work queue. - * Cancels pending work and waits for all remaining threads to complete. - */ - ~WorkQueue(); - - /* Posts a work unit to run later. - * If the work queue has been canceled or is already finished, returns INVALID_OPERATION - * and does not take ownership of the work unit (caller must destroy it itself). - * Otherwise, returns OK and takes ownership of the work unit (the work queue will - * destroy it automatically). - * - * For flow control, this method blocks when the size of the pending work queue is more - * 'backlog' times the number of threads. This condition reduces the rate of entry into - * the pending work queue and prevents it from growing much more rapidly than the - * work threads can actually handle. - * - * If 'backlog' is 0, then no throttle is applied. - */ - status_t schedule(WorkUnit* workUnit, size_t backlog = 2); - - /* Cancels all pending work. - * If the work queue is already finished, returns INVALID_OPERATION. - * If the work queue is already canceled, returns OK and does nothing else. - * Otherwise, returns OK, discards all pending work units and prevents additional - * work units from being scheduled. - * - * Call finish() after cancel() to wait for all remaining work to complete. - */ - status_t cancel(); - - /* Waits for all work to complete. - * If the work queue is already finished, returns INVALID_OPERATION. - * Otherwise, waits for all work to complete and returns OK. - */ - status_t finish(); - -private: - class WorkThread : public Thread { - public: - WorkThread(WorkQueue* workQueue, bool canCallJava); - virtual ~WorkThread(); - - private: - virtual bool threadLoop(); - - WorkQueue* const mWorkQueue; - }; - - status_t cancelLocked(); - bool threadLoop(); // called from each work thread - - const size_t mMaxThreads; - const bool mCanCallJava; - - Mutex mLock; - Condition mWorkChangedCondition; - Condition mWorkDequeuedCondition; - - bool mCanceled; - bool mFinished; - size_t mIdleThreads; - Vector<sp<WorkThread> > mWorkThreads; - Vector<WorkUnit*> mWorkUnits; -}; - -}; // namespace android - -#endif // AAPT_WORK_QUEUE_H diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp deleted file mode 100644 index a663ad5..0000000 --- a/tools/aapt/XMLNode.cpp +++ /dev/null @@ -1,1510 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Build resource files from raw assets. -// - -#include "XMLNode.h" -#include "ResourceTable.h" -#include "pseudolocalize.h" - -#include <utils/ByteOrder.h> -#include <errno.h> -#include <string.h> - -#ifndef HAVE_MS_C_RUNTIME -#define O_BINARY 0 -#endif - -#define NOISY(x) //x -#define NOISY_PARSE(x) //x - -const char* const RESOURCES_ROOT_NAMESPACE = "http://schemas.android.com/apk/res/"; -const char* const RESOURCES_ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android"; -const char* const RESOURCES_AUTO_PACKAGE_NAMESPACE = "http://schemas.android.com/apk/res-auto"; -const char* const RESOURCES_ROOT_PRV_NAMESPACE = "http://schemas.android.com/apk/prv/res/"; - -const char* const XLIFF_XMLNS = "urn:oasis:names:tc:xliff:document:1.2"; -const char* const ALLOWED_XLIFF_ELEMENTS[] = { - "bpt", - "ept", - "it", - "ph", - "g", - "bx", - "ex", - "x" - }; - -bool isWhitespace(const char16_t* str) -{ - while (*str != 0 && *str < 128 && isspace(*str)) { - str++; - } - return *str == 0; -} - -static const String16 RESOURCES_PREFIX(RESOURCES_ROOT_NAMESPACE); -static const String16 RESOURCES_PREFIX_AUTO_PACKAGE(RESOURCES_AUTO_PACKAGE_NAMESPACE); -static const String16 RESOURCES_PRV_PREFIX(RESOURCES_ROOT_PRV_NAMESPACE); -static const String16 RESOURCES_TOOLS_NAMESPACE("http://schemas.android.com/tools"); - -String16 getNamespaceResourcePackage(String16 appPackage, String16 namespaceUri, bool* outIsPublic) -{ - //printf("%s starts with %s?\n", String8(namespaceUri).string(), - // String8(RESOURCES_PREFIX).string()); - size_t prefixSize; - bool isPublic = true; - if(namespaceUri.startsWith(RESOURCES_PREFIX_AUTO_PACKAGE)) { - NOISY(printf("Using default application package: %s -> %s\n", String8(namespaceUri).string(), String8(appPackage).string())); - isPublic = true; - return appPackage; - } else if (namespaceUri.startsWith(RESOURCES_PREFIX)) { - prefixSize = RESOURCES_PREFIX.size(); - } else if (namespaceUri.startsWith(RESOURCES_PRV_PREFIX)) { - isPublic = false; - prefixSize = RESOURCES_PRV_PREFIX.size(); - } else { - if (outIsPublic) *outIsPublic = isPublic; // = true - return String16(); - } - - //printf("YES!\n"); - //printf("namespace: %s\n", String8(String16(namespaceUri, namespaceUri.size()-prefixSize, prefixSize)).string()); - if (outIsPublic) *outIsPublic = isPublic; - return String16(namespaceUri, namespaceUri.size()-prefixSize, prefixSize); -} - -status_t hasSubstitutionErrors(const char* fileName, - ResXMLTree* inXml, - String16 str16) -{ - const char16_t* str = str16.string(); - const char16_t* p = str; - const char16_t* end = str + str16.size(); - - bool nonpositional = false; - int argCount = 0; - - while (p < end) { - /* - * Look for the start of a Java-style substitution sequence. - */ - if (*p == '%' && p + 1 < end) { - p++; - - // A literal percent sign represented by %% - if (*p == '%') { - p++; - continue; - } - - argCount++; - - if (*p >= '0' && *p <= '9') { - do { - p++; - } while (*p >= '0' && *p <= '9'); - if (*p != '$') { - // This must be a size specification instead of position. - nonpositional = true; - } - } else if (*p == '<') { - // Reusing last argument; bad idea since it can be re-arranged. - nonpositional = true; - p++; - - // Optionally '$' can be specified at the end. - if (p < end && *p == '$') { - p++; - } - } else { - nonpositional = true; - } - - // Ignore flags and widths - while (p < end && (*p == '-' || - *p == '#' || - *p == '+' || - *p == ' ' || - *p == ',' || - *p == '(' || - (*p >= '0' && *p <= '9'))) { - p++; - } - - /* - * This is a shortcut to detect strings that are going to Time.format() - * instead of String.format() - * - * Comparison of String.format() and Time.format() args: - * - * String: ABC E GH ST X abcdefgh nost x - * Time: DEFGHKMS W Za d hkm s w yz - * - * Therefore we know it's definitely Time if we have: - * DFKMWZkmwyz - */ - if (p < end) { - switch (*p) { - case 'D': - case 'F': - case 'K': - case 'M': - case 'W': - case 'Z': - case 'k': - case 'm': - case 'w': - case 'y': - case 'z': - return NO_ERROR; - } - } - } - - p++; - } - - /* - * If we have more than one substitution in this string and any of them - * are not in positional form, give the user an error. - */ - if (argCount > 1 && nonpositional) { - SourcePos(String8(fileName), inXml->getLineNumber()).error( - "Multiple substitutions specified in non-positional format; " - "did you mean to add the formatted=\"false\" attribute?\n"); - return NOT_ENOUGH_DATA; - } - - return NO_ERROR; -} - -status_t parseStyledString(Bundle* bundle, - const char* fileName, - ResXMLTree* inXml, - const String16& endTag, - String16* outString, - Vector<StringPool::entry_style_span>* outSpans, - bool isFormatted, - bool pseudolocalize) -{ - Vector<StringPool::entry_style_span> spanStack; - String16 curString; - String16 rawString; - const char* errorMsg; - int xliffDepth = 0; - bool firstTime = true; - - size_t len; - ResXMLTree::event_code_t code; - while ((code=inXml->next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - - if (code == ResXMLTree::TEXT) { - String16 text(inXml->getText(&len)); - if (firstTime && text.size() > 0) { - firstTime = false; - if (text.string()[0] == '@') { - // If this is a resource reference, don't do the pseudoloc. - pseudolocalize = false; - } - } - if (xliffDepth == 0 && pseudolocalize) { - std::string orig(String8(text).string()); - std::string pseudo = pseudolocalize_string(orig); - curString.append(String16(String8(pseudo.c_str()))); - } else { - if (isFormatted && hasSubstitutionErrors(fileName, inXml, text) != NO_ERROR) { - return UNKNOWN_ERROR; - } else { - curString.append(text); - } - } - } else if (code == ResXMLTree::START_TAG) { - const String16 element16(inXml->getElementName(&len)); - const String8 element8(element16); - - size_t nslen; - const uint16_t* ns = inXml->getElementNamespace(&nslen); - if (ns == NULL) { - ns = (const uint16_t*)"\0\0"; - nslen = 0; - } - const String8 nspace(String16(ns, nslen)); - if (nspace == XLIFF_XMLNS) { - const int N = sizeof(ALLOWED_XLIFF_ELEMENTS)/sizeof(ALLOWED_XLIFF_ELEMENTS[0]); - for (int i=0; i<N; i++) { - if (element8 == ALLOWED_XLIFF_ELEMENTS[i]) { - xliffDepth++; - // in this case, treat it like it was just text, in other words, do nothing - // here and silently drop this element - goto moveon; - } - } - { - SourcePos(String8(fileName), inXml->getLineNumber()).error( - "Found unsupported XLIFF tag <%s>\n", - element8.string()); - return UNKNOWN_ERROR; - } -moveon: - continue; - } - - if (outSpans == NULL) { - SourcePos(String8(fileName), inXml->getLineNumber()).error( - "Found style tag <%s> where styles are not allowed\n", element8.string()); - return UNKNOWN_ERROR; - } - - if (!ResTable::collectString(outString, curString.string(), - curString.size(), false, &errorMsg, true)) { - SourcePos(String8(fileName), inXml->getLineNumber()).error("%s (in %s)\n", - errorMsg, String8(curString).string()); - return UNKNOWN_ERROR; - } - rawString.append(curString); - curString = String16(); - - StringPool::entry_style_span span; - span.name = element16; - for (size_t ai=0; ai<inXml->getAttributeCount(); ai++) { - span.name.append(String16(";")); - const char16_t* str = inXml->getAttributeName(ai, &len); - span.name.append(str, len); - span.name.append(String16("=")); - str = inXml->getAttributeStringValue(ai, &len); - span.name.append(str, len); - } - //printf("Span: %s\n", String8(span.name).string()); - span.span.firstChar = span.span.lastChar = outString->size(); - spanStack.push(span); - - } else if (code == ResXMLTree::END_TAG) { - size_t nslen; - const uint16_t* ns = inXml->getElementNamespace(&nslen); - if (ns == NULL) { - ns = (const uint16_t*)"\0\0"; - nslen = 0; - } - const String8 nspace(String16(ns, nslen)); - if (nspace == XLIFF_XMLNS) { - xliffDepth--; - continue; - } - if (!ResTable::collectString(outString, curString.string(), - curString.size(), false, &errorMsg, true)) { - SourcePos(String8(fileName), inXml->getLineNumber()).error("%s (in %s)\n", - errorMsg, String8(curString).string()); - return UNKNOWN_ERROR; - } - rawString.append(curString); - curString = String16(); - - if (spanStack.size() == 0) { - if (strcmp16(inXml->getElementName(&len), endTag.string()) != 0) { - SourcePos(String8(fileName), inXml->getLineNumber()).error( - "Found tag %s where <%s> close is expected\n", - String8(inXml->getElementName(&len)).string(), - String8(endTag).string()); - return UNKNOWN_ERROR; - } - break; - } - StringPool::entry_style_span span = spanStack.top(); - String16 spanTag; - ssize_t semi = span.name.findFirst(';'); - if (semi >= 0) { - spanTag.setTo(span.name.string(), semi); - } else { - spanTag.setTo(span.name); - } - if (strcmp16(inXml->getElementName(&len), spanTag.string()) != 0) { - SourcePos(String8(fileName), inXml->getLineNumber()).error( - "Found close tag %s where close tag %s is expected\n", - String8(inXml->getElementName(&len)).string(), - String8(spanTag).string()); - return UNKNOWN_ERROR; - } - bool empty = true; - if (outString->size() > 0) { - span.span.lastChar = outString->size()-1; - if (span.span.lastChar >= span.span.firstChar) { - empty = false; - outSpans->add(span); - } - } - spanStack.pop(); - - /* - * This warning seems to be just an irritation to most people, - * since it is typically introduced by translators who then never - * see the warning. - */ - if (0 && empty) { - fprintf(stderr, "%s:%d: warning: empty '%s' span found in text '%s'\n", - fileName, inXml->getLineNumber(), - String8(spanTag).string(), String8(*outString).string()); - - } - } else if (code == ResXMLTree::START_NAMESPACE) { - // nothing - } - } - - if (code == ResXMLTree::BAD_DOCUMENT) { - SourcePos(String8(fileName), inXml->getLineNumber()).error( - "Error parsing XML\n"); - } - - if (outSpans != NULL && outSpans->size() > 0) { - if (curString.size() > 0) { - if (!ResTable::collectString(outString, curString.string(), - curString.size(), false, &errorMsg, true)) { - SourcePos(String8(fileName), inXml->getLineNumber()).error( - "%s (in %s)\n", - errorMsg, String8(curString).string()); - return UNKNOWN_ERROR; - } - } - } else { - // There is no style information, so string processing will happen - // later as part of the overall type conversion. Return to the - // client the raw unprocessed text. - rawString.append(curString); - outString->setTo(rawString); - } - - return NO_ERROR; -} - -struct namespace_entry { - String8 prefix; - String8 uri; -}; - -static String8 make_prefix(int depth) -{ - String8 prefix; - int i; - for (i=0; i<depth; i++) { - prefix.append(" "); - } - return prefix; -} - -static String8 build_namespace(const Vector<namespace_entry>& namespaces, - const uint16_t* ns) -{ - String8 str; - if (ns != NULL) { - str = String8(ns); - const size_t N = namespaces.size(); - for (size_t i=0; i<N; i++) { - const namespace_entry& ne = namespaces.itemAt(i); - if (ne.uri == str) { - str = ne.prefix; - break; - } - } - str.append(":"); - } - return str; -} - -void printXMLBlock(ResXMLTree* block) -{ - block->restart(); - - Vector<namespace_entry> namespaces; - - ResXMLTree::event_code_t code; - int depth = 0; - while ((code=block->next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - String8 prefix = make_prefix(depth); - int i; - if (code == ResXMLTree::START_TAG) { - size_t len; - const uint16_t* ns16 = block->getElementNamespace(&len); - String8 elemNs = build_namespace(namespaces, ns16); - const uint16_t* com16 = block->getComment(&len); - if (com16) { - printf("%s <!-- %s -->\n", prefix.string(), String8(com16).string()); - } - printf("%sE: %s%s (line=%d)\n", prefix.string(), elemNs.string(), - String8(block->getElementName(&len)).string(), - block->getLineNumber()); - int N = block->getAttributeCount(); - depth++; - prefix = make_prefix(depth); - for (i=0; i<N; i++) { - uint32_t res = block->getAttributeNameResID(i); - ns16 = block->getAttributeNamespace(i, &len); - String8 ns = build_namespace(namespaces, ns16); - String8 name(block->getAttributeName(i, &len)); - printf("%sA: ", prefix.string()); - if (res) { - printf("%s%s(0x%08x)", ns.string(), name.string(), res); - } else { - printf("%s%s", ns.string(), name.string()); - } - Res_value value; - block->getAttributeValue(i, &value); - if (value.dataType == Res_value::TYPE_NULL) { - printf("=(null)"); - } else if (value.dataType == Res_value::TYPE_REFERENCE) { - printf("=@0x%x", (int)value.data); - } else if (value.dataType == Res_value::TYPE_ATTRIBUTE) { - printf("=?0x%x", (int)value.data); - } else if (value.dataType == Res_value::TYPE_STRING) { - printf("=\"%s\"", - ResTable::normalizeForOutput(String8(block->getAttributeStringValue(i, - &len)).string()).string()); - } else { - printf("=(type 0x%x)0x%x", (int)value.dataType, (int)value.data); - } - const char16_t* val = block->getAttributeStringValue(i, &len); - if (val != NULL) { - printf(" (Raw: \"%s\")", ResTable::normalizeForOutput(String8(val).string()). - string()); - } - printf("\n"); - } - } else if (code == ResXMLTree::END_TAG) { - depth--; - } else if (code == ResXMLTree::START_NAMESPACE) { - namespace_entry ns; - size_t len; - const uint16_t* prefix16 = block->getNamespacePrefix(&len); - if (prefix16) { - ns.prefix = String8(prefix16); - } else { - ns.prefix = "<DEF>"; - } - ns.uri = String8(block->getNamespaceUri(&len)); - namespaces.push(ns); - printf("%sN: %s=%s\n", prefix.string(), ns.prefix.string(), - ns.uri.string()); - depth++; - } else if (code == ResXMLTree::END_NAMESPACE) { - depth--; - const namespace_entry& ns = namespaces.top(); - size_t len; - const uint16_t* prefix16 = block->getNamespacePrefix(&len); - String8 pr; - if (prefix16) { - pr = String8(prefix16); - } else { - pr = "<DEF>"; - } - if (ns.prefix != pr) { - prefix = make_prefix(depth); - printf("%s*** BAD END NS PREFIX: found=%s, expected=%s\n", - prefix.string(), pr.string(), ns.prefix.string()); - } - String8 uri = String8(block->getNamespaceUri(&len)); - if (ns.uri != uri) { - prefix = make_prefix(depth); - printf("%s *** BAD END NS URI: found=%s, expected=%s\n", - prefix.string(), uri.string(), ns.uri.string()); - } - namespaces.pop(); - } else if (code == ResXMLTree::TEXT) { - size_t len; - printf("%sC: \"%s\"\n", prefix.string(), - ResTable::normalizeForOutput(String8(block->getText(&len)).string()).string()); - } - } - - block->restart(); -} - -status_t parseXMLResource(const sp<AaptFile>& file, ResXMLTree* outTree, - bool stripAll, bool keepComments, - const char** cDataTags) -{ - sp<XMLNode> root = XMLNode::parse(file); - if (root == NULL) { - return UNKNOWN_ERROR; - } - root->removeWhitespace(stripAll, cDataTags); - - NOISY(printf("Input XML from %s:\n", (const char*)file->getPrintableSource())); - NOISY(root->print()); - sp<AaptFile> rsc = new AaptFile(String8(), AaptGroupEntry(), String8()); - status_t err = root->flatten(rsc, !keepComments, false); - if (err != NO_ERROR) { - return err; - } - err = outTree->setTo(rsc->getData(), rsc->getSize(), true); - if (err != NO_ERROR) { - return err; - } - - NOISY(printf("Output XML:\n")); - NOISY(printXMLBlock(outTree)); - - return NO_ERROR; -} - -sp<XMLNode> XMLNode::parse(const sp<AaptFile>& file) -{ - char buf[16384]; - int fd = open(file->getSourceFile().string(), O_RDONLY | O_BINARY); - if (fd < 0) { - SourcePos(file->getSourceFile(), -1).error("Unable to open file for read: %s", - strerror(errno)); - return NULL; - } - - XML_Parser parser = XML_ParserCreateNS(NULL, 1); - ParseState state; - state.filename = file->getPrintableSource(); - state.parser = parser; - XML_SetUserData(parser, &state); - XML_SetElementHandler(parser, startElement, endElement); - XML_SetNamespaceDeclHandler(parser, startNamespace, endNamespace); - XML_SetCharacterDataHandler(parser, characterData); - XML_SetCommentHandler(parser, commentData); - - ssize_t len; - bool done; - do { - len = read(fd, buf, sizeof(buf)); - done = len < (ssize_t)sizeof(buf); - if (len < 0) { - SourcePos(file->getSourceFile(), -1).error("Error reading file: %s\n", strerror(errno)); - close(fd); - return NULL; - } - if (XML_Parse(parser, buf, len, done) == XML_STATUS_ERROR) { - SourcePos(file->getSourceFile(), (int)XML_GetCurrentLineNumber(parser)).error( - "Error parsing XML: %s\n", XML_ErrorString(XML_GetErrorCode(parser))); - close(fd); - return NULL; - } - } while (!done); - - XML_ParserFree(parser); - if (state.root == NULL) { - SourcePos(file->getSourceFile(), -1).error("No XML data generated when parsing"); - } - close(fd); - return state.root; -} - -XMLNode::XMLNode(const String8& filename, const String16& s1, const String16& s2, bool isNamespace) - : mNextAttributeIndex(0x80000000) - , mFilename(filename) - , mStartLineNumber(0) - , mEndLineNumber(0) - , mUTF8(false) -{ - if (isNamespace) { - mNamespacePrefix = s1; - mNamespaceUri = s2; - } else { - mNamespaceUri = s1; - mElementName = s2; - } -} - -XMLNode::XMLNode(const String8& filename) - : mFilename(filename) -{ - memset(&mCharsValue, 0, sizeof(mCharsValue)); -} - -XMLNode::type XMLNode::getType() const -{ - if (mElementName.size() != 0) { - return TYPE_ELEMENT; - } - if (mNamespaceUri.size() != 0) { - return TYPE_NAMESPACE; - } - return TYPE_CDATA; -} - -const String16& XMLNode::getNamespacePrefix() const -{ - return mNamespacePrefix; -} - -const String16& XMLNode::getNamespaceUri() const -{ - return mNamespaceUri; -} - -const String16& XMLNode::getElementNamespace() const -{ - return mNamespaceUri; -} - -const String16& XMLNode::getElementName() const -{ - return mElementName; -} - -const Vector<sp<XMLNode> >& XMLNode::getChildren() const -{ - return mChildren; -} - -const String8& XMLNode::getFilename() const -{ - return mFilename; -} - -const Vector<XMLNode::attribute_entry>& - XMLNode::getAttributes() const -{ - return mAttributes; -} - -const XMLNode::attribute_entry* XMLNode::getAttribute(const String16& ns, - const String16& name) const -{ - for (size_t i=0; i<mAttributes.size(); i++) { - const attribute_entry& ae(mAttributes.itemAt(i)); - if (ae.ns == ns && ae.name == name) { - return &ae; - } - } - - return NULL; -} - -XMLNode::attribute_entry* XMLNode::editAttribute(const String16& ns, - const String16& name) -{ - for (size_t i=0; i<mAttributes.size(); i++) { - attribute_entry * ae = &mAttributes.editItemAt(i); - if (ae->ns == ns && ae->name == name) { - return ae; - } - } - - return NULL; -} - -const String16& XMLNode::getCData() const -{ - return mChars; -} - -const String16& XMLNode::getComment() const -{ - return mComment; -} - -int32_t XMLNode::getStartLineNumber() const -{ - return mStartLineNumber; -} - -int32_t XMLNode::getEndLineNumber() const -{ - return mEndLineNumber; -} - -sp<XMLNode> XMLNode::searchElement(const String16& tagNamespace, const String16& tagName) -{ - if (getType() == XMLNode::TYPE_ELEMENT - && mNamespaceUri == tagNamespace - && mElementName == tagName) { - return this; - } - - for (size_t i=0; i<mChildren.size(); i++) { - sp<XMLNode> found = mChildren.itemAt(i)->searchElement(tagNamespace, tagName); - if (found != NULL) { - return found; - } - } - - return NULL; -} - -sp<XMLNode> XMLNode::getChildElement(const String16& tagNamespace, const String16& tagName) -{ - for (size_t i=0; i<mChildren.size(); i++) { - sp<XMLNode> child = mChildren.itemAt(i); - if (child->getType() == XMLNode::TYPE_ELEMENT - && child->mNamespaceUri == tagNamespace - && child->mElementName == tagName) { - return child; - } - } - - return NULL; -} - -status_t XMLNode::addChild(const sp<XMLNode>& child) -{ - if (getType() == TYPE_CDATA) { - SourcePos(mFilename, child->getStartLineNumber()).error("Child to CDATA node."); - return UNKNOWN_ERROR; - } - //printf("Adding child %p to parent %p\n", child.get(), this); - mChildren.add(child); - return NO_ERROR; -} - -status_t XMLNode::insertChildAt(const sp<XMLNode>& child, size_t index) -{ - if (getType() == TYPE_CDATA) { - SourcePos(mFilename, child->getStartLineNumber()).error("Child to CDATA node."); - return UNKNOWN_ERROR; - } - //printf("Adding child %p to parent %p\n", child.get(), this); - mChildren.insertAt(child, index); - return NO_ERROR; -} - -status_t XMLNode::addAttribute(const String16& ns, const String16& name, - const String16& value) -{ - if (getType() == TYPE_CDATA) { - SourcePos(mFilename, getStartLineNumber()).error("Child to CDATA node."); - return UNKNOWN_ERROR; - } - - if (ns != RESOURCES_TOOLS_NAMESPACE) { - attribute_entry e; - e.index = mNextAttributeIndex++; - e.ns = ns; - e.name = name; - e.string = value; - mAttributes.add(e); - mAttributeOrder.add(e.index, mAttributes.size()-1); - } - return NO_ERROR; -} - -void XMLNode::setAttributeResID(size_t attrIdx, uint32_t resId) -{ - attribute_entry& e = mAttributes.editItemAt(attrIdx); - if (e.nameResId) { - mAttributeOrder.removeItem(e.nameResId); - } else { - mAttributeOrder.removeItem(e.index); - } - NOISY(printf("Elem %s %s=\"%s\": set res id = 0x%08x\n", - String8(getElementName()).string(), - String8(mAttributes.itemAt(attrIdx).name).string(), - String8(mAttributes.itemAt(attrIdx).string).string(), - resId)); - mAttributes.editItemAt(attrIdx).nameResId = resId; - mAttributeOrder.add(resId, attrIdx); -} - -status_t XMLNode::appendChars(const String16& chars) -{ - if (getType() != TYPE_CDATA) { - SourcePos(mFilename, getStartLineNumber()).error("Adding characters to element node."); - return UNKNOWN_ERROR; - } - mChars.append(chars); - return NO_ERROR; -} - -status_t XMLNode::appendComment(const String16& comment) -{ - if (mComment.size() > 0) { - mComment.append(String16("\n")); - } - mComment.append(comment); - return NO_ERROR; -} - -void XMLNode::setStartLineNumber(int32_t line) -{ - mStartLineNumber = line; -} - -void XMLNode::setEndLineNumber(int32_t line) -{ - mEndLineNumber = line; -} - -void XMLNode::removeWhitespace(bool stripAll, const char** cDataTags) -{ - //printf("Removing whitespace in %s\n", String8(mElementName).string()); - size_t N = mChildren.size(); - if (cDataTags) { - String8 tag(mElementName); - const char** p = cDataTags; - while (*p) { - if (tag == *p) { - stripAll = false; - break; - } - } - } - for (size_t i=0; i<N; i++) { - sp<XMLNode> node = mChildren.itemAt(i); - if (node->getType() == TYPE_CDATA) { - // This is a CDATA node... - const char16_t* p = node->mChars.string(); - while (*p != 0 && *p < 128 && isspace(*p)) { - p++; - } - //printf("Space ends at %d in \"%s\"\n", - // (int)(p-node->mChars.string()), - // String8(node->mChars).string()); - if (*p == 0) { - if (stripAll) { - // Remove this node! - mChildren.removeAt(i); - N--; - i--; - } else { - node->mChars = String16(" "); - } - } else { - // Compact leading/trailing whitespace. - const char16_t* e = node->mChars.string()+node->mChars.size()-1; - while (e > p && *e < 128 && isspace(*e)) { - e--; - } - if (p > node->mChars.string()) { - p--; - } - if (e < (node->mChars.string()+node->mChars.size()-1)) { - e++; - } - if (p > node->mChars.string() || - e < (node->mChars.string()+node->mChars.size()-1)) { - String16 tmp(p, e-p+1); - node->mChars = tmp; - } - } - } else { - node->removeWhitespace(stripAll, cDataTags); - } - } -} - -status_t XMLNode::parseValues(const sp<AaptAssets>& assets, - ResourceTable* table) -{ - bool hasErrors = false; - - if (getType() == TYPE_ELEMENT) { - const size_t N = mAttributes.size(); - String16 defPackage(assets->getPackage()); - for (size_t i=0; i<N; i++) { - attribute_entry& e = mAttributes.editItemAt(i); - AccessorCookie ac(SourcePos(mFilename, getStartLineNumber()), String8(e.name), - String8(e.string)); - table->setCurrentXmlPos(SourcePos(mFilename, getStartLineNumber())); - if (!assets->getIncludedResources() - .stringToValue(&e.value, &e.string, - e.string.string(), e.string.size(), true, true, - e.nameResId, NULL, &defPackage, table, &ac)) { - hasErrors = true; - } - NOISY(printf("Attr %s: type=0x%x, str=%s\n", - String8(e.name).string(), e.value.dataType, - String8(e.string).string())); - } - } - const size_t N = mChildren.size(); - for (size_t i=0; i<N; i++) { - status_t err = mChildren.itemAt(i)->parseValues(assets, table); - if (err != NO_ERROR) { - hasErrors = true; - } - } - return hasErrors ? UNKNOWN_ERROR : NO_ERROR; -} - -status_t XMLNode::assignResourceIds(const sp<AaptAssets>& assets, - const ResourceTable* table) -{ - bool hasErrors = false; - - if (getType() == TYPE_ELEMENT) { - String16 attr("attr"); - const char* errorMsg; - const size_t N = mAttributes.size(); - for (size_t i=0; i<N; i++) { - const attribute_entry& e = mAttributes.itemAt(i); - if (e.ns.size() <= 0) continue; - bool nsIsPublic; - String16 pkg(getNamespaceResourcePackage(String16(assets->getPackage()), e.ns, &nsIsPublic)); - NOISY(printf("Elem %s %s=\"%s\": namespace(%s) %s ===> %s\n", - String8(getElementName()).string(), - String8(e.name).string(), - String8(e.string).string(), - String8(e.ns).string(), - (nsIsPublic) ? "public" : "private", - String8(pkg).string())); - if (pkg.size() <= 0) continue; - uint32_t res = table != NULL - ? table->getResId(e.name, &attr, &pkg, &errorMsg, nsIsPublic) - : assets->getIncludedResources(). - identifierForName(e.name.string(), e.name.size(), - attr.string(), attr.size(), - pkg.string(), pkg.size()); - if (res != 0) { - NOISY(printf("XML attribute name %s: resid=0x%08x\n", - String8(e.name).string(), res)); - setAttributeResID(i, res); - } else { - SourcePos(mFilename, getStartLineNumber()).error( - "No resource identifier found for attribute '%s' in package '%s'\n", - String8(e.name).string(), String8(pkg).string()); - hasErrors = true; - } - } - } - const size_t N = mChildren.size(); - for (size_t i=0; i<N; i++) { - status_t err = mChildren.itemAt(i)->assignResourceIds(assets, table); - if (err < NO_ERROR) { - hasErrors = true; - } - } - - return hasErrors ? UNKNOWN_ERROR : NO_ERROR; -} - -status_t XMLNode::flatten(const sp<AaptFile>& dest, - bool stripComments, bool stripRawValues) const -{ - StringPool strings(mUTF8); - Vector<uint32_t> resids; - - // First collect just the strings for attribute names that have a - // resource ID assigned to them. This ensures that the resource ID - // array is compact, and makes it easier to deal with attribute names - // in different namespaces (and thus with different resource IDs). - collect_resid_strings(&strings, &resids); - - // Next collect all remainibng strings. - collect_strings(&strings, &resids, stripComments, stripRawValues); - -#if 0 // No longer compiles - NOISY(printf("Found strings:\n"); - const size_t N = strings.size(); - for (size_t i=0; i<N; i++) { - printf("%s\n", String8(strings.entryAt(i).string).string()); - } - ); -#endif - - sp<AaptFile> stringPool = strings.createStringBlock(); - NOISY(aout << "String pool:" - << HexDump(stringPool->getData(), stringPool->getSize()) << endl); - - ResXMLTree_header header; - memset(&header, 0, sizeof(header)); - header.header.type = htods(RES_XML_TYPE); - header.header.headerSize = htods(sizeof(header)); - - const size_t basePos = dest->getSize(); - dest->writeData(&header, sizeof(header)); - dest->writeData(stringPool->getData(), stringPool->getSize()); - - // If we have resource IDs, write them. - if (resids.size() > 0) { - const size_t resIdsPos = dest->getSize(); - const size_t resIdsSize = - sizeof(ResChunk_header)+(sizeof(uint32_t)*resids.size()); - ResChunk_header* idsHeader = (ResChunk_header*) - (((const uint8_t*)dest->editData(resIdsPos+resIdsSize))+resIdsPos); - idsHeader->type = htods(RES_XML_RESOURCE_MAP_TYPE); - idsHeader->headerSize = htods(sizeof(*idsHeader)); - idsHeader->size = htodl(resIdsSize); - uint32_t* ids = (uint32_t*)(idsHeader+1); - for (size_t i=0; i<resids.size(); i++) { - *ids++ = htodl(resids[i]); - } - } - - flatten_node(strings, dest, stripComments, stripRawValues); - - void* data = dest->editData(); - ResXMLTree_header* hd = (ResXMLTree_header*)(((uint8_t*)data)+basePos); - size_t size = dest->getSize()-basePos; - hd->header.size = htodl(dest->getSize()-basePos); - - NOISY(aout << "XML resource:" - << HexDump(dest->getData(), dest->getSize()) << endl); - - #if PRINT_STRING_METRICS - fprintf(stderr, "**** total xml size: %d / %d%% strings (in %s)\n", - dest->getSize(), (stringPool->getSize()*100)/dest->getSize(), - dest->getPath().string()); - #endif - - return NO_ERROR; -} - -void XMLNode::print(int indent) -{ - String8 prefix; - int i; - for (i=0; i<indent; i++) { - prefix.append(" "); - } - if (getType() == TYPE_ELEMENT) { - String8 elemNs(getNamespaceUri()); - if (elemNs.size() > 0) { - elemNs.append(":"); - } - printf("%s E: %s%s", prefix.string(), - elemNs.string(), String8(getElementName()).string()); - int N = mAttributes.size(); - for (i=0; i<N; i++) { - ssize_t idx = mAttributeOrder.valueAt(i); - if (i == 0) { - printf(" / "); - } else { - printf(", "); - } - const attribute_entry& attr = mAttributes.itemAt(idx); - String8 attrNs(attr.ns); - if (attrNs.size() > 0) { - attrNs.append(":"); - } - if (attr.nameResId) { - printf("%s%s(0x%08x)", attrNs.string(), - String8(attr.name).string(), attr.nameResId); - } else { - printf("%s%s", attrNs.string(), String8(attr.name).string()); - } - printf("=%s", String8(attr.string).string()); - } - printf("\n"); - } else if (getType() == TYPE_NAMESPACE) { - printf("%s N: %s=%s\n", prefix.string(), - getNamespacePrefix().size() > 0 - ? String8(getNamespacePrefix()).string() : "<DEF>", - String8(getNamespaceUri()).string()); - } else { - printf("%s C: \"%s\"\n", prefix.string(), String8(getCData()).string()); - } - int N = mChildren.size(); - for (i=0; i<N; i++) { - mChildren.itemAt(i)->print(indent+1); - } -} - -static void splitName(const char* name, String16* outNs, String16* outName) -{ - const char* p = name; - while (*p != 0 && *p != 1) { - p++; - } - if (*p == 0) { - *outNs = String16(); - *outName = String16(name); - } else { - *outNs = String16(name, (p-name)); - *outName = String16(p+1); - } -} - -void XMLCALL -XMLNode::startNamespace(void *userData, const char *prefix, const char *uri) -{ - NOISY_PARSE(printf("Start Namespace: %s %s\n", prefix, uri)); - ParseState* st = (ParseState*)userData; - sp<XMLNode> node = XMLNode::newNamespace(st->filename, - String16(prefix != NULL ? prefix : ""), String16(uri)); - node->setStartLineNumber(XML_GetCurrentLineNumber(st->parser)); - if (st->stack.size() > 0) { - st->stack.itemAt(st->stack.size()-1)->addChild(node); - } else { - st->root = node; - } - st->stack.push(node); -} - -void XMLCALL -XMLNode::startElement(void *userData, const char *name, const char **atts) -{ - NOISY_PARSE(printf("Start Element: %s\n", name)); - ParseState* st = (ParseState*)userData; - String16 ns16, name16; - splitName(name, &ns16, &name16); - sp<XMLNode> node = XMLNode::newElement(st->filename, ns16, name16); - node->setStartLineNumber(XML_GetCurrentLineNumber(st->parser)); - if (st->pendingComment.size() > 0) { - node->appendComment(st->pendingComment); - st->pendingComment = String16(); - } - if (st->stack.size() > 0) { - st->stack.itemAt(st->stack.size()-1)->addChild(node); - } else { - st->root = node; - } - st->stack.push(node); - - for (int i = 0; atts[i]; i += 2) { - splitName(atts[i], &ns16, &name16); - node->addAttribute(ns16, name16, String16(atts[i+1])); - } -} - -void XMLCALL -XMLNode::characterData(void *userData, const XML_Char *s, int len) -{ - NOISY_PARSE(printf("CDATA: \"%s\"\n", String8(s, len).string())); - ParseState* st = (ParseState*)userData; - sp<XMLNode> node = NULL; - if (st->stack.size() == 0) { - return; - } - sp<XMLNode> parent = st->stack.itemAt(st->stack.size()-1); - if (parent != NULL && parent->getChildren().size() > 0) { - node = parent->getChildren()[parent->getChildren().size()-1]; - if (node->getType() != TYPE_CDATA) { - // Last node is not CDATA, need to make a new node. - node = NULL; - } - } - - if (node == NULL) { - node = XMLNode::newCData(st->filename); - node->setStartLineNumber(XML_GetCurrentLineNumber(st->parser)); - parent->addChild(node); - } - - node->appendChars(String16(s, len)); -} - -void XMLCALL -XMLNode::endElement(void *userData, const char *name) -{ - NOISY_PARSE(printf("End Element: %s\n", name)); - ParseState* st = (ParseState*)userData; - sp<XMLNode> node = st->stack.itemAt(st->stack.size()-1); - node->setEndLineNumber(XML_GetCurrentLineNumber(st->parser)); - if (st->pendingComment.size() > 0) { - node->appendComment(st->pendingComment); - st->pendingComment = String16(); - } - String16 ns16, name16; - splitName(name, &ns16, &name16); - LOG_ALWAYS_FATAL_IF(node->getElementNamespace() != ns16 - || node->getElementName() != name16, - "Bad end element %s", name); - st->stack.pop(); -} - -void XMLCALL -XMLNode::endNamespace(void *userData, const char *prefix) -{ - const char* nonNullPrefix = prefix != NULL ? prefix : ""; - NOISY_PARSE(printf("End Namespace: %s\n", prefix)); - ParseState* st = (ParseState*)userData; - sp<XMLNode> node = st->stack.itemAt(st->stack.size()-1); - node->setEndLineNumber(XML_GetCurrentLineNumber(st->parser)); - LOG_ALWAYS_FATAL_IF(node->getNamespacePrefix() != String16(nonNullPrefix), - "Bad end namespace %s", prefix); - st->stack.pop(); -} - -void XMLCALL -XMLNode::commentData(void *userData, const char *comment) -{ - NOISY_PARSE(printf("Comment: %s\n", comment)); - ParseState* st = (ParseState*)userData; - if (st->pendingComment.size() > 0) { - st->pendingComment.append(String16("\n")); - } - st->pendingComment.append(String16(comment)); -} - -status_t XMLNode::collect_strings(StringPool* dest, Vector<uint32_t>* outResIds, - bool stripComments, bool stripRawValues) const -{ - collect_attr_strings(dest, outResIds, true); - - int i; - if (RESOURCES_TOOLS_NAMESPACE != mNamespaceUri) { - if (mNamespacePrefix.size() > 0) { - dest->add(mNamespacePrefix, true); - } - if (mNamespaceUri.size() > 0) { - dest->add(mNamespaceUri, true); - } - } - if (mElementName.size() > 0) { - dest->add(mElementName, true); - } - - if (!stripComments && mComment.size() > 0) { - dest->add(mComment, true); - } - - const int NA = mAttributes.size(); - - for (i=0; i<NA; i++) { - const attribute_entry& ae = mAttributes.itemAt(i); - if (ae.ns.size() > 0) { - dest->add(ae.ns, true); - } - if (!stripRawValues || ae.needStringValue()) { - dest->add(ae.string, true); - } - /* - if (ae.value.dataType == Res_value::TYPE_NULL - || ae.value.dataType == Res_value::TYPE_STRING) { - dest->add(ae.string, true); - } - */ - } - - if (mElementName.size() == 0) { - // If not an element, include the CDATA, even if it is empty. - dest->add(mChars, true); - } - - const int NC = mChildren.size(); - - for (i=0; i<NC; i++) { - mChildren.itemAt(i)->collect_strings(dest, outResIds, - stripComments, stripRawValues); - } - - return NO_ERROR; -} - -status_t XMLNode::collect_attr_strings(StringPool* outPool, - Vector<uint32_t>* outResIds, bool allAttrs) const { - const int NA = mAttributes.size(); - - for (int i=0; i<NA; i++) { - const attribute_entry& attr = mAttributes.itemAt(i); - uint32_t id = attr.nameResId; - if (id || allAttrs) { - // See if we have already assigned this resource ID to a pooled - // string... - const Vector<size_t>* indices = outPool->offsetsForString(attr.name); - ssize_t idx = -1; - if (indices != NULL) { - const int NJ = indices->size(); - const size_t NR = outResIds->size(); - for (int j=0; j<NJ; j++) { - size_t strIdx = indices->itemAt(j); - if (strIdx >= NR) { - if (id == 0) { - // We don't need to assign a resource ID for this one. - idx = strIdx; - break; - } - // Just ignore strings that are out of range of - // the currently assigned resource IDs... we add - // strings as we assign the first ID. - } else if (outResIds->itemAt(strIdx) == id) { - idx = strIdx; - break; - } - } - } - if (idx < 0) { - idx = outPool->add(attr.name); - NOISY(printf("Adding attr %s (resid 0x%08x) to pool: idx=%d\n", - String8(attr.name).string(), id, idx)); - if (id != 0) { - while ((ssize_t)outResIds->size() <= idx) { - outResIds->add(0); - } - outResIds->replaceAt(id, idx); - } - } - attr.namePoolIdx = idx; - NOISY(printf("String %s offset=0x%08x\n", - String8(attr.name).string(), idx)); - } - } - - return NO_ERROR; -} - -status_t XMLNode::collect_resid_strings(StringPool* outPool, - Vector<uint32_t>* outResIds) const -{ - collect_attr_strings(outPool, outResIds, false); - - const int NC = mChildren.size(); - - for (int i=0; i<NC; i++) { - mChildren.itemAt(i)->collect_resid_strings(outPool, outResIds); - } - - return NO_ERROR; -} - -status_t XMLNode::flatten_node(const StringPool& strings, const sp<AaptFile>& dest, - bool stripComments, bool stripRawValues) const -{ - ResXMLTree_node node; - ResXMLTree_cdataExt cdataExt; - ResXMLTree_namespaceExt namespaceExt; - ResXMLTree_attrExt attrExt; - const void* extData = NULL; - size_t extSize = 0; - ResXMLTree_attribute attr; - bool writeCurrentNode = true; - - const size_t NA = mAttributes.size(); - const size_t NC = mChildren.size(); - size_t i; - - LOG_ALWAYS_FATAL_IF(NA != mAttributeOrder.size(), "Attributes messed up!"); - - const String16 id16("id"); - const String16 class16("class"); - const String16 style16("style"); - - const type type = getType(); - - memset(&node, 0, sizeof(node)); - memset(&attr, 0, sizeof(attr)); - node.header.headerSize = htods(sizeof(node)); - node.lineNumber = htodl(getStartLineNumber()); - if (!stripComments) { - node.comment.index = htodl( - mComment.size() > 0 ? strings.offsetForString(mComment) : -1); - //if (mComment.size() > 0) { - // printf("Flattening comment: %s\n", String8(mComment).string()); - //} - } else { - node.comment.index = htodl((uint32_t)-1); - } - if (type == TYPE_ELEMENT) { - node.header.type = htods(RES_XML_START_ELEMENT_TYPE); - extData = &attrExt; - extSize = sizeof(attrExt); - memset(&attrExt, 0, sizeof(attrExt)); - if (mNamespaceUri.size() > 0) { - attrExt.ns.index = htodl(strings.offsetForString(mNamespaceUri)); - } else { - attrExt.ns.index = htodl((uint32_t)-1); - } - attrExt.name.index = htodl(strings.offsetForString(mElementName)); - attrExt.attributeStart = htods(sizeof(attrExt)); - attrExt.attributeSize = htods(sizeof(attr)); - attrExt.attributeCount = htods(NA); - attrExt.idIndex = htods(0); - attrExt.classIndex = htods(0); - attrExt.styleIndex = htods(0); - for (i=0; i<NA; i++) { - ssize_t idx = mAttributeOrder.valueAt(i); - const attribute_entry& ae = mAttributes.itemAt(idx); - if (ae.ns.size() == 0) { - if (ae.name == id16) { - attrExt.idIndex = htods(i+1); - } else if (ae.name == class16) { - attrExt.classIndex = htods(i+1); - } else if (ae.name == style16) { - attrExt.styleIndex = htods(i+1); - } - } - } - } else if (type == TYPE_NAMESPACE) { - if (mNamespaceUri == RESOURCES_TOOLS_NAMESPACE) { - writeCurrentNode = false; - } else { - node.header.type = htods(RES_XML_START_NAMESPACE_TYPE); - extData = &namespaceExt; - extSize = sizeof(namespaceExt); - memset(&namespaceExt, 0, sizeof(namespaceExt)); - if (mNamespacePrefix.size() > 0) { - namespaceExt.prefix.index = htodl(strings.offsetForString(mNamespacePrefix)); - } else { - namespaceExt.prefix.index = htodl((uint32_t)-1); - } - namespaceExt.prefix.index = htodl(strings.offsetForString(mNamespacePrefix)); - namespaceExt.uri.index = htodl(strings.offsetForString(mNamespaceUri)); - } - LOG_ALWAYS_FATAL_IF(NA != 0, "Namespace nodes can't have attributes!"); - } else if (type == TYPE_CDATA) { - node.header.type = htods(RES_XML_CDATA_TYPE); - extData = &cdataExt; - extSize = sizeof(cdataExt); - memset(&cdataExt, 0, sizeof(cdataExt)); - cdataExt.data.index = htodl(strings.offsetForString(mChars)); - cdataExt.typedData.size = htods(sizeof(cdataExt.typedData)); - cdataExt.typedData.res0 = 0; - cdataExt.typedData.dataType = mCharsValue.dataType; - cdataExt.typedData.data = htodl(mCharsValue.data); - LOG_ALWAYS_FATAL_IF(NA != 0, "CDATA nodes can't have attributes!"); - } - - node.header.size = htodl(sizeof(node) + extSize + (sizeof(attr)*NA)); - - if (writeCurrentNode) { - dest->writeData(&node, sizeof(node)); - if (extSize > 0) { - dest->writeData(extData, extSize); - } - } - - for (i=0; i<NA; i++) { - ssize_t idx = mAttributeOrder.valueAt(i); - const attribute_entry& ae = mAttributes.itemAt(idx); - if (ae.ns.size() > 0) { - attr.ns.index = htodl(strings.offsetForString(ae.ns)); - } else { - attr.ns.index = htodl((uint32_t)-1); - } - attr.name.index = htodl(ae.namePoolIdx); - - if (!stripRawValues || ae.needStringValue()) { - attr.rawValue.index = htodl(strings.offsetForString(ae.string)); - } else { - attr.rawValue.index = htodl((uint32_t)-1); - } - attr.typedValue.size = htods(sizeof(attr.typedValue)); - if (ae.value.dataType == Res_value::TYPE_NULL - || ae.value.dataType == Res_value::TYPE_STRING) { - attr.typedValue.res0 = 0; - attr.typedValue.dataType = Res_value::TYPE_STRING; - attr.typedValue.data = htodl(strings.offsetForString(ae.string)); - } else { - attr.typedValue.res0 = 0; - attr.typedValue.dataType = ae.value.dataType; - attr.typedValue.data = htodl(ae.value.data); - } - dest->writeData(&attr, sizeof(attr)); - } - - for (i=0; i<NC; i++) { - status_t err = mChildren.itemAt(i)->flatten_node(strings, dest, - stripComments, stripRawValues); - if (err != NO_ERROR) { - return err; - } - } - - if (type == TYPE_ELEMENT) { - ResXMLTree_endElementExt endElementExt; - memset(&endElementExt, 0, sizeof(endElementExt)); - node.header.type = htods(RES_XML_END_ELEMENT_TYPE); - node.header.size = htodl(sizeof(node)+sizeof(endElementExt)); - node.lineNumber = htodl(getEndLineNumber()); - node.comment.index = htodl((uint32_t)-1); - endElementExt.ns.index = attrExt.ns.index; - endElementExt.name.index = attrExt.name.index; - dest->writeData(&node, sizeof(node)); - dest->writeData(&endElementExt, sizeof(endElementExt)); - } else if (type == TYPE_NAMESPACE) { - if (writeCurrentNode) { - node.header.type = htods(RES_XML_END_NAMESPACE_TYPE); - node.lineNumber = htodl(getEndLineNumber()); - node.comment.index = htodl((uint32_t)-1); - node.header.size = htodl(sizeof(node)+extSize); - dest->writeData(&node, sizeof(node)); - dest->writeData(extData, extSize); - } - } - - return NO_ERROR; -} diff --git a/tools/aapt/XMLNode.h b/tools/aapt/XMLNode.h deleted file mode 100644 index 05624b7..0000000 --- a/tools/aapt/XMLNode.h +++ /dev/null @@ -1,202 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Build resource files from raw assets. -// - -#ifndef XML_NODE_H -#define XML_NODE_H - -#include "StringPool.h" -#include "ResourceTable.h" - -class XMLNode; - -extern const char* const RESOURCES_ROOT_NAMESPACE; -extern const char* const RESOURCES_ANDROID_NAMESPACE; - -bool isWhitespace(const char16_t* str); - -String16 getNamespaceResourcePackage(String16 namespaceUri, bool* outIsPublic = NULL); - -status_t parseStyledString(Bundle* bundle, - const char* fileName, - ResXMLTree* inXml, - const String16& endTag, - String16* outString, - Vector<StringPool::entry_style_span>* outSpans, - bool isFormatted, - bool isPseudolocalizable); - -void printXMLBlock(ResXMLTree* block); - -status_t parseXMLResource(const sp<AaptFile>& file, ResXMLTree* outTree, - bool stripAll=true, bool keepComments=false, - const char** cDataTags=NULL); - -class XMLNode : public RefBase -{ -public: - static sp<XMLNode> parse(const sp<AaptFile>& file); - - static inline - sp<XMLNode> newNamespace(const String8& filename, const String16& prefix, const String16& uri) { - return new XMLNode(filename, prefix, uri, true); - } - - static inline - sp<XMLNode> newElement(const String8& filename, const String16& ns, const String16& name) { - return new XMLNode(filename, ns, name, false); - } - - static inline - sp<XMLNode> newCData(const String8& filename) { - return new XMLNode(filename); - } - - enum type { - TYPE_NAMESPACE, - TYPE_ELEMENT, - TYPE_CDATA - }; - - type getType() const; - - const String16& getNamespacePrefix() const; - const String16& getNamespaceUri() const; - - const String16& getElementNamespace() const; - const String16& getElementName() const; - const Vector<sp<XMLNode> >& getChildren() const; - - const String8& getFilename() const; - - struct attribute_entry { - attribute_entry() : index(~(uint32_t)0), nameResId(0) - { - value.dataType = Res_value::TYPE_NULL; - } - - bool needStringValue() const { - return nameResId == 0 - || value.dataType == Res_value::TYPE_NULL - || value.dataType == Res_value::TYPE_STRING; - } - - String16 ns; - String16 name; - String16 string; - Res_value value; - uint32_t index; - uint32_t nameResId; - mutable uint32_t namePoolIdx; - }; - - const Vector<attribute_entry>& getAttributes() const; - - const attribute_entry* getAttribute(const String16& ns, const String16& name) const; - - attribute_entry* editAttribute(const String16& ns, const String16& name); - - const String16& getCData() const; - - const String16& getComment() const; - - int32_t getStartLineNumber() const; - int32_t getEndLineNumber() const; - - sp<XMLNode> searchElement(const String16& tagNamespace, const String16& tagName); - - sp<XMLNode> getChildElement(const String16& tagNamespace, const String16& tagName); - - status_t addChild(const sp<XMLNode>& child); - - status_t insertChildAt(const sp<XMLNode>& child, size_t index); - - status_t addAttribute(const String16& ns, const String16& name, - const String16& value); - - void setAttributeResID(size_t attrIdx, uint32_t resId); - - status_t appendChars(const String16& chars); - - status_t appendComment(const String16& comment); - - void setStartLineNumber(int32_t line); - void setEndLineNumber(int32_t line); - - void removeWhitespace(bool stripAll=true, const char** cDataTags=NULL); - - void setUTF8(bool val) { mUTF8 = val; } - - status_t parseValues(const sp<AaptAssets>& assets, ResourceTable* table); - - status_t assignResourceIds(const sp<AaptAssets>& assets, - const ResourceTable* table = NULL); - - status_t flatten(const sp<AaptFile>& dest, bool stripComments, - bool stripRawValues) const; - - void print(int indent=0); - -private: - struct ParseState - { - String8 filename; - XML_Parser parser; - sp<XMLNode> root; - Vector<sp<XMLNode> > stack; - String16 pendingComment; - }; - - static void XMLCALL - startNamespace(void *userData, const char *prefix, const char *uri); - static void XMLCALL - startElement(void *userData, const char *name, const char **atts); - static void XMLCALL - characterData(void *userData, const XML_Char *s, int len); - static void XMLCALL - endElement(void *userData, const char *name); - static void XMLCALL - endNamespace(void *userData, const char *prefix); - - static void XMLCALL - commentData(void *userData, const char *comment); - - // Creating an element node. - XMLNode(const String8& filename, const String16& s1, const String16& s2, bool isNamespace); - - // Creating a CDATA node. - XMLNode(const String8& filename); - - status_t collect_strings(StringPool* dest, Vector<uint32_t>* outResIds, - bool stripComments, bool stripRawValues) const; - - status_t collect_attr_strings(StringPool* outPool, - Vector<uint32_t>* outResIds, bool allAttrs) const; - - status_t collect_resid_strings(StringPool* outPool, - Vector<uint32_t>* outResIds) const; - - status_t flatten_node(const StringPool& strings, const sp<AaptFile>& dest, - bool stripComments, bool stripRawValues) const; - - String16 mNamespacePrefix; - String16 mNamespaceUri; - String16 mElementName; - Vector<sp<XMLNode> > mChildren; - Vector<attribute_entry> mAttributes; - KeyedVector<uint32_t, uint32_t> mAttributeOrder; - uint32_t mNextAttributeIndex; - String16 mChars; - Res_value mCharsValue; - String16 mComment; - String8 mFilename; - int32_t mStartLineNumber; - int32_t mEndLineNumber; - - // Encode compiled XML with UTF-8 StringPools? - bool mUTF8; -}; - -#endif diff --git a/tools/aapt/ZipEntry.cpp b/tools/aapt/ZipEntry.cpp deleted file mode 100644 index b575988..0000000 --- a/tools/aapt/ZipEntry.cpp +++ /dev/null @@ -1,696 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// Access to entries in a Zip archive. -// - -#define LOG_TAG "zip" - -#include "ZipEntry.h" -#include <utils/Log.h> - -#include <stdio.h> -#include <string.h> -#include <assert.h> - -using namespace android; - -/* - * Initialize a new ZipEntry structure from a FILE* positioned at a - * CentralDirectoryEntry. - * - * On exit, the file pointer will be at the start of the next CDE or - * at the EOCD. - */ -status_t ZipEntry::initFromCDE(FILE* fp) -{ - status_t result; - long posn; - bool hasDD; - - //ALOGV("initFromCDE ---\n"); - - /* read the CDE */ - result = mCDE.read(fp); - if (result != NO_ERROR) { - ALOGD("mCDE.read failed\n"); - return result; - } - - //mCDE.dump(); - - /* using the info in the CDE, go load up the LFH */ - posn = ftell(fp); - if (fseek(fp, mCDE.mLocalHeaderRelOffset, SEEK_SET) != 0) { - ALOGD("local header seek failed (%ld)\n", - mCDE.mLocalHeaderRelOffset); - return UNKNOWN_ERROR; - } - - result = mLFH.read(fp); - if (result != NO_ERROR) { - ALOGD("mLFH.read failed\n"); - return result; - } - - if (fseek(fp, posn, SEEK_SET) != 0) - return UNKNOWN_ERROR; - - //mLFH.dump(); - - /* - * We *might* need to read the Data Descriptor at this point and - * integrate it into the LFH. If this bit is set, the CRC-32, - * compressed size, and uncompressed size will be zero. In practice - * these seem to be rare. - */ - hasDD = (mLFH.mGPBitFlag & kUsesDataDescr) != 0; - if (hasDD) { - // do something clever - //ALOGD("+++ has data descriptor\n"); - } - - /* - * Sanity-check the LFH. Note that this will fail if the "kUsesDataDescr" - * flag is set, because the LFH is incomplete. (Not a problem, since we - * prefer the CDE values.) - */ - if (!hasDD && !compareHeaders()) { - ALOGW("warning: header mismatch\n"); - // keep going? - } - - /* - * If the mVersionToExtract is greater than 20, we may have an - * issue unpacking the record -- could be encrypted, compressed - * with something we don't support, or use Zip64 extensions. We - * can defer worrying about that to when we're extracting data. - */ - - return NO_ERROR; -} - -/* - * Initialize a new entry. Pass in the file name and an optional comment. - * - * Initializes the CDE and the LFH. - */ -void ZipEntry::initNew(const char* fileName, const char* comment) -{ - assert(fileName != NULL && *fileName != '\0'); // name required - - /* most fields are properly initialized by constructor */ - mCDE.mVersionMadeBy = kDefaultMadeBy; - mCDE.mVersionToExtract = kDefaultVersion; - mCDE.mCompressionMethod = kCompressStored; - mCDE.mFileNameLength = strlen(fileName); - if (comment != NULL) - mCDE.mFileCommentLength = strlen(comment); - mCDE.mExternalAttrs = 0x81b60020; // matches what WinZip does - - if (mCDE.mFileNameLength > 0) { - mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1]; - strcpy((char*) mCDE.mFileName, fileName); - } - if (mCDE.mFileCommentLength > 0) { - /* TODO: stop assuming null-terminated ASCII here? */ - mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1]; - strcpy((char*) mCDE.mFileComment, comment); - } - - copyCDEtoLFH(); -} - -/* - * Initialize a new entry, starting with the ZipEntry from a different - * archive. - * - * Initializes the CDE and the LFH. - */ -status_t ZipEntry::initFromExternal(const ZipFile* pZipFile, - const ZipEntry* pEntry) -{ - /* - * Copy everything in the CDE over, then fix up the hairy bits. - */ - memcpy(&mCDE, &pEntry->mCDE, sizeof(mCDE)); - - if (mCDE.mFileNameLength > 0) { - mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1]; - if (mCDE.mFileName == NULL) - return NO_MEMORY; - strcpy((char*) mCDE.mFileName, (char*)pEntry->mCDE.mFileName); - } - if (mCDE.mFileCommentLength > 0) { - mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1]; - if (mCDE.mFileComment == NULL) - return NO_MEMORY; - strcpy((char*) mCDE.mFileComment, (char*)pEntry->mCDE.mFileComment); - } - if (mCDE.mExtraFieldLength > 0) { - /* we null-terminate this, though it may not be a string */ - mCDE.mExtraField = new unsigned char[mCDE.mExtraFieldLength+1]; - if (mCDE.mExtraField == NULL) - return NO_MEMORY; - memcpy(mCDE.mExtraField, pEntry->mCDE.mExtraField, - mCDE.mExtraFieldLength+1); - } - - /* construct the LFH from the CDE */ - copyCDEtoLFH(); - - /* - * The LFH "extra" field is independent of the CDE "extra", so we - * handle it here. - */ - assert(mLFH.mExtraField == NULL); - mLFH.mExtraFieldLength = pEntry->mLFH.mExtraFieldLength; - if (mLFH.mExtraFieldLength > 0) { - mLFH.mExtraField = new unsigned char[mLFH.mExtraFieldLength+1]; - if (mLFH.mExtraField == NULL) - return NO_MEMORY; - memcpy(mLFH.mExtraField, pEntry->mLFH.mExtraField, - mLFH.mExtraFieldLength+1); - } - - return NO_ERROR; -} - -/* - * Insert pad bytes in the LFH by tweaking the "extra" field. This will - * potentially confuse something that put "extra" data in here earlier, - * but I can't find an actual problem. - */ -status_t ZipEntry::addPadding(int padding) -{ - if (padding <= 0) - return INVALID_OPERATION; - - //ALOGI("HEY: adding %d pad bytes to existing %d in %s\n", - // padding, mLFH.mExtraFieldLength, mCDE.mFileName); - - if (mLFH.mExtraFieldLength > 0) { - /* extend existing field */ - unsigned char* newExtra; - - newExtra = new unsigned char[mLFH.mExtraFieldLength + padding]; - if (newExtra == NULL) - return NO_MEMORY; - memset(newExtra + mLFH.mExtraFieldLength, 0, padding); - memcpy(newExtra, mLFH.mExtraField, mLFH.mExtraFieldLength); - - delete[] mLFH.mExtraField; - mLFH.mExtraField = newExtra; - mLFH.mExtraFieldLength += padding; - } else { - /* create new field */ - mLFH.mExtraField = new unsigned char[padding]; - memset(mLFH.mExtraField, 0, padding); - mLFH.mExtraFieldLength = padding; - } - - return NO_ERROR; -} - -/* - * Set the fields in the LFH equal to the corresponding fields in the CDE. - * - * This does not touch the LFH "extra" field. - */ -void ZipEntry::copyCDEtoLFH(void) -{ - mLFH.mVersionToExtract = mCDE.mVersionToExtract; - mLFH.mGPBitFlag = mCDE.mGPBitFlag; - mLFH.mCompressionMethod = mCDE.mCompressionMethod; - mLFH.mLastModFileTime = mCDE.mLastModFileTime; - mLFH.mLastModFileDate = mCDE.mLastModFileDate; - mLFH.mCRC32 = mCDE.mCRC32; - mLFH.mCompressedSize = mCDE.mCompressedSize; - mLFH.mUncompressedSize = mCDE.mUncompressedSize; - mLFH.mFileNameLength = mCDE.mFileNameLength; - // the "extra field" is independent - - delete[] mLFH.mFileName; - if (mLFH.mFileNameLength > 0) { - mLFH.mFileName = new unsigned char[mLFH.mFileNameLength+1]; - strcpy((char*) mLFH.mFileName, (const char*) mCDE.mFileName); - } else { - mLFH.mFileName = NULL; - } -} - -/* - * Set some information about a file after we add it. - */ -void ZipEntry::setDataInfo(long uncompLen, long compLen, unsigned long crc32, - int compressionMethod) -{ - mCDE.mCompressionMethod = compressionMethod; - mCDE.mCRC32 = crc32; - mCDE.mCompressedSize = compLen; - mCDE.mUncompressedSize = uncompLen; - mCDE.mCompressionMethod = compressionMethod; - if (compressionMethod == kCompressDeflated) { - mCDE.mGPBitFlag |= 0x0002; // indicates maximum compression used - } - copyCDEtoLFH(); -} - -/* - * See if the data in mCDE and mLFH match up. This is mostly useful for - * debugging these classes, but it can be used to identify damaged - * archives. - * - * Returns "false" if they differ. - */ -bool ZipEntry::compareHeaders(void) const -{ - if (mCDE.mVersionToExtract != mLFH.mVersionToExtract) { - ALOGV("cmp: VersionToExtract\n"); - return false; - } - if (mCDE.mGPBitFlag != mLFH.mGPBitFlag) { - ALOGV("cmp: GPBitFlag\n"); - return false; - } - if (mCDE.mCompressionMethod != mLFH.mCompressionMethod) { - ALOGV("cmp: CompressionMethod\n"); - return false; - } - if (mCDE.mLastModFileTime != mLFH.mLastModFileTime) { - ALOGV("cmp: LastModFileTime\n"); - return false; - } - if (mCDE.mLastModFileDate != mLFH.mLastModFileDate) { - ALOGV("cmp: LastModFileDate\n"); - return false; - } - if (mCDE.mCRC32 != mLFH.mCRC32) { - ALOGV("cmp: CRC32\n"); - return false; - } - if (mCDE.mCompressedSize != mLFH.mCompressedSize) { - ALOGV("cmp: CompressedSize\n"); - return false; - } - if (mCDE.mUncompressedSize != mLFH.mUncompressedSize) { - ALOGV("cmp: UncompressedSize\n"); - return false; - } - if (mCDE.mFileNameLength != mLFH.mFileNameLength) { - ALOGV("cmp: FileNameLength\n"); - return false; - } -#if 0 // this seems to be used for padding, not real data - if (mCDE.mExtraFieldLength != mLFH.mExtraFieldLength) { - ALOGV("cmp: ExtraFieldLength\n"); - return false; - } -#endif - if (mCDE.mFileName != NULL) { - if (strcmp((char*) mCDE.mFileName, (char*) mLFH.mFileName) != 0) { - ALOGV("cmp: FileName\n"); - return false; - } - } - - return true; -} - - -/* - * Convert the DOS date/time stamp into a UNIX time stamp. - */ -time_t ZipEntry::getModWhen(void) const -{ - struct tm parts; - - parts.tm_sec = (mCDE.mLastModFileTime & 0x001f) << 1; - parts.tm_min = (mCDE.mLastModFileTime & 0x07e0) >> 5; - parts.tm_hour = (mCDE.mLastModFileTime & 0xf800) >> 11; - parts.tm_mday = (mCDE.mLastModFileDate & 0x001f); - parts.tm_mon = ((mCDE.mLastModFileDate & 0x01e0) >> 5) -1; - parts.tm_year = ((mCDE.mLastModFileDate & 0xfe00) >> 9) + 80; - parts.tm_wday = parts.tm_yday = 0; - parts.tm_isdst = -1; // DST info "not available" - - return mktime(&parts); -} - -/* - * Set the CDE/LFH timestamp from UNIX time. - */ -void ZipEntry::setModWhen(time_t when) -{ -#ifdef HAVE_LOCALTIME_R - struct tm tmResult; -#endif - time_t even; - unsigned short zdate, ztime; - - struct tm* ptm; - - /* round up to an even number of seconds */ - even = (time_t)(((unsigned long)(when) + 1) & (~1)); - - /* expand */ -#ifdef HAVE_LOCALTIME_R - ptm = localtime_r(&even, &tmResult); -#else - ptm = localtime(&even); -#endif - - int year; - year = ptm->tm_year; - if (year < 80) - year = 80; - - zdate = (year - 80) << 9 | (ptm->tm_mon+1) << 5 | ptm->tm_mday; - ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1; - - mCDE.mLastModFileTime = mLFH.mLastModFileTime = ztime; - mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate; -} - - -/* - * =========================================================================== - * ZipEntry::LocalFileHeader - * =========================================================================== - */ - -/* - * Read a local file header. - * - * On entry, "fp" points to the signature at the start of the header. - * On exit, "fp" points to the start of data. - */ -status_t ZipEntry::LocalFileHeader::read(FILE* fp) -{ - status_t result = NO_ERROR; - unsigned char buf[kLFHLen]; - - assert(mFileName == NULL); - assert(mExtraField == NULL); - - if (fread(buf, 1, kLFHLen, fp) != kLFHLen) { - result = UNKNOWN_ERROR; - goto bail; - } - - if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) { - ALOGD("whoops: didn't find expected signature\n"); - result = UNKNOWN_ERROR; - goto bail; - } - - mVersionToExtract = ZipEntry::getShortLE(&buf[0x04]); - mGPBitFlag = ZipEntry::getShortLE(&buf[0x06]); - mCompressionMethod = ZipEntry::getShortLE(&buf[0x08]); - mLastModFileTime = ZipEntry::getShortLE(&buf[0x0a]); - mLastModFileDate = ZipEntry::getShortLE(&buf[0x0c]); - mCRC32 = ZipEntry::getLongLE(&buf[0x0e]); - mCompressedSize = ZipEntry::getLongLE(&buf[0x12]); - mUncompressedSize = ZipEntry::getLongLE(&buf[0x16]); - mFileNameLength = ZipEntry::getShortLE(&buf[0x1a]); - mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1c]); - - // TODO: validate sizes - - /* grab filename */ - if (mFileNameLength != 0) { - mFileName = new unsigned char[mFileNameLength+1]; - if (mFileName == NULL) { - result = NO_MEMORY; - goto bail; - } - if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) { - result = UNKNOWN_ERROR; - goto bail; - } - mFileName[mFileNameLength] = '\0'; - } - - /* grab extra field */ - if (mExtraFieldLength != 0) { - mExtraField = new unsigned char[mExtraFieldLength+1]; - if (mExtraField == NULL) { - result = NO_MEMORY; - goto bail; - } - if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) { - result = UNKNOWN_ERROR; - goto bail; - } - mExtraField[mExtraFieldLength] = '\0'; - } - -bail: - return result; -} - -/* - * Write a local file header. - */ -status_t ZipEntry::LocalFileHeader::write(FILE* fp) -{ - unsigned char buf[kLFHLen]; - - ZipEntry::putLongLE(&buf[0x00], kSignature); - ZipEntry::putShortLE(&buf[0x04], mVersionToExtract); - ZipEntry::putShortLE(&buf[0x06], mGPBitFlag); - ZipEntry::putShortLE(&buf[0x08], mCompressionMethod); - ZipEntry::putShortLE(&buf[0x0a], mLastModFileTime); - ZipEntry::putShortLE(&buf[0x0c], mLastModFileDate); - ZipEntry::putLongLE(&buf[0x0e], mCRC32); - ZipEntry::putLongLE(&buf[0x12], mCompressedSize); - ZipEntry::putLongLE(&buf[0x16], mUncompressedSize); - ZipEntry::putShortLE(&buf[0x1a], mFileNameLength); - ZipEntry::putShortLE(&buf[0x1c], mExtraFieldLength); - - if (fwrite(buf, 1, kLFHLen, fp) != kLFHLen) - return UNKNOWN_ERROR; - - /* write filename */ - if (mFileNameLength != 0) { - if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength) - return UNKNOWN_ERROR; - } - - /* write "extra field" */ - if (mExtraFieldLength != 0) { - if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) - return UNKNOWN_ERROR; - } - - return NO_ERROR; -} - - -/* - * Dump the contents of a LocalFileHeader object. - */ -void ZipEntry::LocalFileHeader::dump(void) const -{ - ALOGD(" LocalFileHeader contents:\n"); - ALOGD(" versToExt=%u gpBits=0x%04x compression=%u\n", - mVersionToExtract, mGPBitFlag, mCompressionMethod); - ALOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n", - mLastModFileTime, mLastModFileDate, mCRC32); - ALOGD(" compressedSize=%lu uncompressedSize=%lu\n", - mCompressedSize, mUncompressedSize); - ALOGD(" filenameLen=%u extraLen=%u\n", - mFileNameLength, mExtraFieldLength); - if (mFileName != NULL) - ALOGD(" filename: '%s'\n", mFileName); -} - - -/* - * =========================================================================== - * ZipEntry::CentralDirEntry - * =========================================================================== - */ - -/* - * Read the central dir entry that appears next in the file. - * - * On entry, "fp" should be positioned on the signature bytes for the - * entry. On exit, "fp" will point at the signature word for the next - * entry or for the EOCD. - */ -status_t ZipEntry::CentralDirEntry::read(FILE* fp) -{ - status_t result = NO_ERROR; - unsigned char buf[kCDELen]; - - /* no re-use */ - assert(mFileName == NULL); - assert(mExtraField == NULL); - assert(mFileComment == NULL); - - if (fread(buf, 1, kCDELen, fp) != kCDELen) { - result = UNKNOWN_ERROR; - goto bail; - } - - if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) { - ALOGD("Whoops: didn't find expected signature\n"); - result = UNKNOWN_ERROR; - goto bail; - } - - mVersionMadeBy = ZipEntry::getShortLE(&buf[0x04]); - mVersionToExtract = ZipEntry::getShortLE(&buf[0x06]); - mGPBitFlag = ZipEntry::getShortLE(&buf[0x08]); - mCompressionMethod = ZipEntry::getShortLE(&buf[0x0a]); - mLastModFileTime = ZipEntry::getShortLE(&buf[0x0c]); - mLastModFileDate = ZipEntry::getShortLE(&buf[0x0e]); - mCRC32 = ZipEntry::getLongLE(&buf[0x10]); - mCompressedSize = ZipEntry::getLongLE(&buf[0x14]); - mUncompressedSize = ZipEntry::getLongLE(&buf[0x18]); - mFileNameLength = ZipEntry::getShortLE(&buf[0x1c]); - mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1e]); - mFileCommentLength = ZipEntry::getShortLE(&buf[0x20]); - mDiskNumberStart = ZipEntry::getShortLE(&buf[0x22]); - mInternalAttrs = ZipEntry::getShortLE(&buf[0x24]); - mExternalAttrs = ZipEntry::getLongLE(&buf[0x26]); - mLocalHeaderRelOffset = ZipEntry::getLongLE(&buf[0x2a]); - - // TODO: validate sizes and offsets - - /* grab filename */ - if (mFileNameLength != 0) { - mFileName = new unsigned char[mFileNameLength+1]; - if (mFileName == NULL) { - result = NO_MEMORY; - goto bail; - } - if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) { - result = UNKNOWN_ERROR; - goto bail; - } - mFileName[mFileNameLength] = '\0'; - } - - /* read "extra field" */ - if (mExtraFieldLength != 0) { - mExtraField = new unsigned char[mExtraFieldLength+1]; - if (mExtraField == NULL) { - result = NO_MEMORY; - goto bail; - } - if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) { - result = UNKNOWN_ERROR; - goto bail; - } - mExtraField[mExtraFieldLength] = '\0'; - } - - - /* grab comment, if any */ - if (mFileCommentLength != 0) { - mFileComment = new unsigned char[mFileCommentLength+1]; - if (mFileComment == NULL) { - result = NO_MEMORY; - goto bail; - } - if (fread(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength) - { - result = UNKNOWN_ERROR; - goto bail; - } - mFileComment[mFileCommentLength] = '\0'; - } - -bail: - return result; -} - -/* - * Write a central dir entry. - */ -status_t ZipEntry::CentralDirEntry::write(FILE* fp) -{ - unsigned char buf[kCDELen]; - - ZipEntry::putLongLE(&buf[0x00], kSignature); - ZipEntry::putShortLE(&buf[0x04], mVersionMadeBy); - ZipEntry::putShortLE(&buf[0x06], mVersionToExtract); - ZipEntry::putShortLE(&buf[0x08], mGPBitFlag); - ZipEntry::putShortLE(&buf[0x0a], mCompressionMethod); - ZipEntry::putShortLE(&buf[0x0c], mLastModFileTime); - ZipEntry::putShortLE(&buf[0x0e], mLastModFileDate); - ZipEntry::putLongLE(&buf[0x10], mCRC32); - ZipEntry::putLongLE(&buf[0x14], mCompressedSize); - ZipEntry::putLongLE(&buf[0x18], mUncompressedSize); - ZipEntry::putShortLE(&buf[0x1c], mFileNameLength); - ZipEntry::putShortLE(&buf[0x1e], mExtraFieldLength); - ZipEntry::putShortLE(&buf[0x20], mFileCommentLength); - ZipEntry::putShortLE(&buf[0x22], mDiskNumberStart); - ZipEntry::putShortLE(&buf[0x24], mInternalAttrs); - ZipEntry::putLongLE(&buf[0x26], mExternalAttrs); - ZipEntry::putLongLE(&buf[0x2a], mLocalHeaderRelOffset); - - if (fwrite(buf, 1, kCDELen, fp) != kCDELen) - return UNKNOWN_ERROR; - - /* write filename */ - if (mFileNameLength != 0) { - if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength) - return UNKNOWN_ERROR; - } - - /* write "extra field" */ - if (mExtraFieldLength != 0) { - if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) - return UNKNOWN_ERROR; - } - - /* write comment */ - if (mFileCommentLength != 0) { - if (fwrite(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength) - return UNKNOWN_ERROR; - } - - return NO_ERROR; -} - -/* - * Dump the contents of a CentralDirEntry object. - */ -void ZipEntry::CentralDirEntry::dump(void) const -{ - ALOGD(" CentralDirEntry contents:\n"); - ALOGD(" versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n", - mVersionMadeBy, mVersionToExtract, mGPBitFlag, mCompressionMethod); - ALOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n", - mLastModFileTime, mLastModFileDate, mCRC32); - ALOGD(" compressedSize=%lu uncompressedSize=%lu\n", - mCompressedSize, mUncompressedSize); - ALOGD(" filenameLen=%u extraLen=%u commentLen=%u\n", - mFileNameLength, mExtraFieldLength, mFileCommentLength); - ALOGD(" diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n", - mDiskNumberStart, mInternalAttrs, mExternalAttrs, - mLocalHeaderRelOffset); - - if (mFileName != NULL) - ALOGD(" filename: '%s'\n", mFileName); - if (mFileComment != NULL) - ALOGD(" comment: '%s'\n", mFileComment); -} - diff --git a/tools/aapt/ZipEntry.h b/tools/aapt/ZipEntry.h deleted file mode 100644 index c2f3227..0000000 --- a/tools/aapt/ZipEntry.h +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// Zip archive entries. -// -// The ZipEntry class is tightly meshed with the ZipFile class. -// -#ifndef __LIBS_ZIPENTRY_H -#define __LIBS_ZIPENTRY_H - -#include <utils/Errors.h> - -#include <stdlib.h> -#include <stdio.h> - -namespace android { - -class ZipFile; - -/* - * ZipEntry objects represent a single entry in a Zip archive. - * - * You can use one of these to get or set information about an entry, but - * there are no functions here for accessing the data itself. (We could - * tuck a pointer to the ZipFile in here for convenience, but that raises - * the likelihood of using ZipEntry objects after discarding the ZipFile.) - * - * File information is stored in two places: next to the file data (the Local - * File Header, and possibly a Data Descriptor), and at the end of the file - * (the Central Directory Entry). The two must be kept in sync. - */ -class ZipEntry { -public: - friend class ZipFile; - - ZipEntry(void) - : mDeleted(false), mMarked(false) - {} - ~ZipEntry(void) {} - - /* - * Returns "true" if the data is compressed. - */ - bool isCompressed(void) const { - return mCDE.mCompressionMethod != kCompressStored; - } - int getCompressionMethod(void) const { return mCDE.mCompressionMethod; } - - /* - * Return the uncompressed length. - */ - off_t getUncompressedLen(void) const { return mCDE.mUncompressedSize; } - - /* - * Return the compressed length. For uncompressed data, this returns - * the same thing as getUncompresesdLen(). - */ - off_t getCompressedLen(void) const { return mCDE.mCompressedSize; } - - /* - * Return the offset of the local file header. - */ - off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; } - - /* - * Return the absolute file offset of the start of the compressed or - * uncompressed data. - */ - off_t getFileOffset(void) const { - return mCDE.mLocalHeaderRelOffset + - LocalFileHeader::kLFHLen + - mLFH.mFileNameLength + - mLFH.mExtraFieldLength; - } - - /* - * Return the data CRC. - */ - unsigned long getCRC32(void) const { return mCDE.mCRC32; } - - /* - * Return file modification time in UNIX seconds-since-epoch. - */ - time_t getModWhen(void) const; - - /* - * Return the archived file name. - */ - const char* getFileName(void) const { return (const char*) mCDE.mFileName; } - - /* - * Application-defined "mark". Can be useful when synchronizing the - * contents of an archive with contents on disk. - */ - bool getMarked(void) const { return mMarked; } - void setMarked(bool val) { mMarked = val; } - - /* - * Some basic functions for raw data manipulation. "LE" means - * Little Endian. - */ - static inline unsigned short getShortLE(const unsigned char* buf) { - return buf[0] | (buf[1] << 8); - } - static inline unsigned long getLongLE(const unsigned char* buf) { - return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); - } - static inline void putShortLE(unsigned char* buf, short val) { - buf[0] = (unsigned char) val; - buf[1] = (unsigned char) (val >> 8); - } - static inline void putLongLE(unsigned char* buf, long val) { - buf[0] = (unsigned char) val; - buf[1] = (unsigned char) (val >> 8); - buf[2] = (unsigned char) (val >> 16); - buf[3] = (unsigned char) (val >> 24); - } - - /* defined for Zip archives */ - enum { - kCompressStored = 0, // no compression - // shrunk = 1, - // reduced 1 = 2, - // reduced 2 = 3, - // reduced 3 = 4, - // reduced 4 = 5, - // imploded = 6, - // tokenized = 7, - kCompressDeflated = 8, // standard deflate - // Deflate64 = 9, - // lib imploded = 10, - // reserved = 11, - // bzip2 = 12, - }; - - /* - * Deletion flag. If set, the entry will be removed on the next - * call to "flush". - */ - bool getDeleted(void) const { return mDeleted; } - -protected: - /* - * Initialize the structure from the file, which is pointing at - * our Central Directory entry. - */ - status_t initFromCDE(FILE* fp); - - /* - * Initialize the structure for a new file. We need the filename - * and comment so that we can properly size the LFH area. The - * filename is mandatory, the comment is optional. - */ - void initNew(const char* fileName, const char* comment); - - /* - * Initialize the structure with the contents of a ZipEntry from - * another file. - */ - status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry); - - /* - * Add some pad bytes to the LFH. We do this by adding or resizing - * the "extra" field. - */ - status_t addPadding(int padding); - - /* - * Set information about the data for this entry. - */ - void setDataInfo(long uncompLen, long compLen, unsigned long crc32, - int compressionMethod); - - /* - * Set the modification date. - */ - void setModWhen(time_t when); - - /* - * Set the offset of the local file header, relative to the start of - * the current file. - */ - void setLFHOffset(off_t offset) { - mCDE.mLocalHeaderRelOffset = (long) offset; - } - - /* mark for deletion; used by ZipFile::remove() */ - void setDeleted(void) { mDeleted = true; } - -private: - /* these are private and not defined */ - ZipEntry(const ZipEntry& src); - ZipEntry& operator=(const ZipEntry& src); - - /* returns "true" if the CDE and the LFH agree */ - bool compareHeaders(void) const; - void copyCDEtoLFH(void); - - bool mDeleted; // set if entry is pending deletion - bool mMarked; // app-defined marker - - /* - * Every entry in the Zip archive starts off with one of these. - */ - class LocalFileHeader { - public: - LocalFileHeader(void) : - mVersionToExtract(0), - mGPBitFlag(0), - mCompressionMethod(0), - mLastModFileTime(0), - mLastModFileDate(0), - mCRC32(0), - mCompressedSize(0), - mUncompressedSize(0), - mFileNameLength(0), - mExtraFieldLength(0), - mFileName(NULL), - mExtraField(NULL) - {} - virtual ~LocalFileHeader(void) { - delete[] mFileName; - delete[] mExtraField; - } - - status_t read(FILE* fp); - status_t write(FILE* fp); - - // unsigned long mSignature; - unsigned short mVersionToExtract; - unsigned short mGPBitFlag; - unsigned short mCompressionMethod; - unsigned short mLastModFileTime; - unsigned short mLastModFileDate; - unsigned long mCRC32; - unsigned long mCompressedSize; - unsigned long mUncompressedSize; - unsigned short mFileNameLength; - unsigned short mExtraFieldLength; - unsigned char* mFileName; - unsigned char* mExtraField; - - enum { - kSignature = 0x04034b50, - kLFHLen = 30, // LocalFileHdr len, excl. var fields - }; - - void dump(void) const; - }; - - /* - * Every entry in the Zip archive has one of these in the "central - * directory" at the end of the file. - */ - class CentralDirEntry { - public: - CentralDirEntry(void) : - mVersionMadeBy(0), - mVersionToExtract(0), - mGPBitFlag(0), - mCompressionMethod(0), - mLastModFileTime(0), - mLastModFileDate(0), - mCRC32(0), - mCompressedSize(0), - mUncompressedSize(0), - mFileNameLength(0), - mExtraFieldLength(0), - mFileCommentLength(0), - mDiskNumberStart(0), - mInternalAttrs(0), - mExternalAttrs(0), - mLocalHeaderRelOffset(0), - mFileName(NULL), - mExtraField(NULL), - mFileComment(NULL) - {} - virtual ~CentralDirEntry(void) { - delete[] mFileName; - delete[] mExtraField; - delete[] mFileComment; - } - - status_t read(FILE* fp); - status_t write(FILE* fp); - - // unsigned long mSignature; - unsigned short mVersionMadeBy; - unsigned short mVersionToExtract; - unsigned short mGPBitFlag; - unsigned short mCompressionMethod; - unsigned short mLastModFileTime; - unsigned short mLastModFileDate; - unsigned long mCRC32; - unsigned long mCompressedSize; - unsigned long mUncompressedSize; - unsigned short mFileNameLength; - unsigned short mExtraFieldLength; - unsigned short mFileCommentLength; - unsigned short mDiskNumberStart; - unsigned short mInternalAttrs; - unsigned long mExternalAttrs; - unsigned long mLocalHeaderRelOffset; - unsigned char* mFileName; - unsigned char* mExtraField; - unsigned char* mFileComment; - - void dump(void) const; - - enum { - kSignature = 0x02014b50, - kCDELen = 46, // CentralDirEnt len, excl. var fields - }; - }; - - enum { - //kDataDescriptorSignature = 0x08074b50, // currently unused - kDataDescriptorLen = 16, // four 32-bit fields - - kDefaultVersion = 20, // need deflate, nothing much else - kDefaultMadeBy = 0x0317, // 03=UNIX, 17=spec v2.3 - kUsesDataDescr = 0x0008, // GPBitFlag bit 3 - }; - - LocalFileHeader mLFH; - CentralDirEntry mCDE; -}; - -}; // namespace android - -#endif // __LIBS_ZIPENTRY_H diff --git a/tools/aapt/ZipFile.cpp b/tools/aapt/ZipFile.cpp deleted file mode 100644 index 8057068..0000000 --- a/tools/aapt/ZipFile.cpp +++ /dev/null @@ -1,1297 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// Access to Zip archives. -// - -#define LOG_TAG "zip" - -#include <androidfw/ZipUtils.h> -#include <utils/Log.h> - -#include "ZipFile.h" - -#include <zlib.h> -#define DEF_MEM_LEVEL 8 // normally in zutil.h? - -#include <memory.h> -#include <sys/stat.h> -#include <errno.h> -#include <assert.h> - -using namespace android; - -/* - * Some environments require the "b", some choke on it. - */ -#define FILE_OPEN_RO "rb" -#define FILE_OPEN_RW "r+b" -#define FILE_OPEN_RW_CREATE "w+b" - -/* should live somewhere else? */ -static status_t errnoToStatus(int err) -{ - if (err == ENOENT) - return NAME_NOT_FOUND; - else if (err == EACCES) - return PERMISSION_DENIED; - else - return UNKNOWN_ERROR; -} - -/* - * Open a file and parse its guts. - */ -status_t ZipFile::open(const char* zipFileName, int flags) -{ - bool newArchive = false; - - assert(mZipFp == NULL); // no reopen - - if ((flags & kOpenTruncate)) - flags |= kOpenCreate; // trunc implies create - - if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite)) - return INVALID_OPERATION; // not both - if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite))) - return INVALID_OPERATION; // not neither - if ((flags & kOpenCreate) && !(flags & kOpenReadWrite)) - return INVALID_OPERATION; // create requires write - - if (flags & kOpenTruncate) { - newArchive = true; - } else { - newArchive = (access(zipFileName, F_OK) != 0); - if (!(flags & kOpenCreate) && newArchive) { - /* not creating, must already exist */ - ALOGD("File %s does not exist", zipFileName); - return NAME_NOT_FOUND; - } - } - - /* open the file */ - const char* openflags; - if (flags & kOpenReadWrite) { - if (newArchive) - openflags = FILE_OPEN_RW_CREATE; - else - openflags = FILE_OPEN_RW; - } else { - openflags = FILE_OPEN_RO; - } - mZipFp = fopen(zipFileName, openflags); - if (mZipFp == NULL) { - int err = errno; - ALOGD("fopen failed: %d\n", err); - return errnoToStatus(err); - } - - status_t result; - if (!newArchive) { - /* - * Load the central directory. If that fails, then this probably - * isn't a Zip archive. - */ - result = readCentralDir(); - } else { - /* - * Newly-created. The EndOfCentralDir constructor actually - * sets everything to be the way we want it (all zeroes). We - * set mNeedCDRewrite so that we create *something* if the - * caller doesn't add any files. (We could also just unlink - * the file if it's brand new and nothing was added, but that's - * probably doing more than we really should -- the user might - * have a need for empty zip files.) - */ - mNeedCDRewrite = true; - result = NO_ERROR; - } - - if (flags & kOpenReadOnly) - mReadOnly = true; - else - assert(!mReadOnly); - - return result; -} - -/* - * Return the Nth entry in the archive. - */ -ZipEntry* ZipFile::getEntryByIndex(int idx) const -{ - if (idx < 0 || idx >= (int) mEntries.size()) - return NULL; - - return mEntries[idx]; -} - -/* - * Find an entry by name. - */ -ZipEntry* ZipFile::getEntryByName(const char* fileName) const -{ - /* - * Do a stupid linear string-compare search. - * - * There are various ways to speed this up, especially since it's rare - * to intermingle changes to the archive with "get by name" calls. We - * don't want to sort the mEntries vector itself, however, because - * it's used to recreate the Central Directory. - * - * (Hash table works, parallel list of pointers in sorted order is good.) - */ - int idx; - - for (idx = mEntries.size()-1; idx >= 0; idx--) { - ZipEntry* pEntry = mEntries[idx]; - if (!pEntry->getDeleted() && - strcmp(fileName, pEntry->getFileName()) == 0) - { - return pEntry; - } - } - - return NULL; -} - -/* - * Empty the mEntries vector. - */ -void ZipFile::discardEntries(void) -{ - int count = mEntries.size(); - - while (--count >= 0) - delete mEntries[count]; - - mEntries.clear(); -} - - -/* - * Find the central directory and read the contents. - * - * The fun thing about ZIP archives is that they may or may not be - * readable from start to end. In some cases, notably for archives - * that were written to stdout, the only length information is in the - * central directory at the end of the file. - * - * Of course, the central directory can be followed by a variable-length - * comment field, so we have to scan through it backwards. The comment - * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff - * itself, plus apparently sometimes people throw random junk on the end - * just for the fun of it. - * - * This is all a little wobbly. If the wrong value ends up in the EOCD - * area, we're hosed. This appears to be the way that everbody handles - * it though, so we're in pretty good company if this fails. - */ -status_t ZipFile::readCentralDir(void) -{ - status_t result = NO_ERROR; - unsigned char* buf = NULL; - off_t fileLength, seekStart; - long readAmount; - int i; - - fseek(mZipFp, 0, SEEK_END); - fileLength = ftell(mZipFp); - rewind(mZipFp); - - /* too small to be a ZIP archive? */ - if (fileLength < EndOfCentralDir::kEOCDLen) { - ALOGD("Length is %ld -- too small\n", (long)fileLength); - result = INVALID_OPERATION; - goto bail; - } - - buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch]; - if (buf == NULL) { - ALOGD("Failure allocating %d bytes for EOCD search", - EndOfCentralDir::kMaxEOCDSearch); - result = NO_MEMORY; - goto bail; - } - - if (fileLength > EndOfCentralDir::kMaxEOCDSearch) { - seekStart = fileLength - EndOfCentralDir::kMaxEOCDSearch; - readAmount = EndOfCentralDir::kMaxEOCDSearch; - } else { - seekStart = 0; - readAmount = (long) fileLength; - } - if (fseek(mZipFp, seekStart, SEEK_SET) != 0) { - ALOGD("Failure seeking to end of zip at %ld", (long) seekStart); - result = UNKNOWN_ERROR; - goto bail; - } - - /* read the last part of the file into the buffer */ - if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) { - ALOGD("short file? wanted %ld\n", readAmount); - result = UNKNOWN_ERROR; - goto bail; - } - - /* find the end-of-central-dir magic */ - for (i = readAmount - 4; i >= 0; i--) { - if (buf[i] == 0x50 && - ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature) - { - ALOGV("+++ Found EOCD at buf+%d\n", i); - break; - } - } - if (i < 0) { - ALOGD("EOCD not found, not Zip\n"); - result = INVALID_OPERATION; - goto bail; - } - - /* extract eocd values */ - result = mEOCD.readBuf(buf + i, readAmount - i); - if (result != NO_ERROR) { - ALOGD("Failure reading %ld bytes of EOCD values", readAmount - i); - goto bail; - } - //mEOCD.dump(); - - if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 || - mEOCD.mNumEntries != mEOCD.mTotalNumEntries) - { - ALOGD("Archive spanning not supported\n"); - result = INVALID_OPERATION; - goto bail; - } - - /* - * So far so good. "mCentralDirSize" is the size in bytes of the - * central directory, so we can just seek back that far to find it. - * We can also seek forward mCentralDirOffset bytes from the - * start of the file. - * - * We're not guaranteed to have the rest of the central dir in the - * buffer, nor are we guaranteed that the central dir will have any - * sort of convenient size. We need to skip to the start of it and - * read the header, then the other goodies. - * - * The only thing we really need right now is the file comment, which - * we're hoping to preserve. - */ - if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) { - ALOGD("Failure seeking to central dir offset %ld\n", - mEOCD.mCentralDirOffset); - result = UNKNOWN_ERROR; - goto bail; - } - - /* - * Loop through and read the central dir entries. - */ - ALOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries); - int entry; - for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) { - ZipEntry* pEntry = new ZipEntry; - - result = pEntry->initFromCDE(mZipFp); - if (result != NO_ERROR) { - ALOGD("initFromCDE failed\n"); - delete pEntry; - goto bail; - } - - mEntries.add(pEntry); - } - - - /* - * If all went well, we should now be back at the EOCD. - */ - { - unsigned char checkBuf[4]; - if (fread(checkBuf, 1, 4, mZipFp) != 4) { - ALOGD("EOCD check read failed\n"); - result = INVALID_OPERATION; - goto bail; - } - if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) { - ALOGD("EOCD read check failed\n"); - result = UNKNOWN_ERROR; - goto bail; - } - ALOGV("+++ EOCD read check passed\n"); - } - -bail: - delete[] buf; - return result; -} - - -/* - * Add a new file to the archive. - * - * This requires creating and populating a ZipEntry structure, and copying - * the data into the file at the appropriate position. The "appropriate - * position" is the current location of the central directory, which we - * casually overwrite (we can put it back later). - * - * If we were concerned about safety, we would want to make all changes - * in a temp file and then overwrite the original after everything was - * safely written. Not really a concern for us. - */ -status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size, - const char* storageName, int sourceType, int compressionMethod, - ZipEntry** ppEntry) -{ - ZipEntry* pEntry = NULL; - status_t result = NO_ERROR; - long lfhPosn, startPosn, endPosn, uncompressedLen; - FILE* inputFp = NULL; - unsigned long crc; - time_t modWhen; - - if (mReadOnly) - return INVALID_OPERATION; - - assert(compressionMethod == ZipEntry::kCompressDeflated || - compressionMethod == ZipEntry::kCompressStored); - - /* make sure we're in a reasonable state */ - assert(mZipFp != NULL); - assert(mEntries.size() == mEOCD.mTotalNumEntries); - - /* make sure it doesn't already exist */ - if (getEntryByName(storageName) != NULL) - return ALREADY_EXISTS; - - if (!data) { - inputFp = fopen(fileName, FILE_OPEN_RO); - if (inputFp == NULL) - return errnoToStatus(errno); - } - - if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) { - result = UNKNOWN_ERROR; - goto bail; - } - - pEntry = new ZipEntry; - pEntry->initNew(storageName, NULL); - - /* - * From here on out, failures are more interesting. - */ - mNeedCDRewrite = true; - - /* - * Write the LFH, even though it's still mostly blank. We need it - * as a place-holder. In theory the LFH isn't necessary, but in - * practice some utilities demand it. - */ - lfhPosn = ftell(mZipFp); - pEntry->mLFH.write(mZipFp); - startPosn = ftell(mZipFp); - - /* - * Copy the data in, possibly compressing it as we go. - */ - if (sourceType == ZipEntry::kCompressStored) { - if (compressionMethod == ZipEntry::kCompressDeflated) { - bool failed = false; - result = compressFpToFp(mZipFp, inputFp, data, size, &crc); - if (result != NO_ERROR) { - ALOGD("compression failed, storing\n"); - failed = true; - } else { - /* - * Make sure it has compressed "enough". This probably ought - * to be set through an API call, but I don't expect our - * criteria to change over time. - */ - long src = inputFp ? ftell(inputFp) : size; - long dst = ftell(mZipFp) - startPosn; - if (dst + (dst / 10) > src) { - ALOGD("insufficient compression (src=%ld dst=%ld), storing\n", - src, dst); - failed = true; - } - } - - if (failed) { - compressionMethod = ZipEntry::kCompressStored; - if (inputFp) rewind(inputFp); - fseek(mZipFp, startPosn, SEEK_SET); - /* fall through to kCompressStored case */ - } - } - /* handle "no compression" request, or failed compression from above */ - if (compressionMethod == ZipEntry::kCompressStored) { - if (inputFp) { - result = copyFpToFp(mZipFp, inputFp, &crc); - } else { - result = copyDataToFp(mZipFp, data, size, &crc); - } - if (result != NO_ERROR) { - // don't need to truncate; happens in CDE rewrite - ALOGD("failed copying data in\n"); - goto bail; - } - } - - // currently seeked to end of file - uncompressedLen = inputFp ? ftell(inputFp) : size; - } else if (sourceType == ZipEntry::kCompressDeflated) { - /* we should support uncompressed-from-compressed, but it's not - * important right now */ - assert(compressionMethod == ZipEntry::kCompressDeflated); - - bool scanResult; - int method; - long compressedLen; - - scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen, - &compressedLen, &crc); - if (!scanResult || method != ZipEntry::kCompressDeflated) { - ALOGD("this isn't a deflated gzip file?"); - result = UNKNOWN_ERROR; - goto bail; - } - - result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL); - if (result != NO_ERROR) { - ALOGD("failed copying gzip data in\n"); - goto bail; - } - } else { - assert(false); - result = UNKNOWN_ERROR; - goto bail; - } - - /* - * We could write the "Data Descriptor", but there doesn't seem to - * be any point since we're going to go back and write the LFH. - * - * Update file offsets. - */ - endPosn = ftell(mZipFp); // seeked to end of compressed data - - /* - * Success! Fill out new values. - */ - pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc, - compressionMethod); - modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp)); - pEntry->setModWhen(modWhen); - pEntry->setLFHOffset(lfhPosn); - mEOCD.mNumEntries++; - mEOCD.mTotalNumEntries++; - mEOCD.mCentralDirSize = 0; // mark invalid; set by flush() - mEOCD.mCentralDirOffset = endPosn; - - /* - * Go back and write the LFH. - */ - if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) { - result = UNKNOWN_ERROR; - goto bail; - } - pEntry->mLFH.write(mZipFp); - - /* - * Add pEntry to the list. - */ - mEntries.add(pEntry); - if (ppEntry != NULL) - *ppEntry = pEntry; - pEntry = NULL; - -bail: - if (inputFp != NULL) - fclose(inputFp); - delete pEntry; - return result; -} - -/* - * Add an entry by copying it from another zip file. If "padding" is - * nonzero, the specified number of bytes will be added to the "extra" - * field in the header. - * - * If "ppEntry" is non-NULL, a pointer to the new entry will be returned. - */ -status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry, - int padding, ZipEntry** ppEntry) -{ - ZipEntry* pEntry = NULL; - status_t result; - long lfhPosn, endPosn; - - if (mReadOnly) - return INVALID_OPERATION; - - /* make sure we're in a reasonable state */ - assert(mZipFp != NULL); - assert(mEntries.size() == mEOCD.mTotalNumEntries); - - if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) { - result = UNKNOWN_ERROR; - goto bail; - } - - pEntry = new ZipEntry; - if (pEntry == NULL) { - result = NO_MEMORY; - goto bail; - } - - result = pEntry->initFromExternal(pSourceZip, pSourceEntry); - if (result != NO_ERROR) - goto bail; - if (padding != 0) { - result = pEntry->addPadding(padding); - if (result != NO_ERROR) - goto bail; - } - - /* - * From here on out, failures are more interesting. - */ - mNeedCDRewrite = true; - - /* - * Write the LFH. Since we're not recompressing the data, we already - * have all of the fields filled out. - */ - lfhPosn = ftell(mZipFp); - pEntry->mLFH.write(mZipFp); - - /* - * Copy the data over. - * - * If the "has data descriptor" flag is set, we want to copy the DD - * fields as well. This is a fixed-size area immediately following - * the data. - */ - if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0) - { - result = UNKNOWN_ERROR; - goto bail; - } - - off_t copyLen; - copyLen = pSourceEntry->getCompressedLen(); - if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0) - copyLen += ZipEntry::kDataDescriptorLen; - - if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL) - != NO_ERROR) - { - ALOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName); - result = UNKNOWN_ERROR; - goto bail; - } - - /* - * Update file offsets. - */ - endPosn = ftell(mZipFp); - - /* - * Success! Fill out new values. - */ - pEntry->setLFHOffset(lfhPosn); // sets mCDE.mLocalHeaderRelOffset - mEOCD.mNumEntries++; - mEOCD.mTotalNumEntries++; - mEOCD.mCentralDirSize = 0; // mark invalid; set by flush() - mEOCD.mCentralDirOffset = endPosn; - - /* - * Add pEntry to the list. - */ - mEntries.add(pEntry); - if (ppEntry != NULL) - *ppEntry = pEntry; - pEntry = NULL; - - result = NO_ERROR; - -bail: - delete pEntry; - return result; -} - -/* - * Copy all of the bytes in "src" to "dst". - * - * On exit, "srcFp" will be seeked to the end of the file, and "dstFp" - * will be seeked immediately past the data. - */ -status_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32) -{ - unsigned char tmpBuf[32768]; - size_t count; - - *pCRC32 = crc32(0L, Z_NULL, 0); - - while (1) { - count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp); - if (ferror(srcFp) || ferror(dstFp)) - return errnoToStatus(errno); - if (count == 0) - break; - - *pCRC32 = crc32(*pCRC32, tmpBuf, count); - - if (fwrite(tmpBuf, 1, count, dstFp) != count) { - ALOGD("fwrite %d bytes failed\n", (int) count); - return UNKNOWN_ERROR; - } - } - - return NO_ERROR; -} - -/* - * Copy all of the bytes in "src" to "dst". - * - * On exit, "dstFp" will be seeked immediately past the data. - */ -status_t ZipFile::copyDataToFp(FILE* dstFp, - const void* data, size_t size, unsigned long* pCRC32) -{ - size_t count; - - *pCRC32 = crc32(0L, Z_NULL, 0); - if (size > 0) { - *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size); - if (fwrite(data, 1, size, dstFp) != size) { - ALOGD("fwrite %d bytes failed\n", (int) size); - return UNKNOWN_ERROR; - } - } - - return NO_ERROR; -} - -/* - * Copy some of the bytes in "src" to "dst". - * - * If "pCRC32" is NULL, the CRC will not be computed. - * - * On exit, "srcFp" will be seeked to the end of the file, and "dstFp" - * will be seeked immediately past the data just written. - */ -status_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length, - unsigned long* pCRC32) -{ - unsigned char tmpBuf[32768]; - size_t count; - - if (pCRC32 != NULL) - *pCRC32 = crc32(0L, Z_NULL, 0); - - while (length) { - long readSize; - - readSize = sizeof(tmpBuf); - if (readSize > length) - readSize = length; - - count = fread(tmpBuf, 1, readSize, srcFp); - if ((long) count != readSize) { // error or unexpected EOF - ALOGD("fread %d bytes failed\n", (int) readSize); - return UNKNOWN_ERROR; - } - - if (pCRC32 != NULL) - *pCRC32 = crc32(*pCRC32, tmpBuf, count); - - if (fwrite(tmpBuf, 1, count, dstFp) != count) { - ALOGD("fwrite %d bytes failed\n", (int) count); - return UNKNOWN_ERROR; - } - - length -= readSize; - } - - return NO_ERROR; -} - -/* - * Compress all of the data in "srcFp" and write it to "dstFp". - * - * On exit, "srcFp" will be seeked to the end of the file, and "dstFp" - * will be seeked immediately past the compressed data. - */ -status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp, - const void* data, size_t size, unsigned long* pCRC32) -{ - status_t result = NO_ERROR; - const size_t kBufSize = 32768; - unsigned char* inBuf = NULL; - unsigned char* outBuf = NULL; - z_stream zstream; - bool atEof = false; // no feof() aviailable yet - unsigned long crc; - int zerr; - - /* - * Create an input buffer and an output buffer. - */ - inBuf = new unsigned char[kBufSize]; - outBuf = new unsigned char[kBufSize]; - if (inBuf == NULL || outBuf == NULL) { - result = NO_MEMORY; - goto bail; - } - - /* - * Initialize the zlib stream. - */ - memset(&zstream, 0, sizeof(zstream)); - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.opaque = Z_NULL; - zstream.next_in = NULL; - zstream.avail_in = 0; - zstream.next_out = outBuf; - zstream.avail_out = kBufSize; - zstream.data_type = Z_UNKNOWN; - - zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION, - Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); - if (zerr != Z_OK) { - result = UNKNOWN_ERROR; - if (zerr == Z_VERSION_ERROR) { - ALOGE("Installed zlib is not compatible with linked version (%s)\n", - ZLIB_VERSION); - } else { - ALOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr); - } - goto bail; - } - - crc = crc32(0L, Z_NULL, 0); - - /* - * Loop while we have data. - */ - do { - size_t getSize; - int flush; - - /* only read if the input buffer is empty */ - if (zstream.avail_in == 0 && !atEof) { - ALOGV("+++ reading %d bytes\n", (int)kBufSize); - if (data) { - getSize = size > kBufSize ? kBufSize : size; - memcpy(inBuf, data, getSize); - data = ((const char*)data) + getSize; - size -= getSize; - } else { - getSize = fread(inBuf, 1, kBufSize, srcFp); - if (ferror(srcFp)) { - ALOGD("deflate read failed (errno=%d)\n", errno); - goto z_bail; - } - } - if (getSize < kBufSize) { - ALOGV("+++ got %d bytes, EOF reached\n", - (int)getSize); - atEof = true; - } - - crc = crc32(crc, inBuf, getSize); - - zstream.next_in = inBuf; - zstream.avail_in = getSize; - } - - if (atEof) - flush = Z_FINISH; /* tell zlib that we're done */ - else - flush = Z_NO_FLUSH; /* more to come! */ - - zerr = deflate(&zstream, flush); - if (zerr != Z_OK && zerr != Z_STREAM_END) { - ALOGD("zlib deflate call failed (zerr=%d)\n", zerr); - result = UNKNOWN_ERROR; - goto z_bail; - } - - /* write when we're full or when we're done */ - if (zstream.avail_out == 0 || - (zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize)) - { - ALOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf)); - if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) != - (size_t)(zstream.next_out - outBuf)) - { - ALOGD("write %d failed in deflate\n", - (int) (zstream.next_out - outBuf)); - goto z_bail; - } - - zstream.next_out = outBuf; - zstream.avail_out = kBufSize; - } - } while (zerr == Z_OK); - - assert(zerr == Z_STREAM_END); /* other errors should've been caught */ - - *pCRC32 = crc; - -z_bail: - deflateEnd(&zstream); /* free up any allocated structures */ - -bail: - delete[] inBuf; - delete[] outBuf; - - return result; -} - -/* - * Mark an entry as deleted. - * - * We will eventually need to crunch the file down, but if several files - * are being removed (perhaps as part of an "update" process) we can make - * things considerably faster by deferring the removal to "flush" time. - */ -status_t ZipFile::remove(ZipEntry* pEntry) -{ - /* - * Should verify that pEntry is actually part of this archive, and - * not some stray ZipEntry from a different file. - */ - - /* mark entry as deleted, and mark archive as dirty */ - pEntry->setDeleted(); - mNeedCDRewrite = true; - return NO_ERROR; -} - -/* - * Flush any pending writes. - * - * In particular, this will crunch out deleted entries, and write the - * Central Directory and EOCD if we have stomped on them. - */ -status_t ZipFile::flush(void) -{ - status_t result = NO_ERROR; - long eocdPosn; - int i, count; - - if (mReadOnly) - return INVALID_OPERATION; - if (!mNeedCDRewrite) - return NO_ERROR; - - assert(mZipFp != NULL); - - result = crunchArchive(); - if (result != NO_ERROR) - return result; - - if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) - return UNKNOWN_ERROR; - - count = mEntries.size(); - for (i = 0; i < count; i++) { - ZipEntry* pEntry = mEntries[i]; - pEntry->mCDE.write(mZipFp); - } - - eocdPosn = ftell(mZipFp); - mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset; - - mEOCD.write(mZipFp); - - /* - * If we had some stuff bloat up during compression and get replaced - * with plain files, or if we deleted some entries, there's a lot - * of wasted space at the end of the file. Remove it now. - */ - if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) { - ALOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno)); - // not fatal - } - - /* should we clear the "newly added" flag in all entries now? */ - - mNeedCDRewrite = false; - return NO_ERROR; -} - -/* - * Crunch deleted files out of an archive by shifting the later files down. - * - * Because we're not using a temp file, we do the operation inside the - * current file. - */ -status_t ZipFile::crunchArchive(void) -{ - status_t result = NO_ERROR; - int i, count; - long delCount, adjust; - -#if 0 - printf("CONTENTS:\n"); - for (i = 0; i < (int) mEntries.size(); i++) { - printf(" %d: lfhOff=%ld del=%d\n", - i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted()); - } - printf(" END is %ld\n", (long) mEOCD.mCentralDirOffset); -#endif - - /* - * Roll through the set of files, shifting them as appropriate. We - * could probably get a slight performance improvement by sliding - * multiple files down at once (because we could use larger reads - * when operating on batches of small files), but it's not that useful. - */ - count = mEntries.size(); - delCount = adjust = 0; - for (i = 0; i < count; i++) { - ZipEntry* pEntry = mEntries[i]; - long span; - - if (pEntry->getLFHOffset() != 0) { - long nextOffset; - - /* Get the length of this entry by finding the offset - * of the next entry. Directory entries don't have - * file offsets, so we need to find the next non-directory - * entry. - */ - nextOffset = 0; - for (int ii = i+1; nextOffset == 0 && ii < count; ii++) - nextOffset = mEntries[ii]->getLFHOffset(); - if (nextOffset == 0) - nextOffset = mEOCD.mCentralDirOffset; - span = nextOffset - pEntry->getLFHOffset(); - - assert(span >= ZipEntry::LocalFileHeader::kLFHLen); - } else { - /* This is a directory entry. It doesn't have - * any actual file contents, so there's no need to - * move anything. - */ - span = 0; - } - - //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n", - // i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count); - - if (pEntry->getDeleted()) { - adjust += span; - delCount++; - - delete pEntry; - mEntries.removeAt(i); - - /* adjust loop control */ - count--; - i--; - } else if (span != 0 && adjust > 0) { - /* shuffle this entry back */ - //printf("+++ Shuffling '%s' back %ld\n", - // pEntry->getFileName(), adjust); - result = filemove(mZipFp, pEntry->getLFHOffset() - adjust, - pEntry->getLFHOffset(), span); - if (result != NO_ERROR) { - /* this is why you use a temp file */ - ALOGE("error during crunch - archive is toast\n"); - return result; - } - - pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust); - } - } - - /* - * Fix EOCD info. We have to wait until the end to do some of this - * because we use mCentralDirOffset to determine "span" for the - * last entry. - */ - mEOCD.mCentralDirOffset -= adjust; - mEOCD.mNumEntries -= delCount; - mEOCD.mTotalNumEntries -= delCount; - mEOCD.mCentralDirSize = 0; // mark invalid; set by flush() - - assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries); - assert(mEOCD.mNumEntries == count); - - return result; -} - -/* - * Works like memmove(), but on pieces of a file. - */ -status_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n) -{ - if (dst == src || n <= 0) - return NO_ERROR; - - unsigned char readBuf[32768]; - - if (dst < src) { - /* shift stuff toward start of file; must read from start */ - while (n != 0) { - size_t getSize = sizeof(readBuf); - if (getSize > n) - getSize = n; - - if (fseek(fp, (long) src, SEEK_SET) != 0) { - ALOGD("filemove src seek %ld failed\n", (long) src); - return UNKNOWN_ERROR; - } - - if (fread(readBuf, 1, getSize, fp) != getSize) { - ALOGD("filemove read %ld off=%ld failed\n", - (long) getSize, (long) src); - return UNKNOWN_ERROR; - } - - if (fseek(fp, (long) dst, SEEK_SET) != 0) { - ALOGD("filemove dst seek %ld failed\n", (long) dst); - return UNKNOWN_ERROR; - } - - if (fwrite(readBuf, 1, getSize, fp) != getSize) { - ALOGD("filemove write %ld off=%ld failed\n", - (long) getSize, (long) dst); - return UNKNOWN_ERROR; - } - - src += getSize; - dst += getSize; - n -= getSize; - } - } else { - /* shift stuff toward end of file; must read from end */ - assert(false); // write this someday, maybe - return UNKNOWN_ERROR; - } - - return NO_ERROR; -} - - -/* - * Get the modification time from a file descriptor. - */ -time_t ZipFile::getModTime(int fd) -{ - struct stat sb; - - if (fstat(fd, &sb) < 0) { - ALOGD("HEY: fstat on fd %d failed\n", fd); - return (time_t) -1; - } - - return sb.st_mtime; -} - - -#if 0 /* this is a bad idea */ -/* - * Get a copy of the Zip file descriptor. - * - * We don't allow this if the file was opened read-write because we tend - * to leave the file contents in an uncertain state between calls to - * flush(). The duplicated file descriptor should only be valid for reads. - */ -int ZipFile::getZipFd(void) const -{ - if (!mReadOnly) - return INVALID_OPERATION; - assert(mZipFp != NULL); - - int fd; - fd = dup(fileno(mZipFp)); - if (fd < 0) { - ALOGD("didn't work, errno=%d\n", errno); - } - - return fd; -} -#endif - - -#if 0 -/* - * Expand data. - */ -bool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const -{ - return false; -} -#endif - -// free the memory when you're done -void* ZipFile::uncompress(const ZipEntry* entry) -{ - size_t unlen = entry->getUncompressedLen(); - size_t clen = entry->getCompressedLen(); - - void* buf = malloc(unlen); - if (buf == NULL) { - return NULL; - } - - fseek(mZipFp, 0, SEEK_SET); - - off_t offset = entry->getFileOffset(); - if (fseek(mZipFp, offset, SEEK_SET) != 0) { - goto bail; - } - - switch (entry->getCompressionMethod()) - { - case ZipEntry::kCompressStored: { - ssize_t amt = fread(buf, 1, unlen, mZipFp); - if (amt != (ssize_t)unlen) { - goto bail; - } -#if 0 - printf("data...\n"); - const unsigned char* p = (unsigned char*)buf; - const unsigned char* end = p+unlen; - for (int i=0; i<32 && p < end; i++) { - printf("0x%08x ", (int)(offset+(i*0x10))); - for (int j=0; j<0x10 && p < end; j++) { - printf(" %02x", *p); - p++; - } - printf("\n"); - } -#endif - - } - break; - case ZipEntry::kCompressDeflated: { - if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) { - goto bail; - } - } - break; - default: - goto bail; - } - return buf; - -bail: - free(buf); - return NULL; -} - - -/* - * =========================================================================== - * ZipFile::EndOfCentralDir - * =========================================================================== - */ - -/* - * Read the end-of-central-dir fields. - * - * "buf" should be positioned at the EOCD signature, and should contain - * the entire EOCD area including the comment. - */ -status_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len) -{ - /* don't allow re-use */ - assert(mComment == NULL); - - if (len < kEOCDLen) { - /* looks like ZIP file got truncated */ - ALOGD(" Zip EOCD: expected >= %d bytes, found %d\n", - kEOCDLen, len); - return INVALID_OPERATION; - } - - /* this should probably be an assert() */ - if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) - return UNKNOWN_ERROR; - - mDiskNumber = ZipEntry::getShortLE(&buf[0x04]); - mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]); - mNumEntries = ZipEntry::getShortLE(&buf[0x08]); - mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]); - mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]); - mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]); - mCommentLen = ZipEntry::getShortLE(&buf[0x14]); - - // TODO: validate mCentralDirOffset - - if (mCommentLen > 0) { - if (kEOCDLen + mCommentLen > len) { - ALOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n", - kEOCDLen, mCommentLen, len); - return UNKNOWN_ERROR; - } - mComment = new unsigned char[mCommentLen]; - memcpy(mComment, buf + kEOCDLen, mCommentLen); - } - - return NO_ERROR; -} - -/* - * Write an end-of-central-directory section. - */ -status_t ZipFile::EndOfCentralDir::write(FILE* fp) -{ - unsigned char buf[kEOCDLen]; - - ZipEntry::putLongLE(&buf[0x00], kSignature); - ZipEntry::putShortLE(&buf[0x04], mDiskNumber); - ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir); - ZipEntry::putShortLE(&buf[0x08], mNumEntries); - ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries); - ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize); - ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset); - ZipEntry::putShortLE(&buf[0x14], mCommentLen); - - if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen) - return UNKNOWN_ERROR; - if (mCommentLen > 0) { - assert(mComment != NULL); - if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen) - return UNKNOWN_ERROR; - } - - return NO_ERROR; -} - -/* - * Dump the contents of an EndOfCentralDir object. - */ -void ZipFile::EndOfCentralDir::dump(void) const -{ - ALOGD(" EndOfCentralDir contents:\n"); - ALOGD(" diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n", - mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries); - ALOGD(" centDirSize=%lu centDirOff=%lu commentLen=%u\n", - mCentralDirSize, mCentralDirOffset, mCommentLen); -} - diff --git a/tools/aapt/ZipFile.h b/tools/aapt/ZipFile.h deleted file mode 100644 index 7877550..0000000 --- a/tools/aapt/ZipFile.h +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// General-purpose Zip archive access. This class allows both reading and -// writing to Zip archives, including deletion of existing entries. -// -#ifndef __LIBS_ZIPFILE_H -#define __LIBS_ZIPFILE_H - -#include <utils/Vector.h> -#include <utils/Errors.h> -#include <stdio.h> - -#include "ZipEntry.h" - -namespace android { - -/* - * Manipulate a Zip archive. - * - * Some changes will not be visible in the until until "flush" is called. - * - * The correct way to update a file archive is to make all changes to a - * copy of the archive in a temporary file, and then unlink/rename over - * the original after everything completes. Because we're only interested - * in using this for packaging, we don't worry about such things. Crashing - * after making changes and before flush() completes could leave us with - * an unusable Zip archive. - */ -class ZipFile { -public: - ZipFile(void) - : mZipFp(NULL), mReadOnly(false), mNeedCDRewrite(false) - {} - ~ZipFile(void) { - if (!mReadOnly) - flush(); - if (mZipFp != NULL) - fclose(mZipFp); - discardEntries(); - } - - /* - * Open a new or existing archive. - */ - enum { - kOpenReadOnly = 0x01, - kOpenReadWrite = 0x02, - kOpenCreate = 0x04, // create if it doesn't exist - kOpenTruncate = 0x08, // if it exists, empty it - }; - status_t open(const char* zipFileName, int flags); - - /* - * Add a file to the end of the archive. Specify whether you want the - * library to try to store it compressed. - * - * If "storageName" is specified, the archive will use that instead - * of "fileName". - * - * If there is already an entry with the same name, the call fails. - * Existing entries with the same name must be removed first. - * - * If "ppEntry" is non-NULL, a pointer to the new entry will be returned. - */ - status_t add(const char* fileName, int compressionMethod, - ZipEntry** ppEntry) - { - return add(fileName, fileName, compressionMethod, ppEntry); - } - status_t add(const char* fileName, const char* storageName, - int compressionMethod, ZipEntry** ppEntry) - { - return addCommon(fileName, NULL, 0, storageName, - ZipEntry::kCompressStored, - compressionMethod, ppEntry); - } - - /* - * Add a file that is already compressed with gzip. - * - * If "ppEntry" is non-NULL, a pointer to the new entry will be returned. - */ - status_t addGzip(const char* fileName, const char* storageName, - ZipEntry** ppEntry) - { - return addCommon(fileName, NULL, 0, storageName, - ZipEntry::kCompressDeflated, - ZipEntry::kCompressDeflated, ppEntry); - } - - /* - * Add a file from an in-memory data buffer. - * - * If "ppEntry" is non-NULL, a pointer to the new entry will be returned. - */ - status_t add(const void* data, size_t size, const char* storageName, - int compressionMethod, ZipEntry** ppEntry) - { - return addCommon(NULL, data, size, storageName, - ZipEntry::kCompressStored, - compressionMethod, ppEntry); - } - - /* - * Add an entry by copying it from another zip file. If "padding" is - * nonzero, the specified number of bytes will be added to the "extra" - * field in the header. - * - * If "ppEntry" is non-NULL, a pointer to the new entry will be returned. - */ - status_t add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry, - int padding, ZipEntry** ppEntry); - - /* - * Mark an entry as having been removed. It is not actually deleted - * from the archive or our internal data structures until flush() is - * called. - */ - status_t remove(ZipEntry* pEntry); - - /* - * Flush changes. If mNeedCDRewrite is set, this writes the central dir. - */ - status_t flush(void); - - /* - * Expand the data into the buffer provided. The buffer must hold - * at least <uncompressed len> bytes. Variation expands directly - * to a file. - * - * Returns "false" if an error was encountered in the compressed data. - */ - //bool uncompress(const ZipEntry* pEntry, void* buf) const; - //bool uncompress(const ZipEntry* pEntry, FILE* fp) const; - void* uncompress(const ZipEntry* pEntry); - - /* - * Get an entry, by name. Returns NULL if not found. - * - * Does not return entries pending deletion. - */ - ZipEntry* getEntryByName(const char* fileName) const; - - /* - * Get the Nth entry in the archive. - * - * This will return an entry that is pending deletion. - */ - int getNumEntries(void) const { return mEntries.size(); } - ZipEntry* getEntryByIndex(int idx) const; - -private: - /* these are private and not defined */ - ZipFile(const ZipFile& src); - ZipFile& operator=(const ZipFile& src); - - class EndOfCentralDir { - public: - EndOfCentralDir(void) : - mDiskNumber(0), - mDiskWithCentralDir(0), - mNumEntries(0), - mTotalNumEntries(0), - mCentralDirSize(0), - mCentralDirOffset(0), - mCommentLen(0), - mComment(NULL) - {} - virtual ~EndOfCentralDir(void) { - delete[] mComment; - } - - status_t readBuf(const unsigned char* buf, int len); - status_t write(FILE* fp); - - //unsigned long mSignature; - unsigned short mDiskNumber; - unsigned short mDiskWithCentralDir; - unsigned short mNumEntries; - unsigned short mTotalNumEntries; - unsigned long mCentralDirSize; - unsigned long mCentralDirOffset; // offset from first disk - unsigned short mCommentLen; - unsigned char* mComment; - - enum { - kSignature = 0x06054b50, - kEOCDLen = 22, // EndOfCentralDir len, excl. comment - - kMaxCommentLen = 65535, // longest possible in ushort - kMaxEOCDSearch = kMaxCommentLen + EndOfCentralDir::kEOCDLen, - - }; - - void dump(void) const; - }; - - - /* read all entries in the central dir */ - status_t readCentralDir(void); - - /* crunch deleted entries out */ - status_t crunchArchive(void); - - /* clean up mEntries */ - void discardEntries(void); - - /* common handler for all "add" functions */ - status_t addCommon(const char* fileName, const void* data, size_t size, - const char* storageName, int sourceType, int compressionMethod, - ZipEntry** ppEntry); - - /* copy all of "srcFp" into "dstFp" */ - status_t copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32); - /* copy all of "data" into "dstFp" */ - status_t copyDataToFp(FILE* dstFp, - const void* data, size_t size, unsigned long* pCRC32); - /* copy some of "srcFp" into "dstFp" */ - status_t copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length, - unsigned long* pCRC32); - /* like memmove(), but on parts of a single file */ - status_t filemove(FILE* fp, off_t dest, off_t src, size_t n); - /* compress all of "srcFp" into "dstFp", using Deflate */ - status_t compressFpToFp(FILE* dstFp, FILE* srcFp, - const void* data, size_t size, unsigned long* pCRC32); - - /* get modification date from a file descriptor */ - time_t getModTime(int fd); - - /* - * We use stdio FILE*, which gives us buffering but makes dealing - * with files >2GB awkward. Until we support Zip64, we're fine. - */ - FILE* mZipFp; // Zip file pointer - - /* one of these per file */ - EndOfCentralDir mEOCD; - - /* did we open this read-only? */ - bool mReadOnly; - - /* set this when we trash the central dir */ - bool mNeedCDRewrite; - - /* - * One ZipEntry per entry in the zip file. I'm using pointers instead - * of objects because it's easier than making operator= work for the - * classes and sub-classes. - */ - Vector<ZipEntry*> mEntries; -}; - -}; // namespace android - -#endif // __LIBS_ZIPFILE_H diff --git a/tools/aapt/printapk.cpp b/tools/aapt/printapk.cpp deleted file mode 100644 index 4cf73d8..0000000 --- a/tools/aapt/printapk.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include <utils/ResourceTypes.h> -#include <utils/String8.h> -#include <utils/String16.h> -#include <zipfile/zipfile.h> -#include <stdio.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdlib.h> - -using namespace android; - -static int -usage() -{ - fprintf(stderr, - "usage: apk APKFILE\n" - "\n" - "APKFILE an android packge file produced by aapt.\n" - ); - return 1; -} - - -int -main(int argc, char** argv) -{ - const char* filename; - int fd; - ssize_t amt; - off_t size; - void* buf; - zipfile_t zip; - zipentry_t entry; - void* cookie; - void* resfile; - int bufsize; - int err; - - if (argc != 2) { - return usage(); - } - - filename = argv[1]; - fd = open(filename, O_RDONLY); - if (fd == -1) { - fprintf(stderr, "apk: couldn't open file for read: %s\n", filename); - return 1; - } - - size = lseek(fd, 0, SEEK_END); - amt = lseek(fd, 0, SEEK_SET); - - if (size < 0 || amt < 0) { - fprintf(stderr, "apk: error determining file size: %s\n", filename); - return 1; - } - - buf = malloc(size); - if (buf == NULL) { - fprintf(stderr, "apk: file too big: %s\n", filename); - return 1; - } - - amt = read(fd, buf, size); - if (amt != size) { - fprintf(stderr, "apk: error reading file: %s\n", filename); - return 1; - } - - close(fd); - - zip = init_zipfile(buf, size); - if (zip == NULL) { - fprintf(stderr, "apk: file doesn't seem to be a zip file: %s\n", - filename); - return 1; - } - - printf("files:\n"); - cookie = NULL; - while ((entry = iterate_zipfile(zip, &cookie))) { - char* name = get_zipentry_name(entry); - printf(" %s\n", name); - free(name); - } - - entry = lookup_zipentry(zip, "resources.arsc"); - if (entry != NULL) { - size = get_zipentry_size(entry); - bufsize = size + (size / 1000) + 1; - resfile = malloc(bufsize); - - err = decompress_zipentry(entry, resfile, bufsize); - if (err != 0) { - fprintf(stderr, "apk: error decompressing resources.arsc"); - return 1; - } - - ResTable res(resfile, size, resfile); - res.print(); -#if 0 - size_t tableCount = res.getTableCount(); - printf("Tables: %d\n", (int)tableCount); - for (size_t tableIndex=0; tableIndex<tableCount; tableIndex++) { - const ResStringPool* strings = res.getTableStringBlock(tableIndex); - size_t stringCount = strings->size(); - for (size_t stringIndex=0; stringIndex<stringCount; stringIndex++) { - size_t len; - const char16_t* ch = strings->stringAt(stringIndex, &len); - String8 s(String16(ch, len)); - printf(" [%3d] %s\n", (int)stringIndex, s.string()); - } - } - - size_t basePackageCount = res.getBasePackageCount(); - printf("Base Packages: %d\n", (int)basePackageCount); - for (size_t bpIndex=0; bpIndex<basePackageCount; bpIndex++) { - const char16_t* ch = res.getBasePackageName(bpIndex); - String8 s = String8(String16(ch)); - printf(" [%3d] %s\n", (int)bpIndex, s.string()); - } -#endif - } - - - return 0; -} diff --git a/tools/aapt/pseudolocalize.cpp b/tools/aapt/pseudolocalize.cpp deleted file mode 100644 index 9e50c5a..0000000 --- a/tools/aapt/pseudolocalize.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include "pseudolocalize.h" - -using namespace std; - -static const char* -pseudolocalize_char(char c) -{ - switch (c) { - case 'a': return "\xc4\x83"; - case 'b': return "\xcf\x84"; - case 'c': return "\xc4\x8b"; - case 'd': return "\xc4\x8f"; - case 'e': return "\xc4\x99"; - case 'f': return "\xc6\x92"; - case 'g': return "\xc4\x9d"; - case 'h': return "\xd1\x9b"; - case 'i': return "\xcf\x8a"; - case 'j': return "\xc4\xb5"; - case 'k': return "\xc4\xb8"; - case 'l': return "\xc4\xba"; - case 'm': return "\xe1\xb8\xbf"; - case 'n': return "\xd0\xb8"; - case 'o': return "\xcf\x8c"; - case 'p': return "\xcf\x81"; - case 'q': return "\x51"; - case 'r': return "\xd2\x91"; - case 's': return "\xc5\xa1"; - case 't': return "\xd1\x82"; - case 'u': return "\xce\xb0"; - case 'v': return "\x56"; - case 'w': return "\xe1\xba\x85"; - case 'x': return "\xd1\x85"; - case 'y': return "\xe1\xbb\xb3"; - case 'z': return "\xc5\xba"; - case 'A': return "\xc3\x85"; - case 'B': return "\xce\xb2"; - case 'C': return "\xc4\x88"; - case 'D': return "\xc4\x90"; - case 'E': return "\xd0\x84"; - case 'F': return "\xce\x93"; - case 'G': return "\xc4\x9e"; - case 'H': return "\xc4\xa6"; - case 'I': return "\xd0\x87"; - case 'J': return "\xc4\xb5"; - case 'K': return "\xc4\xb6"; - case 'L': return "\xc5\x81"; - case 'M': return "\xe1\xb8\xbe"; - case 'N': return "\xc5\x83"; - case 'O': return "\xce\x98"; - case 'P': return "\xcf\x81"; - case 'Q': return "\x71"; - case 'R': return "\xd0\xaf"; - case 'S': return "\xc8\x98"; - case 'T': return "\xc5\xa6"; - case 'U': return "\xc5\xa8"; - case 'V': return "\xce\xbd"; - case 'W': return "\xe1\xba\x84"; - case 'X': return "\xc3\x97"; - case 'Y': return "\xc2\xa5"; - case 'Z': return "\xc5\xbd"; - default: return NULL; - } -} - -/** - * Converts characters so they look like they've been localized. - * - * Note: This leaves escape sequences untouched so they can later be - * processed by ResTable::collectString in the normal way. - */ -string -pseudolocalize_string(const string& source) -{ - const char* s = source.c_str(); - string result; - const size_t I = source.length(); - for (size_t i=0; i<I; i++) { - char c = s[i]; - if (c == '\\') { - if (i<I-1) { - result += '\\'; - i++; - c = s[i]; - switch (c) { - case 'u': - // this one takes up 5 chars - result += string(s+i, 5); - i += 4; - break; - case 't': - case 'n': - case '#': - case '@': - case '?': - case '"': - case '\'': - case '\\': - default: - result += c; - break; - } - } else { - result += c; - } - } else { - const char* p = pseudolocalize_char(c); - if (p != NULL) { - result += p; - } else { - result += c; - } - } - } - - //printf("result=\'%s\'\n", result.c_str()); - return result; -} - - diff --git a/tools/aapt/pseudolocalize.h b/tools/aapt/pseudolocalize.h deleted file mode 100644 index 94cb034..0000000 --- a/tools/aapt/pseudolocalize.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef HOST_PSEUDOLOCALIZE_H -#define HOST_PSEUDOLOCALIZE_H - -#include <string> - -std::string pseudolocalize_string(const std::string& source); - -#endif // HOST_PSEUDOLOCALIZE_H - diff --git a/tools/aapt/qsort_r_compat.c b/tools/aapt/qsort_r_compat.c deleted file mode 100644 index 2a8dbe8..0000000 --- a/tools/aapt/qsort_r_compat.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdlib.h> -#include "qsort_r_compat.h" - -/* - * Note: This code is only used on the host, and is primarily here for - * Mac OS compatibility. Apparently, glibc and Apple's libc disagree on - * the parameter order for qsort_r. - */ - -#if HAVE_BSD_QSORT_R - -/* - * BSD qsort_r parameter order is as we have defined here. - */ - -void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk, - int (*compar)(void*, const void* , const void*)) { - qsort_r(base, nel, width, thunk, compar); -} - -#elif HAVE_GNU_QSORT_R - -/* - * GNU qsort_r parameter order places the thunk parameter last. - */ - -struct compar_data { - void* thunk; - int (*compar)(void*, const void* , const void*); -}; - -static int compar_wrapper(const void* a, const void* b, void* data) { - struct compar_data* compar_data = (struct compar_data*)data; - return compar_data->compar(compar_data->thunk, a, b); -} - -void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk, - int (*compar)(void*, const void* , const void*)) { - struct compar_data compar_data; - compar_data.thunk = thunk; - compar_data.compar = compar; - qsort_r(base, nel, width, compar_wrapper, &compar_data); -} - -#else - -/* - * Emulate qsort_r using thread local storage to access the thunk data. - */ - -#include <cutils/threads.h> - -static thread_store_t compar_data_key = THREAD_STORE_INITIALIZER; - -struct compar_data { - void* thunk; - int (*compar)(void*, const void* , const void*); -}; - -static int compar_wrapper(const void* a, const void* b) { - struct compar_data* compar_data = (struct compar_data*)thread_store_get(&compar_data_key); - return compar_data->compar(compar_data->thunk, a, b); -} - -void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk, - int (*compar)(void*, const void* , const void*)) { - struct compar_data compar_data; - compar_data.thunk = thunk; - compar_data.compar = compar; - thread_store_set(&compar_data_key, &compar_data, NULL); - qsort(base, nel, width, compar_wrapper); -} - -#endif diff --git a/tools/aapt/qsort_r_compat.h b/tools/aapt/qsort_r_compat.h deleted file mode 100644 index e14f999..0000000 --- a/tools/aapt/qsort_r_compat.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Provides a portable version of qsort_r, called qsort_r_compat, which is a - * reentrant variant of qsort that passes a user data pointer to its comparator. - * This implementation follows the BSD parameter convention. - */ - -#ifndef ___QSORT_R_COMPAT_H -#define ___QSORT_R_COMPAT_H - -#include <stdlib.h> - -#ifdef __cplusplus -extern "C" { -#endif - -void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk, - int (*compar)(void*, const void* , const void* )); - -#ifdef __cplusplus -} -#endif - -#endif // ___QSORT_R_COMPAT_H diff --git a/tools/aapt/tests/CrunchCache_test.cpp b/tools/aapt/tests/CrunchCache_test.cpp deleted file mode 100644 index 20b5022..0000000 --- a/tools/aapt/tests/CrunchCache_test.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// -// Copyright 2011 The Android Open Source Project -// -#include <utils/String8.h> -#include <iostream> -#include <errno.h> - -#include "CrunchCache.h" -#include "FileFinder.h" -#include "MockFileFinder.h" -#include "CacheUpdater.h" -#include "MockCacheUpdater.h" - -using namespace android; -using std::cout; -using std::endl; - -void expectEqual(int got, int expected, const char* desc) { - cout << "Checking " << desc << ": "; - cout << "Got " << got << ", expected " << expected << "..."; - cout << ( (got == expected) ? "PASSED" : "FAILED") << endl; - errno += ((got == expected) ? 0 : 1); -} - -int main() { - - errno = 0; - - String8 source("res"); - String8 dest("res2"); - - // Create data for MockFileFinder to feed to the cache - KeyedVector<String8, time_t> sourceData; - // This shouldn't be updated - sourceData.add(String8("res/drawable/hello.png"),3); - // This should be updated - sourceData.add(String8("res/drawable/world.png"),5); - // This should cause make directory to be called - sourceData.add(String8("res/drawable-cool/hello.png"),3); - - KeyedVector<String8, time_t> destData; - destData.add(String8("res2/drawable/hello.png"),3); - destData.add(String8("res2/drawable/world.png"),3); - // this should call delete - destData.add(String8("res2/drawable/dead.png"),3); - - // Package up data and create mock file finder - KeyedVector<String8, KeyedVector<String8,time_t> > data; - data.add(source,sourceData); - data.add(dest,destData); - FileFinder* ff = new MockFileFinder(data); - CrunchCache cc(source,dest,ff); - - MockCacheUpdater* mcu = new MockCacheUpdater(); - CacheUpdater* cu(mcu); - - cout << "Running Crunch..."; - int result = cc.crunch(cu); - cout << ((result > 0) ? "PASSED" : "FAILED") << endl; - errno += ((result > 0) ? 0 : 1); - - const int EXPECTED_RESULT = 2; - expectEqual(result, EXPECTED_RESULT, "number of files touched"); - - cout << "Checking calls to deleteFile and processImage:" << endl; - const int EXPECTED_DELETES = 1; - const int EXPECTED_PROCESSED = 2; - // Deletes - expectEqual(mcu->deleteCount, EXPECTED_DELETES, "deleteFile"); - // processImage - expectEqual(mcu->processCount, EXPECTED_PROCESSED, "processImage"); - - const int EXPECTED_OVERWRITES = 3; - result = cc.crunch(cu, true); - expectEqual(result, EXPECTED_OVERWRITES, "number of files touched with overwrite"); - \ - - if (errno == 0) - cout << "ALL TESTS PASSED!" << endl; - else - cout << errno << " TESTS FAILED" << endl; - - delete ff; - delete cu; - - // TESTS BELOW WILL GO AWAY SOON - - String8 source2("ApiDemos/res"); - String8 dest2("ApiDemos/res2"); - - FileFinder* sff = new SystemFileFinder(); - CacheUpdater* scu = new SystemCacheUpdater(); - - CrunchCache scc(source2,dest2,sff); - - scc.crunch(scu); -}
\ No newline at end of file diff --git a/tools/aapt/tests/FileFinder_test.cpp b/tools/aapt/tests/FileFinder_test.cpp deleted file mode 100644 index 07bd665..0000000 --- a/tools/aapt/tests/FileFinder_test.cpp +++ /dev/null @@ -1,101 +0,0 @@ -// -// Copyright 2011 The Android Open Source Project -// -#include <utils/Vector.h> -#include <utils/KeyedVector.h> -#include <iostream> -#include <cassert> -#include <utils/String8.h> -#include <utility> - -#include "DirectoryWalker.h" -#include "MockDirectoryWalker.h" -#include "FileFinder.h" - -using namespace android; - -using std::pair; -using std::cout; -using std::endl; - - - -int main() -{ - - cout << "\n\n STARTING FILE FINDER TESTS" << endl; - String8 path("ApiDemos"); - - // Storage to pass to findFiles() - KeyedVector<String8,time_t> testStorage; - - // Mock Directory Walker initialization. First data, then sdw - Vector< pair<String8,time_t> > data; - data.push( pair<String8,time_t>(String8("hello.png"),3) ); - data.push( pair<String8,time_t>(String8("world.PNG"),3) ); - data.push( pair<String8,time_t>(String8("foo.pNg"),3) ); - // Neither of these should be found - data.push( pair<String8,time_t>(String8("hello.jpg"),3) ); - data.push( pair<String8,time_t>(String8(".hidden.png"),3)); - - DirectoryWalker* sdw = new StringDirectoryWalker(path,data); - - // Extensions to look for - Vector<String8> exts; - exts.push(String8(".png")); - - errno = 0; - - // Make sure we get a valid mock directory walker - // Make sure we finish without errors - cout << "Checking DirectoryWalker..."; - assert(sdw != NULL); - cout << "PASSED" << endl; - - // Make sure we finish without errors - cout << "Running findFiles()..."; - bool findStatus = FileFinder::findFiles(path,exts, testStorage, sdw); - assert(findStatus); - cout << "PASSED" << endl; - - const size_t SIZE_EXPECTED = 3; - // Check to make sure we have the right number of things in our storage - cout << "Running size comparison: Size is " << testStorage.size() << ", "; - cout << "Expected " << SIZE_EXPECTED << "..."; - if(testStorage.size() == SIZE_EXPECTED) - cout << "PASSED" << endl; - else { - cout << "FAILED" << endl; - errno++; - } - - // Check to make sure that each of our found items has the right extension - cout << "Checking Returned Extensions..."; - bool extsOkay = true; - String8 wrongExts; - for (size_t i = 0; i < SIZE_EXPECTED; ++i) { - String8 testExt(testStorage.keyAt(i).getPathExtension()); - testExt.toLower(); - if (testExt != ".png") { - wrongExts += testStorage.keyAt(i); - wrongExts += "\n"; - extsOkay = false; - } - } - if (extsOkay) - cout << "PASSED" << endl; - else { - cout << "FAILED" << endl; - cout << "The following extensions didn't check out" << endl << wrongExts; - } - - // Clean up - delete sdw; - - if(errno == 0) { - cout << "ALL TESTS PASSED" << endl; - } else { - cout << errno << " TESTS FAILED" << endl; - } - return errno; -}
\ No newline at end of file diff --git a/tools/aapt/tests/MockCacheUpdater.h b/tools/aapt/tests/MockCacheUpdater.h deleted file mode 100644 index c7f4bd7..0000000 --- a/tools/aapt/tests/MockCacheUpdater.h +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright 2011 The Android Open Source Project -// -#ifndef MOCKCACHEUPDATER_H -#define MOCKCACHEUPDATER_H - -#include <utils/String8.h> -#include "CacheUpdater.h" - -using namespace android; - -class MockCacheUpdater : public CacheUpdater { -public: - - MockCacheUpdater() - : deleteCount(0), processCount(0) { }; - - // Make sure all the directories along this path exist - virtual void ensureDirectoriesExist(String8 path) - { - // Nothing to do - }; - - // Delete a file - virtual void deleteFile(String8 path) { - deleteCount++; - }; - - // Process an image from source out to dest - virtual void processImage(String8 source, String8 dest) { - processCount++; - }; - - // DATA MEMBERS - int deleteCount; - int processCount; -private: -}; - -#endif // MOCKCACHEUPDATER_H
\ No newline at end of file diff --git a/tools/aapt/tests/MockDirectoryWalker.h b/tools/aapt/tests/MockDirectoryWalker.h deleted file mode 100644 index 5900cf3..0000000 --- a/tools/aapt/tests/MockDirectoryWalker.h +++ /dev/null @@ -1,85 +0,0 @@ -// -// Copyright 2011 The Android Open Source Project -// -#ifndef MOCKDIRECTORYWALKER_H -#define MOCKDIRECTORYWALKER_H - -#include <utils/Vector.h> -#include <utils/String8.h> -#include <utility> -#include "DirectoryWalker.h" - -using namespace android; -using std::pair; - -// String8 Directory Walker -// This is an implementation of the Directory Walker abstraction that is built -// for testing. -// Instead of system calls it queries a private data structure for the directory -// entries. It takes a path and a map of filenames and their modification times. -// functions are inlined since they are short and simple - -class StringDirectoryWalker : public DirectoryWalker { -public: - StringDirectoryWalker(String8& path, Vector< pair<String8,time_t> >& data) - : mPos(0), mBasePath(path), mData(data) { - //fprintf(stdout,"StringDW built to mimic %s with %d files\n", - // mBasePath.string()); - }; - // Default copy constructor, and destructor are fine - - virtual bool openDir(String8 path) { - // If the user is trying to query the "directory" that this - // walker was initialized with, then return success. Else fail. - return path == mBasePath; - }; - virtual bool openDir(const char* path) { - String8 p(path); - openDir(p); - return true; - }; - // Advance to next entry in the Vector - virtual struct dirent* nextEntry() { - // Advance position and check to see if we're done - if (mPos >= mData.size()) - return NULL; - - // Place data in the entry descriptor. This class only returns files. - mEntry.d_type = DT_REG; - mEntry.d_ino = mPos; - // Copy chars from the string name to the entry name - size_t i = 0; - for (i; i < mData[mPos].first.size(); ++i) - mEntry.d_name[i] = mData[mPos].first[i]; - mEntry.d_name[i] = '\0'; - - // Place data in stats - mStats.st_ino = mPos; - mStats.st_mtime = mData[mPos].second; - - // Get ready to move to the next entry - mPos++; - - return &mEntry; - }; - // Get the stats for the current entry - virtual struct stat* entryStats() { - return &mStats; - }; - // Nothing to do in clean up - virtual void closeDir() { - // Nothing to do - }; - virtual DirectoryWalker* clone() { - return new StringDirectoryWalker(*this); - }; -private: - // Current position in the Vector - size_t mPos; - // Base path - String8 mBasePath; - // Data to simulate a directory full of files. - Vector< pair<String8,time_t> > mData; -}; - -#endif // MOCKDIRECTORYWALKER_H
\ No newline at end of file diff --git a/tools/aapt/tests/MockFileFinder.h b/tools/aapt/tests/MockFileFinder.h deleted file mode 100644 index da5ea4f..0000000 --- a/tools/aapt/tests/MockFileFinder.h +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright 2011 The Android Open Source Project -// - -#ifndef MOCKFILEFINDER_H -#define MOCKFILEFINDER_H - -#include <utils/Vector.h> -#include <utils/KeyedVector.h> -#include <utils/String8.h> - -#include "DirectoryWalker.h" - -using namespace android; - -class MockFileFinder : public FileFinder { -public: - MockFileFinder (KeyedVector<String8, KeyedVector<String8,time_t> >& files) - : mFiles(files) - { - // Nothing left to do - }; - - /** - * findFiles implementation for the abstraction. - * PRECONDITIONS: - * No checking is done, so there MUST be an entry in mFiles with - * path matching basePath. - * - * POSTCONDITIONS: - * fileStore is filled with a copy of the data in mFiles corresponding - * to the basePath. - */ - - virtual bool findFiles(String8 basePath, Vector<String8>& extensions, - KeyedVector<String8,time_t>& fileStore, - DirectoryWalker* dw) - { - const KeyedVector<String8,time_t>* payload(&mFiles.valueFor(basePath)); - // Since KeyedVector doesn't implement swap - // (who doesn't use swap??) we loop and add one at a time. - for (size_t i = 0; i < payload->size(); ++i) { - fileStore.add(payload->keyAt(i),payload->valueAt(i)); - } - return true; - } - -private: - // Virtual mapping between "directories" and the "files" contained - // in them - KeyedVector<String8, KeyedVector<String8,time_t> > mFiles; -}; - - -#endif // MOCKFILEFINDER_H
\ No newline at end of file diff --git a/tools/aapt/tests/plurals/AndroidManifest.xml b/tools/aapt/tests/plurals/AndroidManifest.xml deleted file mode 100644 index c721dee..0000000 --- a/tools/aapt/tests/plurals/AndroidManifest.xml +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.aapt.test.plurals"> - -</manifest> diff --git a/tools/aapt/tests/plurals/res/values/strings.xml b/tools/aapt/tests/plurals/res/values/strings.xml deleted file mode 100644 index 1c1fc19..0000000 --- a/tools/aapt/tests/plurals/res/values/strings.xml +++ /dev/null @@ -1,7 +0,0 @@ -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="ok">OK</string> - <plurals name="a_plural"> - <item quantity="one">A dog</item> - <item quantity="other">Some dogs</item> - </plurals> -</resources> diff --git a/tools/aapt/tests/plurals/run.sh b/tools/aapt/tests/plurals/run.sh deleted file mode 100755 index 4d39e10..0000000 --- a/tools/aapt/tests/plurals/run.sh +++ /dev/null @@ -1,16 +0,0 @@ -TEST_DIR=tools/aapt/tests/plurals -TEST_OUT_DIR=out/plurals_test - -rm -rf $TEST_OUT_DIR -mkdir -p $TEST_OUT_DIR -mkdir -p $TEST_OUT_DIR/java - -#gdb --args \ -aapt package -v -x -m -z -J $TEST_OUT_DIR/java -M $TEST_DIR/AndroidManifest.xml \ - -I out/target/common/obj/APPS/framework-res_intermediates/package-export.apk \ - -P $TEST_OUT_DIR/public_resources.xml \ - -S $TEST_DIR/res - -echo -echo "==================== FILES CREATED ==================== " -find $TEST_OUT_DIR -type f |