From: The Android Open Source Project Date: Wed, 4 Mar 2009 02:28:45 +0000 (-0800) Subject: auto import from //depot/cupcake/@135843 X-Git-Url: https://git.saurik.com/android/aapt.git/commitdiff_plain/8cf49628c9a6f3c38a29ac7d3c0747b846b9d3e3?hp=-c auto import from //depot/cupcake/@135843 --- 8cf49628c9a6f3c38a29ac7d3c0747b846b9d3e3 diff --git a/AaptAssets.cpp b/AaptAssets.cpp deleted file mode 100644 index 6bc1ee6..0000000 --- a/AaptAssets.cpp +++ /dev/null @@ -1,1717 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// - -#include "AaptAssets.h" -#include "Main.h" - -#include -#include - -#include -#include -#include - -static const char* kDefaultLocale = "default"; -static const char* kWildcardName = "any"; -static const char* kAssetDir = "assets"; -static const char* kResourceDir = "res"; -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; -} - -static bool isHidden(const char *root, const char *path) -{ - const char *type = NULL; - - // Skip all hidden files. - if (path[0] == '.') { - // Skip ., .. and .svn but don't chatter about it. - if (strcmp(path, ".") == 0 - || strcmp(path, "..") == 0 - || strcmp(path, ".svn") == 0) { - return true; - } - type = "hidden"; - } else if (path[0] == '_') { - // skip directories starting with _ (don't chatter about it) - String8 subdirName(root); - subdirName.appendPath(path); - if (getFileType(subdirName.string()) == kFileTypeDirectory) { - return true; - } - } else if (strcmp(path, "CVS") == 0) { - // Skip CVS but don't chatter about it. - return true; - } else if (strcasecmp(path, "thumbs.db") == 0 - || strcasecmp(path, "picasa.ini") == 0) { - // Skip suspected image indexes files. - type = "index"; - } else if (path[strlen(path)-1] == '~') { - // Skip suspected emacs backup files. - type = "backup"; - } else { - // Let everything else through. - return false; - } - - /* If we get this far, "type" should be set and the file - * should be skipped. - */ - String8 subdirName(root); - subdirName.appendPath(path); - fprintf(stderr, " (skipping %s %s '%s')\n", type, - getFileType(subdirName.string())==kFileTypeDirectory ? "dir":"file", - subdirName.string()); - - return true; -} - -// ========================================================================= -// ========================================================================= -// ========================================================================= - -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; - } - - // orientation - if (getOrientationName(part.string(), &config)) { - *axis = AXIS_ORIENTATION; - *value = config.orientation; - 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 - 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; -} - -bool -AaptGroupEntry::initFromDirName(const char* dir, String8* resType) -{ - Vector parts; - - String8 mcc, mnc, loc, orient, den, touch, key, keysHidden, nav, size, vers; - - 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()); - } - - // orientation - if (getOrientationName(part.string())) { - orient = part; - - index++; - if (index == N) { - goto success; - } - part = parts[index]; - } else { - //printf("not orientation: %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()); - } - - 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->orientation = orient; - this->density = den; - this->touchscreen = touch; - this->keysHidden = keysHidden; - this->keyboard = key; - this->navigation = nav; - this->screenSize = size; - 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 += this->orientation; - s += ","; - s += density; - s += ","; - s += touchscreen; - s += ","; - s += keysHidden; - s += ","; - s += keyboard; - s += ","; - s += navigation; - s += ","; - s += screenSize; - s += ","; - s += version; - return s; -} - -String8 -AaptGroupEntry::toDirName(const String8& resType) const -{ - String8 s = resType; - if (this->mcc != "") { - s += "-"; - s += mcc; - } - if (this->mnc != "") { - s += "-"; - s += mnc; - } - if (this->locale != "") { - s += "-"; - s += locale; - } - if (this->orientation != "") { - s += "-"; - s += orientation; - } - if (this->density != "") { - s += "-"; - s += density; - } - if (this->touchscreen != "") { - s += "-"; - s += touchscreen; - } - if (this->keysHidden != "") { - s += "-"; - s += keysHidden; - } - if (this->keyboard != "") { - s += "-"; - s += keyboard; - } - if (this->navigation != "") { - s += "-"; - s += navigation; - } - if (this->screenSize != "") { - s += "-"; - s += screenSize; - } - if (this->version != "") { - 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; - - int d = atoi(val); - if (d != 0) { - if (out) out->mnc = d; - return true; - } - - return false; -} - -/* - * 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::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::getDensityName(const char* name, - ResTable_config* out) -{ - if (strcmp(name, kWildcardName) == 0) { - if (out) out->density = 0; - 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 = out->MASK_KEYSHIDDEN; - value = out->KEYSHIDDEN_ANY; - } else if (strcmp(name, "keysexposed") == 0) { - mask = out->MASK_KEYSHIDDEN; - value = out->KEYSHIDDEN_NO; - } else if (strcmp(name, "keyshidden") == 0) { - mask = out->MASK_KEYSHIDDEN; - value = out->KEYSHIDDEN_YES; - } else if (strcmp(name, "keyssoft") == 0) { - mask = out->MASK_KEYSHIDDEN; - value = out->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::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::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 = vendor.compare(o.vendor); - if (v == 0) v = orientation.compare(o.orientation); - 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 = navigation.compare(o.navigation); - if (v == 0) v = screenSize.compare(o.screenSize); - if (v == 0) v = version.compare(o.version); - return v; -} - -ResTable_config AaptGroupEntry::toParams() const -{ - ResTable_config params; - memset(¶ms, 0, sizeof(params)); - getMccName(mcc.string(), ¶ms); - getMncName(mnc.string(), ¶ms); - getLocaleName(locale.string(), ¶ms); - getOrientationName(orientation.string(), ¶ms); - getDensityName(density.string(), ¶ms); - getTouchscreenName(touchscreen.string(), ¶ms); - getKeysHiddenName(keysHidden.string(), ¶ms); - getKeyboardName(keyboard.string(), ¶ms); - getNavigationName(navigation.string(), ¶ms); - getScreenSizeName(screenSize.string(), ¶ms); - getVersionName(version.string(), ¶ms); - 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.locale.string()); - name.appendPath(mGroupEntry.vendor.string()); - name.appendPath(mPath); - name.append(" #generated"); - return name; - } - return mSourceFile; -} - -// ========================================================================= -// ========================================================================= -// ========================================================================= - -status_t AaptGroup::addFile(const sp& file) -{ - if (mFiles.indexOfKey(file->getGroupEntry()) < 0) { - file->mPath = mPath; - mFiles.add(file->getGroupEntry(), file); - return NO_ERROR; - } - - 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 -{ - printf(" %s\n", getPath().string()); - const size_t N=mFiles.size(); - size_t i; - for (i=0; i file = mFiles.valueAt(i); - const AaptGroupEntry& e = file->getGroupEntry(); - if (file->hasData()) { - printf(" Gen: (%s) %d bytes\n", e.toString().string(), - (int)file->getSize()); - } else { - printf(" Src: %s\n", file->getPrintableSource().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& 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& dir) -{ - if (mDirs.indexOfKey(name) >= 0) { - return ALREADY_EXISTS; - } - mDirs.add(name, dir); - return NO_ERROR; -} - -sp AaptDir::makeDir(const String8& path) -{ - String8 name; - String8 remain = path; - - sp 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 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::renameFile(const sp& file, const String8& newName) -{ - sp origGroup; - - // Find and remove the given file with shear, brute force! - const size_t NG = mFiles.size(); - size_t i; - for (i=0; origGroup == NULL && i g = mFiles.valueAt(i); - const size_t NF = g->getFiles().size(); - for (size_t j=0; jgetFiles().valueAt(j) == file) { - origGroup = g; - g->removeFile(j); - if (NF == 1) { - mFiles.removeItemsAt(i); - } - break; - } - } - } - - //printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string()); - - // Place the file under its new name. - if (origGroup != NULL) { - return addLeafFile(newName, file); - } - - return NO_ERROR; -} - -status_t AaptDir::addLeafFile(const String8& leafName, const sp& file) -{ - sp 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) -{ - Vector 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; - - fileNames.add(String8(entry->d_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 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); - if (res < NO_ERROR) { - return res; - } - if (res > 0 && notAdded) { - mDirs.add(fileNames[i], subdir); - } - count += res; - } else if (type == kFileTypeRegular) { - sp 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 -{ - const size_t ND=getDirs().size(); - size_t i; - for (i=0; iprint(); - } - - const size_t NF=getFiles().size(); - for (i=0; iprint(); - } -} - -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; - -} - -// ========================================================================= -// ========================================================================= -// ========================================================================= - -sp AaptAssets::addFile( - const String8& filePath, const AaptGroupEntry& entry, - const String8& srcDir, sp* outGroup, - const String8& resType) -{ - sp dir = this; - sp group; - sp 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 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& file, const String8& resType) -{ - sp res = AaptDir::makeDir(kResString); - String8 dirname = file->getGroupEntry().toDirName(resType); - sp subdir = res->makeDir(dirname); - sp 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& resDirs = bundle->getResourceSourceDirs(); - const size_t dirCount =resDirs.size(); - sp 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 assetAaptDir = makeDir(String8(kAssetDir)); - AaptGroupEntry group; - count = assetAaptDir->slurpFullTree(bundle, assetRoot, group, - String8()); - 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; i0) { - sp nextOverlay = new AaptAssets(); - current->setOverlay(nextOverlay); - current = nextOverlay; - } - 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; arggetFileSpecEntry(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()); - 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; - } - - -bail: - return totalCount; -} - -ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir, - const AaptGroupEntry& kind, - const String8& resType) -{ - ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType); - 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; - } - - FileType type = getFileType(subdirName.string()); - - if (type == kFileTypeDirectory) { - sp dir = makeDir(String8(entry->d_name)); - ssize_t res = dir->slurpFullTree(bundle, subdirName, group, - resType); - if (res < 0) { - count = res; - goto bail; - } - if (res > 0) { - mGroupEntries.add(group); - count += res; - } - - mDirs.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 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; igetEntryByIndex(i); - if (entry->getDeleted()) { - continue; - } - - String8 entryName(entry->getFileName()); - - String8 dirName = entryName.getPathDir(); - sp 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 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; -} - -sp AaptAssets::getSymbolsFor(const String8& name) -{ - sp sym = mSymbols.valueFor(name); - if (sym == NULL) { - sym = new AaptSymbols(); - mSymbols.add(name, sym); - } - return sym; -} - -status_t AaptAssets::buildIncludedResources(Bundle* bundle) -{ - if (!mHaveIncludedAssets) { - // Add in all includes. - const Vector& incl = bundle->getPackageIncludes(); - const size_t N=incl.size(); - for (size_t i=0; igetVerbose()) - 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& file) -{ - const ResTable& res = getIncludedResources(); - // XXX dirty! - return const_cast(res).add(file->getData(), file->getSize(), NULL); -} - -const ResTable& AaptAssets::getIncludedResources() const -{ - return mIncludedAssets.getResources(false); -} - -void AaptAssets::print() const -{ - printf("Locale/Vendor pairs:\n"); - const size_t N=mGroupEntries.size(); - for (size_t i=0; i -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Bundle.h" -#include "SourcePos.h" - -using namespace android; - -bool valid_symbol_name(const String8& str); - -enum { - AXIS_NONE = 0, - AXIS_MCC = 1, - AXIS_MNC, - AXIS_LANGUAGE, - AXIS_REGION, - AXIS_ORIENTATION, - AXIS_DENSITY, - AXIS_TOUCHSCREEN, - AXIS_KEYSHIDDEN, - AXIS_KEYBOARD, - AXIS_NAVIGATION, - AXIS_SCREENSIZE, - 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() { } - AaptGroupEntry(const String8& _locale, const String8& _vendor) - : locale(_locale), vendor(_vendor) { } - - String8 mcc; - String8 mnc; - String8 locale; - String8 vendor; - String8 orientation; - String8 density; - String8 touchscreen; - String8 keysHidden; - String8 keyboard; - String8 navigation; - String8 screenSize; - String8 version; - - bool initFromDirName(const char* dir, String8* resType); - - static status_t parseNamePart(const String8& part, int* axis, uint32_t* value); - - 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 getOrientationName(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 getScreenSizeName(const char* name, ResTable_config* out = NULL); - static bool getVersionName(const char* name, ResTable_config* out = NULL); - - int compare(const AaptGroupEntry& o) 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; -}; - -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; - -/** - * 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() { } - - 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 >& getFiles() const - { return mFiles; } - - status_t addFile(const sp& file); - void removeFile(size_t index); - - void print() const; - - String8 getPrintableSource() const; - -private: - String8 mLeaf; - String8 mPath; - - DefaultKeyedVector > mFiles; -}; - -/** - * A single directory of assets, which can contain for 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 >& getFiles() const { return mFiles; } - const DefaultKeyedVector >& getDirs() const { return mDirs; } - - status_t addFile(const String8& name, const sp& file); - status_t addDir(const String8& name, const sp& dir); - - sp makeDir(const String8& name); - - void removeFile(const String8& name); - void removeDir(const String8& name); - - status_t renameFile(const sp& file, const String8& newName); - - status_t addLeafFile(const String8& leafName, - const sp& file); - - virtual ssize_t slurpFullTree(Bundle* bundle, - const String8& srcDir, - const AaptGroupEntry& kind, - const String8& resType); - - /* - * 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 getPrintableSource() const; - -private: - String8 mLeaf; - String8 mPath; - - DefaultKeyedVector > mFiles; - DefaultKeyedVector > mDirs; -}; - -/** - * All information we know about a particular symbol. - */ -class AaptSymbolEntry -{ -public: - AaptSymbolEntry() - : isPublic(false), typeCode(TYPE_UNKNOWN) - { - } - AaptSymbolEntry(const String8& _name) - : name(_name), isPublic(false), typeCode(TYPE_UNKNOWN) - { - } - AaptSymbolEntry(const AaptSymbolEntry& o) - : name(o.name), sourcePos(o.sourcePos), isPublic(o.isPublic) - , 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; - comment = o.comment; - typeComment = o.typeComment; - typeCode = o.typeCode; - int32Val = o.int32Val; - stringVal = o.stringVal; - return *this; - } - - const String8 name; - - SourcePos sourcePos; - bool isPublic; - - 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; - } - - 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 addNestedSymbol(const String8& name, const SourcePos& pos) { - if (!check_valid_symbol_name(name, pos, "nested symbol")) { - return NULL; - } - - sp sym = mNestedSymbols.valueFor(name); - if (sym == NULL) { - sym = new AaptSymbols(); - mNestedSymbols.add(name, sym); - } - - return sym; - } - - const KeyedVector& getSymbols() const - { return mSymbols; } - const DefaultKeyedVector >& 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 mSymbols; - DefaultKeyedVector > mNestedSymbols; - AaptSymbolEntry mDefSymbol; -}; - -class ResourceTypeSet; - -/** - * Asset hierarchy being operated on. - */ -class AaptAssets : public AaptDir -{ -public: - AaptAssets() : AaptDir(String8(), String8()), mHaveIncludedAssets(false) { } - virtual ~AaptAssets() { } - - const String8& getPackage() const { return mPackage; } - void setPackage(const String8& package) { mPackage = package; mSymbolsPrivatePackage = package; } - - const SortedVector& getGroupEntries() const { return mGroupEntries; } - - sp addFile(const String8& filePath, - const AaptGroupEntry& entry, - const String8& srcDir, - sp* outGroup, - const String8& resType); - - void addResource(const String8& leafName, - const String8& path, - const sp& file, - const String8& resType); - - ssize_t slurpFromArgs(Bundle* bundle); - - virtual ssize_t slurpFullTree(Bundle* bundle, - const String8& srcDir, - const AaptGroupEntry& kind, - const String8& resType); - - ssize_t slurpResourceTree(Bundle* bundle, const String8& srcDir); - ssize_t slurpResourceZip(Bundle* bundle, const char* filename); - - sp getSymbolsFor(const String8& name); - - const DefaultKeyedVector >& getSymbols() const { return mSymbols; } - - String8 getSymbolsPrivatePackage() const { return mSymbolsPrivatePackage; } - void setSymbolsPrivatePackage(const String8& pkg) { mSymbolsPrivatePackage = pkg; } - - status_t buildIncludedResources(Bundle* bundle); - status_t addIncludedResources(const sp& file); - const ResTable& getIncludedResources() const; - - void print() const; - - inline const Vector >& resDirs() { return mDirs; } - - inline sp getOverlay() { return mOverlay; } - inline void setOverlay(sp& overlay) { mOverlay = overlay; } - - inline KeyedVector >* getResources() { return mRes; } - inline void - setResources(KeyedVector >* res) { mRes = res; } - -private: - String8 mPackage; - SortedVector mGroupEntries; - DefaultKeyedVector > mSymbols; - String8 mSymbolsPrivatePackage; - - Vector > mDirs; - - bool mHaveIncludedAssets; - AssetManager mIncludedAssets; - - sp mOverlay; - KeyedVector >* mRes; -}; - -#endif // __AAPT_ASSETS_H - diff --git a/Android.mk b/Android.mk deleted file mode 100644 index fdc859c..0000000 --- a/Android.mk +++ /dev/null @@ -1,52 +0,0 @@ -# -# Copyright 2006 The Android Open Source Project -# -# Android Asset Packaging Tool -# - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - AaptAssets.cpp \ - Command.cpp \ - Main.cpp \ - Package.cpp \ - StringPool.cpp \ - XMLNode.cpp \ - ResourceTable.cpp \ - Images.cpp \ - Resource.cpp \ - SourcePos.cpp - -LOCAL_CFLAGS += -Wno-format-y2k - -LOCAL_C_INCLUDES += external/expat/lib -LOCAL_C_INCLUDES += external/libpng -LOCAL_C_INCLUDES += external/zlib -LOCAL_C_INCLUDES += build/libs/host/include - -#LOCAL_WHOLE_STATIC_LIBRARIES := -LOCAL_STATIC_LIBRARIES := \ - libhost \ - libutils \ - libcutils \ - libexpat \ - libpng - -LOCAL_LDLIBS := -lz - -ifeq ($(HOST_OS),linux) -LOCAL_LDLIBS += -lrt -endif - -ifeq ($(HOST_OS),windows) -ifeq ($(strip $(USE_CYGWIN),),) -LOCAL_LDLIBS += -lws2_32 -endif -endif - -LOCAL_MODULE := aapt - -include $(BUILD_HOST_EXECUTABLE) - diff --git a/Bundle.h b/Bundle.h deleted file mode 100644 index 2d8471b..0000000 --- a/Bundle.h +++ /dev/null @@ -1,164 +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 -#include // android -#include -#include - -/* - * Things we can do. - */ -typedef enum Command { - kCommandUnknown = 0, - kCommandVersion, - kCommandList, - kCommandDump, - kCommandAdd, - kCommandRemove, - kCommandPackage, -} 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), - mCompressionMethod(0), mOutputAPKFile(NULL), - mAssetSourceDir(NULL), - mAndroidManifestFile(NULL), mPublicOutputFile(NULL), - mRClassDir(NULL), mResourceIntermediatesDir(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() { 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; } - int getCompressionMethod(void) const { return mCompressionMethod; } - void setCompressionMethod(int val) { mCompressionMethod = val; } - const char* getOutputAPKFile() const { return mOutputAPKFile; } - void setOutputAPKFile(const char* val) { mOutputAPKFile = val; } - - /* - * Input options. - */ - const char* getAssetSourceDir() const { return mAssetSourceDir; } - void setAssetSourceDir(const char* dir) { mAssetSourceDir = dir; } - const android::Vector& 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* getResourceIntermediatesDir() const { return mResourceIntermediatesDir; } - void setResourceIntermediatesDir(const char* dir) { mResourceIntermediatesDir = dir; } - const android::Vector& getPackageIncludes() const { return mPackageIncludes; } - void addPackageInclude(const char* file) { mPackageIncludes.add(file); } - const android::Vector& getJarFiles() const { return mJarFiles; } - void addJarFile(const char* file) { mJarFiles.add(file); } - const android::Vector& getNoCompressExtensions() const { return mNoCompressExtensions; } - void addNoCompressExtension(const char* ext) { mNoCompressExtensions.add(ext); } - - /* - * 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 - -private: - /* commands & modifiers */ - Command mCmd; - bool mVerbose; - bool mAndroidList; - bool mForce; - int mGrayscaleTolerance; - bool mMakePackageDirs; - bool mUpdate; - bool mExtending; - bool mRequireLocalization; - bool mPseudolocalize; - int mCompressionMethod; - const char* mOutputAPKFile; - const char* mAssetSourceDir; - const char* mAndroidManifestFile; - const char* mPublicOutputFile; - const char* mRClassDir; - const char* mResourceIntermediatesDir; - android::String8 mConfigurations; - android::Vector mPackageIncludes; - android::Vector mJarFiles; - android::Vector mNoCompressExtensions; - android::Vector mResourceSourceDirs; - - /* file specification */ - int mArgc; - char* const* mArgv; - -#if 0 - /* misc stuff */ - int mPackageCount; -#endif -}; - -#endif // __BUNDLE_H diff --git a/Command.cpp b/Command.cpp deleted file mode 100644 index bff0423..0000000 --- a/Command.cpp +++ /dev/null @@ -1,841 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Android Asset Packaging Tool main entry point. -// -#include "Main.h" -#include "Bundle.h" -#include "ResourceTable.h" -#include "XMLNode.h" - -#include -#include - -#include -#include - -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 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%% %s %08lx %s\n", - (long) entry->getUncompressedLen(), - compressionName(entry->getCompressionMethod()), - (long) entry->getCompressedLen(), - calcPercent(entry->getUncompressedLen(), - entry->getCompressedLen()), - 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 { - printf("\nResource table:\n"); - res.print(); - } - - 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; iresolveReference(&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)->valueToString(value2, 0, NULL, &len); - return str ? String8(str, len) : String8(); -} - -// These are attribute resource constants for the platform, as found -// in android.R.attr -enum { - NAME_ATTR = 0x01010003, - VERSION_CODE_ATTR = 0x0101021b, - VERSION_NAME_ATTR = 0x0101021c, - LABEL_ATTR = 0x01010001, - ICON_ATTR = 0x01010002, -}; - -/* - * Handle the "dump" command, to extract select data from an archive. - */ -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; - if (!assets.addAssetPath(String8(filename), NULL)) { - fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n"); - return 1; - } - - 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) { - res.print(); - - } 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; igetFileSpecCount(); 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 %p 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); - 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; igetFileSpecCount(); 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 %p 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 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()); - } - } - } else if (strcmp("badging", option) == 0) { - size_t len; - ResXMLTree::event_code_t code; - int depth = 0; - String8 error; - bool withinActivity = false; - bool isMainActivity = false; - bool isLauncherActivity = false; - String8 activityName; - String8 activityLabel; - String8 activityIcon; - 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 tag\n"); - goto bail; - } - String8 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 = getAttribute(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 && tag == "application") { - String8 label = getResolvedAttribute(&res, tree, LABEL_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n", error.string()); - goto bail; - } - printf("application: label='%s' ", label.string()); - - String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string()); - goto bail; - } - printf("icon='%s'\n", icon.string()); - } else if (depth == 3 && tag == "activity") { - withinActivity = true; - //printf("LOG: withinActivity==true\n"); - - 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; - } - } else if (depth == 5 && withinActivity) { - if (tag == "action") { - //printf("LOG: action tag\n"); - String8 action = getAttribute(tree, NAME_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string()); - goto bail; - } - if (action == "android.intent.action.MAIN") { - isMainActivity = true; - //printf("LOG: isMainActivity==true\n"); - } - } else 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 (category == "android.intent.category.LAUNCHER") { - isLauncherActivity = true; - //printf("LOG: isLauncherActivity==true\n"); - } - } - } - - if (depth < 3) { - //if (withinActivity) printf("LOG: withinActivity==false\n"); - withinActivity = false; - } - - if (depth < 5) { - //if (isMainActivity) printf("LOG: isMainActivity==false\n"); - //if (isLauncherActivity) printf("LOG: isLauncherActivity==false\n"); - isMainActivity = false; - isLauncherActivity = false; - } - - if (withinActivity && isMainActivity && isLauncherActivity) { - printf("launchable activity: name='%s' label='%s' icon='%s'\n", - activityName.string(), activityLabel.string(), - activityIcon.string()); - } - } - printf("locales:"); - Vector locales; - res.getLocales(&locales); - const size_t N = locales.size(); - for (size_t i=0; i configs; - res.getConfigurations(&configs); - const size_t N = configs.size(); - for (size_t i=0; igetUpdate()) { - /* 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 { - 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 assets; - int N; - - // -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(); - err = assets->slurpFromArgs(bundle); - if (err < 0) { - goto bail; - } - - if (bundle->getVerbose()) { - assets->print(); - } - - // If they asked for any files 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; - } - - // Write out R.java constants - if (assets->getPackage() == assets->getSymbolsPrivatePackage()) { - err = writeResourceSymbols(bundle, assets, assets->getPackage(), true); - if (err < 0) { - goto bail; - } - } 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 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; - } - } - - retVal = 0; -bail: - if (SourcePos::hasErrors()) { - SourcePos::printErrors(stderr); - } - return retVal; -} diff --git a/Images.cpp b/Images.cpp deleted file mode 100644 index 4c776fb..0000000 --- a/Images.cpp +++ /dev/null @@ -1,1074 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Build resource files from raw assets. -// - -#define PNG_INTERNAL - -#include "Images.h" - -#include -#include - -#include - -#define NOISY(x) //x - -static void -png_write_aapt_file(png_structp png_ptr, png_bytep data, png_size_t length) -{ - status_t err = ((AaptFile*)png_ptr->io_ptr)->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); - } - } - - png_uint_32 width; - png_uint_32 height; - png_bytepp rows; - - // 9-patch info. - bool is9Patch; - Res_png_9patch info9Patch; - - 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_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 * png_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); -} - -static bool is_tick(png_bytep p, bool transparent, const char** outError) -{ - if (transparent) { - if (p[3] == 0) { - return false; - } - if (p[3] != 0xff) { - *outError = "Frame pixels must be either solid or transparent (not intermediate alphas)"; - return false; - } - if (p[0] != 0 || p[1] != 0 || p[2] != 0) { - *outError = "Ticks in transparent frame must be black"; - } - return true; - } - - if (p[3] != 0xFF) { - *outError = "White frame must be a solid color (no alpha)"; - } - if (p[0] == 0xFF && p[1] == 0xFF && p[2] == 0xFF) { - return false; - } - if (p[0] != 0 || p[1] != 0 || p[2] != 0) { - *outError = "Ticks in white frame must be black"; - return false; - } - return true; -} - -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 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 / 2 + 1) * sizeof(int32_t); - int maxSizeYDivs = (H / 2 + 1) * 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; - - png_bytep p = image->rows[0]; - bool transparent = p[3] == 0; - bool hasColor = false; - - const char* errorMsg = NULL; - int errorPixel = -1; - const char* errorEdge = ""; - - 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; - } - - // 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) * png_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--; - } - 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; iinfo9Patch.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 (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[1]; - - png_bytepp outRows = (png_bytepp) malloc((int) imageInfo.height * png_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); - 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) { - NOISY(printf("Adding 9-patch info...\n")); - strcpy((char*)unknowns[0].name, "npTc"); - unknowns[0].data = (png_byte*)imageInfo.info9Patch.serialize(); - unknowns[0].size = imageInfo.info9Patch.serializedSize(); - // TODO: remove the check below when everything works - checkNinePatchSerialization(&imageInfo.info9Patch, unknowns[0].data); - png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS, - (png_byte*)"npTc", 1); - png_set_unknown_chunks(write_ptr, write_info, unknowns, 1); - // XXX I can't get this to work without forcibly changing - // the location to what I want... which apparently is supposed - // to be a private API, but everything else I have tried results - // in the location being set to what I -last- wrote so I never - // get written. :p - png_set_unknown_chunk_location(write_ptr, write_info, 0, PNG_HAVE_PLTE); - } - - png_write_info(write_ptr, write_info); - - png_bytepp rows; - if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) { - 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); - - 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(Bundle* bundle, const sp& assets, - const sp& 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()); - - 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 postProcessImage(const sp& assets, - ResourceTable* table, const sp& 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/Images.h b/Images.h deleted file mode 100644 index 168e22f..0000000 --- a/Images.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Build resource files from raw assets. -// - -#ifndef IMAGES_H -#define IMAGES_H - -#include "ResourceTable.h" - -status_t preProcessImage(Bundle* bundle, const sp& assets, - const sp& file, String8* outNewLeafName); - -status_t postProcessImage(const sp& assets, - ResourceTable* table, const sp& file); - -#endif diff --git a/Main.cpp b/Main.cpp deleted file mode 100644 index 71b1a3c..0000000 --- a/Main.cpp +++ /dev/null @@ -1,369 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Android Asset Packaging Tool main entry point. -// -#include "Main.h" -#include "Bundle.h" - -#include -#include - -#include -#include -#include - -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] WHAT file.{apk} [asset [asset ...]]\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 ...]] \\\n" - " [-g tolerance] \\\n" - " [-j jarfile] \\\n" - " [-I base-package [-I base-package ...]] \\\n" - " [-A asset-source-dir] [-P public-definitions-file] \\\n" - " [-S resource-sources [-S resource-sources ...]] " - " [-F apk-file] [-J R-file-dir] \\\n" - " [raw-files-dir [raw-files-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 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" - " -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" - " -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" - " and the first match found (left to right) will take precedence." - " -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"); -} - -/* - * 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); - 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 { - 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 '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 '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 '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; - 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/Main.h b/Main.h deleted file mode 100644 index 65c0a8a..0000000 --- a/Main.h +++ /dev/null @@ -1,41 +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 -#include "Bundle.h" -#include "AaptAssets.h" -#include - -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 calcPercent(long uncompressedLen, long compressedLen); - -extern android::status_t writeAPK(Bundle* bundle, - const sp& assets, - const android::String8& outputFile); - -extern android::status_t buildResources(Bundle* bundle, - const sp& assets); - -extern android::status_t writeResourceSymbols(Bundle* bundle, - const sp& assets, const String8& pkgName, bool includePrivate); - -extern bool isValidResourceType(const String8& type); - -ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp& assets); - -extern status_t filterResources(Bundle* bundle, const sp& assets); - -int dumpResources(Bundle* bundle); - -#endif // __MAIN_H diff --git a/Package.cpp b/Package.cpp deleted file mode 100644 index eb7d6f5..0000000 --- a/Package.cpp +++ /dev/null @@ -1,464 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Package assets into Zip files. -// -#include "Main.h" -#include "AaptAssets.h" -#include "ResourceTable.h" - -#include -#include - -#include -#include -#include -#include - -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& assets); -ssize_t processAssets(Bundle* bundle, ZipFile* zip, - const sp& dir, const AaptGroupEntry& ge); -bool processFile(Bundle* bundle, ZipFile* zip, - const sp& group, const sp& 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& assets, - const String8& outputFile) -{ - 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()); - } - } - - 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"); - return result; -} - -ssize_t processAssets(Bundle* bundle, ZipFile* zip, - const sp& 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; igetGroupEntries()[i]; - if (!filter.match(ge.toParams())) { - continue; - } - ssize_t res = processAssets(bundle, zip, assets, ge); - if (res < 0) { - return res; - } - count += res; - } - - return count; -} - -ssize_t processAssets(Bundle* bundle, ZipFile* zip, - const sp& dir, const AaptGroupEntry& ge) -{ - ssize_t count = 0; - - const size_t ND = dir->getDirs().size(); - size_t i; - for (i=0; igetDirs().valueAt(i), ge); - if (res < 0) { - return res; - } - count += res; - } - - const size_t NF = dir->getFiles().size(); - for (i=0; i gp = dir->getFiles().valueAt(i); - ssize_t fi = gp->getFiles().indexOfKey(ge); - if (fi >= 0) { - sp 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& group, const sp& 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& 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; igetEntryByIndex(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) -{ - ssize_t err; - ssize_t count = 0; - const android::Vector& jars = bundle->getJarFiles(); - - size_t N = jars.size(); - for (size_t i=0; i& 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); - } -} - -class ResourceTypeSet : public RefBase, - public KeyedVector > -{ -public: - ResourceTypeSet(); -}; - -ResourceTypeSet::ResourceTypeSet() - :RefBase(), - KeyedVector >() -{ -} - -class ResourceDirIterator -{ -public: - ResourceDirIterator(const sp& set, const String8& resType) - : mResType(resType), mSet(set), mSetPos(0), mGroupPos(0) - { - } - - inline const sp& getGroup() const { return mGroup; } - inline const sp& 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 group; - sp 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 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.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 mSet; - size_t mSetPos; - - sp mGroup; - size_t mGroupPos; - - sp mFile; - String8 mBaseName; - String8 mLeafName; - String8 mPath; - ResTable_config mParams; -}; - -// ========================================================================== -// ========================================================================== -// ========================================================================== - -bool isValidResourceType(const String8& type) -{ - return type == "anim" || type == "drawable" || type == "layout" - || type == "values" || type == "xml" || type == "raw" - || type == "color" || type == "menu"; -} - -static sp getResourceFile(const sp& assets, bool makeIfNecessary=true) -{ - sp group = assets->getFiles().valueFor(String8("resources.arsc")); - sp 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(const sp& assets, const sp& grp) -{ - if (grp->getFiles().size() != 1) { - fprintf(stderr, "WARNING: Multiple AndroidManifest.xml files found, using %s\n", - grp->getFiles().valueAt(0)->getPrintableSource().string()); - } - - sp 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 \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: does not have package attribute.\n", - file->getPrintableSource().string(), block.getLineNumber()); - return UNKNOWN_ERROR; - } - - assets->setPackage(String8(block.getAttributeStringValue(nameIndex, &len))); - - return NO_ERROR; -} - -// ========================================================================== -// ========================================================================== -// ========================================================================== - -static status_t makeFileResources(Bundle* bundle, const sp& assets, - ResourceTable* table, - const sp& 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; -} - -static status_t preProcessImages(Bundle* bundle, const sp& assets, - const sp& set) -{ - ResourceDirIterator it(set, String8("drawable")); - Vector > newNameFiles; - Vector newNamePaths; - ssize_t res; - while ((res=it.next()) == NO_ERROR) { - res = preProcessImage(bundle, assets, it.getFile(), NULL); - if (res != NO_ERROR) { - return res; - } - } - - return NO_ERROR; -} - -status_t postProcessImages(const sp& assets, - ResourceTable* table, - const sp& set) -{ - ResourceDirIterator it(set, String8("drawable")); - ssize_t res; - while ((res=it.next()) == NO_ERROR) { - res = postProcessImage(assets, table, it.getFile()); - if (res != NO_ERROR) { - return res; - } - } - - return res < NO_ERROR ? res : (status_t)NO_ERROR; -} - -static void collect_files(const sp& dir, - KeyedVector >* resources) -{ - const DefaultKeyedVector >& groups = dir->getFiles(); - int N = groups.size(); - for (int i=0; i& group = groups.valueAt(i); - - const DefaultKeyedVector >& files - = group->getFiles(); - - if (files.size() == 0) { - continue; - } - - String8 resType = files.valueAt(0)->getResourceType(); - - ssize_t index = resources->indexOfKey(resType); - - if (index < 0) { - sp set = new ResourceTypeSet(); - set->add(leafName, group); - resources->add(resType, set); - } else { - sp set = resources->valueAt(index); - index = set->indexOfKey(leafName); - if (index < 0) { - set->add(leafName, group); - } else { - sp existingGroup = set->valueAt(index); - int M = files.size(); - for (int j=0; jaddFile(files.valueAt(j)); - } - } - } - } -} - -static void collect_files(const sp& ass, - KeyedVector >* resources) -{ - const Vector >& dirs = ass->resDirs(); - int N = dirs.size(); - - for (int i=0; i d = dirs.itemAt(i); - collect_files(d, resources); - - // don't try to include the res dir - 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 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; - if (index >= 0 && (str=parser.getAttributeStringValue(index, &len)) != NULL) { - if (validChars) { - for (size_t i=0; i 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 void applyFileOverlay(const sp& assets, - const sp& baseSet, - const char *resType) -{ - // Replace any base level files in this category with any found from the overlay - // Also add any found only in the overlay. - sp overlay = assets->getOverlay(); - String8 resTypeString(resType); - - // work through the linked list of overlays - while (overlay.get()) { - KeyedVector >* overlayRes = overlay->getResources(); - - // get the overlay resources of the requested type - ssize_t index = overlayRes->indexOfKey(resTypeString); - if (index >= 0) { - sp 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; overlayIndexindexOfKey(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 overlayGroup = overlaySet->valueAt(overlayIndex); - sp baseGroup = baseSet->valueAt(baseIndex); - - DefaultKeyedVector > baseFiles = - baseGroup->getFiles(); - DefaultKeyedVector > overlayFiles = - overlayGroup->getFiles(); - size_t overlayGroupSize = overlayFiles.size(); - for (size_t overlayGroupIndex = 0; - overlayGroupIndexremoveFile(baseFileIndex); - } else { - // didn't find a match fall through and add it.. - } - baseGroup->addFile(overlayFiles.valueAt(overlayGroupIndex)); - } - } else { - // this group doesn't exist (a file that's only in the overlay) - // add it - baseSet->add(overlaySet->keyAt(overlayIndex), - overlaySet->valueAt(overlayIndex)); - } - } - // this overlay didn't have resources for this type - } - // try next overlay - overlay = overlay->getOverlay(); - } - return; -} - -#define ASSIGN_IT(n) \ - do { \ - ssize_t index = resources->indexOfKey(String8(#n)); \ - if (index >= 0) { \ - n ## s = resources->valueAt(index); \ - } \ - } while (0) - -status_t buildResources(Bundle* bundle, const sp& assets) -{ - // First, look for a package file to parse. This is required to - // be able to generate the resource information. - sp 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(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())); - - // -------------------------------------------------------------- - // First, gather all resource information. - // -------------------------------------------------------------- - - // resType -> leafName -> group - KeyedVector > *resources = - new KeyedVector >; - collect_files(assets, resources); - - sp drawables; - sp layouts; - sp anims; - sp xmls; - sp raws; - sp colors; - sp menus; - - ASSIGN_IT(drawable); - ASSIGN_IT(layout); - ASSIGN_IT(anim); - ASSIGN_IT(xml); - ASSIGN_IT(raw); - ASSIGN_IT(color); - ASSIGN_IT(menu); - - assets->setResources(resources); - // now go through any resource overlays and collect their files - sp current = assets->getOverlay(); - while(current.get()) { - KeyedVector > *resources = - new KeyedVector >; - current->setResources(resources); - collect_files(current, resources); - current = current->getOverlay(); - } - // apply the overlay files to the base set - applyFileOverlay(assets, drawables, "drawable"); - applyFileOverlay(assets, layouts, "layout"); - applyFileOverlay(assets, anims, "anim"); - applyFileOverlay(assets, xmls, "xml"); - applyFileOverlay(assets, raws, "raw"); - applyFileOverlay(assets, colors, "color"); - applyFileOverlay(assets, menus, "menu"); - - bool hasErrors = false; - - if (drawables != NULL) { - err = preProcessImages(bundle, assets, drawables); - if (err == NO_ERROR) { - err = makeFileResources(bundle, assets, &table, drawables, "drawable"); - 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 (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 > *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 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 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); - 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); - 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); - 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); - 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); - 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; - } - - const sp manifestFile(androidManifestFile->getFiles().valueAt(0)); - String8 manifestPath(manifestFile->getPrintableSource()); - - // 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. - err = compileXmlFile(assets, manifestFile, &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(manifestFile->getData(), manifestFile->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 permissionSymbols; - sp 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, block, NULL, "package", - packageIdentChars, true) != 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, block, RESOURCES_ANDROID_NAMESPACE, "name", - isGroup ? packageIdentCharsWithTheStupid - : packageIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - SourcePos srcPos(manifestPath, block.getLineNumber()); - sp syms; - if (!isGroup) { - syms = permissionSymbols; - if (syms == NULL) { - sp symbols = - assets->getSymbolsFor(String8("Manifest")); - syms = permissionSymbols = symbols->addNestedSymbol( - String8("permission"), srcPos); - } - } else { - syms = permissionGroupSymbols; - if (syms == NULL) { - sp 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, block, RESOURCES_ANDROID_NAMESPACE, "name", - packageIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - } else if (strcmp16(block.getElementName(&len), instrumentation16.string()) == 0) { - if (validateAttr(manifestPath, block, RESOURCES_ANDROID_NAMESPACE, "name", - classIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, block, - RESOURCES_ANDROID_NAMESPACE, "targetPackage", - packageIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - } else if (strcmp16(block.getElementName(&len), application16.string()) == 0) { - if (validateAttr(manifestPath, block, RESOURCES_ANDROID_NAMESPACE, "name", - classIdentChars, false) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, block, - RESOURCES_ANDROID_NAMESPACE, "permission", - packageIdentChars, false) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, block, - RESOURCES_ANDROID_NAMESPACE, "process", - processIdentChars, false) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, block, - RESOURCES_ANDROID_NAMESPACE, "taskAffinity", - processIdentChars, false) != ATTR_OKAY) { - hasErrors = true; - } - } else if (strcmp16(block.getElementName(&len), provider16.string()) == 0) { - if (validateAttr(manifestPath, block, RESOURCES_ANDROID_NAMESPACE, "name", - classIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, block, - RESOURCES_ANDROID_NAMESPACE, "authorities", - authoritiesIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, block, - RESOURCES_ANDROID_NAMESPACE, "permission", - packageIdentChars, false) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, 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, block, RESOURCES_ANDROID_NAMESPACE, "name", - classIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, block, - RESOURCES_ANDROID_NAMESPACE, "permission", - packageIdentChars, false) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, block, - RESOURCES_ANDROID_NAMESPACE, "process", - processIdentChars, false) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, 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, block, - RESOURCES_ANDROID_NAMESPACE, "name", - packageIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - } else if (strcmp16(block.getElementName(&len), data16.string()) == 0) { - if (validateAttr(manifestPath, block, - RESOURCES_ANDROID_NAMESPACE, "mimeType", - typeIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - if (validateAttr(manifestPath, block, - RESOURCES_ANDROID_NAMESPACE, "scheme", - schemeIdentChars, true) != ATTR_OKAY) { - hasErrors = true; - } - } - } - } - - if (table.validateLocalizations()) { - hasErrors = true; - } - - if (hasErrors) { - return UNKNOWN_ERROR; - } - - // Generate final compiled manifest file. - manifestFile->clearData(); - err = compileXmlFile(assets, 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 - // -------------------------------------------------------------- - - if (table.hasResources()) { - sp symbols = assets->getSymbolsFor(String8("R")); - err = table.addSymbols(symbols); - if (err < NO_ERROR) { - return err; - } - - sp 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); - } - - NOISY( - ResTable rt; - rt.add(resFile->getData(), resFile->getSize(), NULL); - printf("Generated resources:\n"); - rt.print(); - ) - - // 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 status_t fixupSymbol(String16* inoutSymbol) -{ - inoutSymbol->replaceAll('.', '_'); - inoutSymbol->replaceAll(':', '_'); - return NO_ERROR; -} - -static String16 getAttributeComment(const sp& assets, - const String8& name, - String16* outTypeComment = NULL) -{ - sp 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& assets, - const sp& 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 nsymbols = symbols->getNestedSymbols().valueAt(i); - String16 nclassName16(symbols->getNestedSymbols().keyAt(i)); - String8 realClassName(nclassName16); - if (fixupSymbol(&nclassName16) != NO_ERROR) { - hasErrors = true; - } - String8 nclassName(nclassName16); - - SortedVector idents; - Vector origOrder; - Vector publicFlags; - - size_t a; - size_t NA = nsymbols->getSymbols().size(); - for (a=0; agetSymbols().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 %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(); - - String16 comment = symbols->getComment(realClassName); - fprintf(fp, "%s/** ", indentStr); - if (comment.size() > 0) { - fprintf(fp, "%s\n", String8(comment).string()); - } else { - fprintf(fp, "Attributes that can be used with a %s.\n", nclassName.string()); - } - bool hasTable = false; - for (a=0; a= 0) { - if (!hasTable) { - hasTable = true; - fprintf(fp, - "%s

Includes the following attributes:

\n" - "%s \n" - "%s \n" - "%s \n" - "%s \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()); - } - String16 name(name8); - fixupSymbol(&name); - fprintf(fp, "%s \n", - indentStr, nclassName.string(), - String8(name).string(), - assets->getPackage().string(), - String8(name).string(), - String8(comment).string()); - } - } - if (hasTable) { - fprintf(fp, "%s
AttributeSummary
{@link #%s_%s %s:%s}%s
\n", indentStr); - } - for (a=0; a= 0) { - const AaptSymbolEntry& sym = nsymbols->getSymbols().valueAt(a); - if (!publicFlags.itemAt(a) && !includePrivate) { - continue; - } - String16 name(sym.name); - fixupSymbol(&name); - fprintf(fp, "%s @see #%s_%s\n", - indentStr, nclassName.string(), - String8(name).string()); - } - } - fprintf(fp, "%s */\n", getIndentSpace(indent)); - - fprintf(fp, - "%spublic static final int[] %s = {\n" - "%s", - indentStr, nclassName.string(), - getIndentSpace(indent+1)); - - for (a=0; a= 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); - } - String16 name(name8); - if (fixupSymbol(&name) != NO_ERROR) { - hasErrors = true; - } - - 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, "%s/**\n", indentStr); - if (comment.size() > 0) { - fprintf(fp, "%s

\n%s @attr description\n", indentStr, indentStr); - fprintf(fp, "%s %s\n", indentStr, String8(comment).string()); - } else { - fprintf(fp, - "%s

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, - pub ? assets->getPackage().string() - : assets->getSymbolsPrivatePackage().string(), - String8(name).string(), - indentStr, nclassName.string()); - } - if (typeComment.size() > 0) { - fprintf(fp, "\n\n%s %s\n", indentStr, String8(typeComment).string()); - } - if (comment.size() > 0) { - if (pub) { - fprintf(fp, - "%s

This corresponds to the global attribute" - "%s resource symbol {@link %s.R.attr#%s}.\n", - indentStr, indentStr, - assets->getPackage().string(), - String8(name).string()); - } else { - fprintf(fp, - "%s

This is a private symbol.\n", indentStr); - } - } - fprintf(fp, "%s @attr name %s:%s\n", indentStr, - "android", String8(name).string()); - fprintf(fp, "%s*/\n", indentStr); - fprintf(fp, - "%spublic static final int %s_%s = %d;\n", - indentStr, nclassName.string(), - String8(name).string(), (int)pos); - } - } - } - - indent--; - fprintf(fp, "%s};\n", getIndentSpace(indent)); - return hasErrors ? UNKNOWN_ERROR : NO_ERROR; -} - -static status_t writeSymbolClass( - FILE* fp, const sp& assets, bool includePrivate, - const sp& symbols, const String8& className, int indent) -{ - fprintf(fp, "%spublic %sfinal class %s {\n", - getIndentSpace(indent), - indent != 0 ? "static " : "", className.string()); - indent++; - - size_t i; - status_t err = NO_ERROR; - - size_t N = symbols->getSymbols().size(); - for (i=0; igetSymbols().valueAt(i); - if (sym.typeCode != AaptSymbolEntry::TYPE_INT32) { - continue; - } - if (!includePrivate && !sym.isPublic) { - continue; - } - String16 name(sym.name); - String8 realName(name); - if (fixupSymbol(&name) != NO_ERROR) { - return UNKNOWN_ERROR; - } - String16 comment(sym.comment); - bool haveComment = false; - if (comment.size() > 0) { - haveComment = true; - fprintf(fp, - "%s/** %s\n", - getIndentSpace(indent), String8(comment).string()); - } 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) { - if (!haveComment) { - haveComment = true; - fprintf(fp, - "%s/** %s\n", - getIndentSpace(indent), String8(typeComment).string()); - } else { - fprintf(fp, - "%s %s\n", - getIndentSpace(indent), String8(typeComment).string()); - } - } - if (haveComment) { - fprintf(fp,"%s */\n", getIndentSpace(indent)); - } - fprintf(fp, "%spublic static final int %s=0x%08x;\n", - getIndentSpace(indent), - String8(name).string(), (int)sym.int32Val); - } - - for (i=0; igetSymbols().valueAt(i); - if (sym.typeCode != AaptSymbolEntry::TYPE_STRING) { - continue; - } - if (!includePrivate && !sym.isPublic) { - continue; - } - String16 name(sym.name); - if (fixupSymbol(&name) != NO_ERROR) { - return UNKNOWN_ERROR; - } - String16 comment(sym.comment); - if (comment.size() > 0) { - fprintf(fp, - "%s/** %s\n" - "%s */\n", - getIndentSpace(indent), String8(comment).string(), - getIndentSpace(indent)); - } 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()); - } - fprintf(fp, "%spublic static final String %s=\"%s\";\n", - getIndentSpace(indent), - String8(name).string(), sym.stringVal.string()); - } - - sp styleableSymbols; - - N = symbols->getNestedSymbols().size(); - for (i=0; i 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); - } - 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; -} - -status_t writeResourceSymbols(Bundle* bundle, const sp& assets, - const String8& package, bool includePrivate) -{ - if (!bundle->getRClassDir()) { - return NO_ERROR; - } - - const size_t N = assets->getSymbols().size(); - for (size_t i=0; i 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); - if (err != NO_ERROR) { - return err; - } - fclose(fp); - } - - return NO_ERROR; -} diff --git a/ResourceTable.cpp b/ResourceTable.cpp deleted file mode 100644 index 6f71a1e..0000000 --- a/ResourceTable.cpp +++ /dev/null @@ -1,3491 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Build resource files from raw assets. -// - -#include "ResourceTable.h" - -#include "XMLNode.h" - -#include -#include -#include - -#define NOISY(x) //x - -status_t compileXmlFile(const sp& assets, - const sp& target, - ResourceTable* table, - int options) -{ - sp root = XMLNode::parse(target); - if (root == NULL) { - return UNKNOWN_ERROR; - } - if ((options&XML_COMPILE_STRIP_WHITESPACE) != 0) { - root->removeWhitespace(true, NULL); - } else if ((options&XML_COMPILE_COMPACT_WHITESPACE) != 0) { - root->removeWhitespace(false, NULL); - } - - 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 \"@[+][package:]type:name\"\n" - "or to a theme attribute in the form \"?[package:][type:]name\"."}, - { 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 \"100\"." }, - { booleanArray, sizeof(booleanArray)/2, ResTable_map::TYPE_BOOLEAN, - "a boolean value, either \"true\" or \"false\"." }, - { colorArray, sizeof(colorArray)/2, ResTable_map::TYPE_COLOR, - "a color value, in the form of \"#rgb\", \"#argb\",\n" - "\"#rrggbb\", or \"#aarrggbb\"." }, - { floatArray, sizeof(floatArray)/2, ResTable_map::TYPE_FLOAT, - "a floating point value, such as \"1.2\"."}, - { dimensionArray, sizeof(dimensionArray)/2, ResTable_map::TYPE_DIMENSION, - "a dimension value, which is a floating point number appended with a unit such as \"14.5sp\".\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 \"14.5%\".\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("

Must"); - } - - return String16("

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("

This may also be a reference to a resource (in the form\n" - "\"@[package:]type:name\") or\n" - "theme attribute (in the form\n" - "\"?[package:][type:]name\")\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& 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& 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 \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 '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 '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 '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 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 'localization' attribute value \"%s\" not valid\n", - String8(str).string()); - attr.hasErrors = true; - } - attr.createIfNeeded(outTable); - if (!attr.hasErrors) { - char buf[10]; - 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 , only or \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(" attribute can not be used inside a flags format\n"); - attr.hasErrors = true; - } else { - SourcePos(in->getPrintableSource(), block.getLineNumber()) - .error(" 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 or \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 or \n"); - attr.hasErrors = true; - } - if (!attr.hasErrors && !ResTable::stringToInt(value.string(), value.size(), NULL)) { - SourcePos(in->getPrintableSource(), block.getLineNumber()) - .error("Tag or '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("

\n\n" - "\n" - "\n" - "\n" - "")); - } - - enumOrFlagsComment.append(String16("\n")); - - 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 where 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 where 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
ConstantValueDescription
")); - enumOrFlagsComment.append(itemIdent); - enumOrFlagsComment.append(String16("")); - enumOrFlagsComment.append(value); - enumOrFlagsComment.append(String16("")); - if (block.getComment(&len)) { - enumOrFlagsComment.append(String16(block.getComment(&len))); - } - enumOrFlagsComment.append(String16("
")); - 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& 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 pseudolocalize, - const bool overwrite, - ResourceTable* outTable) -{ - status_t err; - const String16 item16("item"); - - String16 str; - Vector spans; - err = parseStyledString(bundle, in->getPrintableSource().string(), - block, item16, &str, &spans, - 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; -} - - -status_t parseAndAddEntry(Bundle* bundle, - const sp& 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 pseudolocalize, - const bool overwrite, - ResourceTable* outTable) -{ - status_t err; - - String16 str; - Vector spans; - err = parseStyledString(bundle, in->getPrintableSource().string(), block, - curTag, &str, curIsStyled ? &spans : NULL, - pseudolocalize); - - if (err < NO_ERROR) { - return err; - } - - 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& assets, - const sp& 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 private_symbols16("private-symbols"); - 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 false16("false"); - - const String16 myPackage(assets->getPackage()); - - bool hasErrors = false; - - 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 curIsStyled = false; - bool curIsPseudolocalizable = false; - 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 \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 \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 = ident+1; - } - } else if (nextPublicId == 0) { - srcPos.error("No 'id' attribute supplied ," - " and no previous id defined in this file.\n"); - hasErrors = localHasErrors = true; - } else if (!localHasErrors) { - ident = nextPublicId; - nextPublicId++; - } - - if (!localHasErrors) { - err = outTable->addPublic(srcPos, myPackage, type, name, ident); - if (err < NO_ERROR) { - hasErrors = localHasErrors = true; - } - } - if (!localHasErrors) { - sp 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), 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 \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), 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 \n"); - hasErrors = localHasErrors = true; - } - ident = String16(block.getAttributeStringValue(identIdx, &len)); - - sp symbols = assets->getSymbolsFor(String8("R")); - if (!localHasErrors) { - if (symbols != NULL) { - symbols = symbols->addNestedSymbol(String8("styleable"), srcPos); - } - sp 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 , only \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 where 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 '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 \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; - - 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)); - } - } - - if (name.size() > 0) { - if (translatable == false16) { - // 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); - } - } - - 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 \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; - 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 'format' attribute value \"%s\" not valid\n", - String8(formatStr).string()); - hasErrors = localHasErrors = true; - } - } - } else if (strcmp16(block.getElementName(&len), string_array16.string()) == 0) { - curTag = &string_array16; - curType = array16; - curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING; - curIsBag = 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; - } 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 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); - 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 \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 inside \n"); - hasErrors = localHasErrors = true; - } - } else { - SourcePos(in->getPrintableSource(), block.getLineNumber()).error( - "A 'quantity' attribute is required for inside \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 \n"); - hasErrors = localHasErrors = true; - } - } - - ResXMLParser::ResXMLPosition parserPosition; - block.getPosition(&parserPosition); - - err = parseAndAddBag(bundle, in, &block, curParams, myPackage, curType, - ident, parentIdent, itemIdent, curFormat, - 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, 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 where 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, 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, true, false, 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& 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 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 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 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 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* 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 e = getEntry(package, type, name, sourcePos, 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 replace, bool isId) -{ - // 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 e = getEntry(package, type, name, sourcePos, params); - if (e == NULL) { - return UNKNOWN_ERROR; - } - - // If a parent is explicitly specified, set it. - if (bagParent.size() > 0) { - String16 curPar = e->getParent(); - if (curPar.size() > 0 && curPar != bagParent) { - sourcePos.error("Conflicting parents specified, was '%s', now '%s'\n", - String8(e->getParent()).string(), - String8(bagParent).string()); - return UNKNOWN_ERROR; - } - e->setParent(bagParent); - } - - return e->makeItABag(sourcePos); -} - -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* 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 e = getEntry(package, type, name, sourcePos, params); - if (e == NULL) { - return UNKNOWN_ERROR; - } - - // If a parent is explicitly specified, set it. - if (bagParent.size() > 0) { - String16 curPar = e->getParent(); - if (curPar.size() > 0 && curPar != bagParent) { - sourcePos.error("Conflicting parents specified, was '%s', now '%s'\n", - String8(e->getParent()).string(), - String8(bagParent).string()); - return UNKNOWN_ERROR; - } - 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 p = mPackages.valueFor(package); - if (p != NULL) { - sp t = p->getTypes().valueFor(type); - if (t != NULL) { - sp c = t->getConfigs().valueFor(name); - if (c != 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 p = mPackages.valueFor(package); - if (p != NULL) { - sp t = p->getTypes().valueFor(type); - if (t != NULL) { - sp 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 p = mPackages.valueFor(package); - if (p != NULL) { - sp t = p->getTypes().valueFor(type); - if (t != NULL) { - sp c = t->getConfigs().valueFor(name); - if (c != NULL) { - c->appendTypeComment(comment); - return true; - } - } - } - return false; -} - -size_t ResourceTable::size() const { - return mPackages.size(); -} - -size_t ResourceTable::numLocalResources() const { - return mNumLocal; -} - -bool ResourceTable::hasResources() const { - return mNumLocal > 0; -} - -sp ResourceTable::flatten(Bundle* bundle) -{ - sp 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& p, - const sp& 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 -{ - sp 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 rid; - } - return Res_MAKEID(p->getAssignedId()-1, - Res_GETTYPE(rid), - Res_GETENTRY(rid)); - } - - sp t = p->getTypes().valueFor(type); - if (t == NULL) return 0; - sp 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::getResId(const String16& ref, - const String16* defType, - const String16* defPackage, - const char** outErrorMsg, - bool onlyPublic) const -{ - String16 package, type, name; - if (!ResTable::expandResourceRef( - ref.string(), ref.size(), &package, &type, &name, - defType, defPackage ? defPackage:&mAssetsPackage, - outErrorMsg)) { - 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); - 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* style, - String16* outStr, void* accessorCookie, - uint32_t attrType) -{ - 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) { - if (style != NULL && style->size() > 0) { - outValue->data = pool->add(finalStr, *style); - } else { - outValue->data = pool->add(finalStr, true); - } - } 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 p = mPackages.valueFor(package); - if (p == NULL) return 0; - sp t = p->getTypes().valueFor(type); - if (t == NULL) return 0; - sp 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* outKeys) -{ - sp e = getEntry(attrID); - if (e != NULL) { - const size_t N = e->getBag().size(); - for (size_t i=0; igetBag().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 e = getEntry(attrID); - if (e != NULL) { - const size_t N = e->getBag().size(); - for (size_t i=0; igetBag().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 e = getEntry(attrID); - if (e != NULL) { - const size_t N = e->getBag().size(); - - const char16_t* end = name + nameLen; - const char16_t* pos = name; - bool failed = false; - while (pos < end && !failed) { - const char16_t* start = pos; - end++; - while (pos < end && *pos != '|') { - pos++; - } - - String16 nameStr(start, pos-start); - size_t i; - for (i=0; igetBag().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; - } - if (pos < end) { - 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 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 t = p->getOrderedTypes().itemAt(ti); - if (t == NULL) { - continue; - } - const size_t N = t->getOrderedConfigs().size(); - for (size_t ci=0; ci c = t->getOrderedConfigs().itemAt(ci); - if (c == NULL) { - continue; - } - const size_t N = c->getEntries().size(); - for (size_t ei=0; ei 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 attr = p->getType(String16("attr"), unknown); - - // Assign indices... - for (ti=0; ti 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 c = t->getOrderedConfigs().itemAt(ei); - if (c == NULL) { - continue; - } - c->setEntryIndex(ei); - } - } - - // Assign resource IDs to keys in bags... - for (ti=0; ti t = p->getOrderedTypes().itemAt(ti); - if (t == NULL) { - continue; - } - const size_t N = t->getOrderedConfigs().size(); - for (size_t ci=0; ci 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 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& outSymbols) { - const size_t N = mOrderedPackages.size(); - size_t pi; - - for (pi=0; pi 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 t = p->getOrderedTypes().itemAt(ti); - if (t == NULL) { - continue; - } - const size_t N = t->getOrderedConfigs().size(); - sp typeSymbols; - typeSymbols = outSymbols->addNestedSymbol(String8(t->getName()), t->getPos()); - for (size_t ci=0; ci 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 >::iterator nameIter = mLocalizations.begin(); - nameIter != mLocalizations.end(); - nameIter++) { - const set& 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::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: error: " - "*** string '%s' has no default or required localization " - "for '%s' in %s\n", - String8(nameIter->first).string(), - config.string(), - mBundle->getResourceSourceDirs()[0]); - err = UNKNOWN_ERROR; - } - } - } - } - } while (comma != NULL); - } - } - - return err; -} - - -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()); - } - SortedVector& 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::match(int axis, uint32_t value) -{ - 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& sv = mData.valueAt(index); - return sv.indexOf(value) >= 0; -} - -bool -ResourceFilter::match(const ResTable_config& config) -{ - if (config.locale) { - uint32_t locale = (config.country[1] << 24) | (config.country[0] << 16) - | (config.language[1] << 8) | (config.language[0]); - if (!match(AXIS_LANGUAGE, locale)) { - return false; - } - } - if (!match(AXIS_ORIENTATION, config.orientation)) { - return false; - } - if (!match(AXIS_DENSITY, config.density)) { - return false; - } - if (!match(AXIS_TOUCHSCREEN, config.touchscreen)) { - return false; - } - if (!match(AXIS_KEYSHIDDEN, config.inputFlags)) { - return false; - } - if (!match(AXIS_KEYBOARD, config.keyboard)) { - return false; - } - if (!match(AXIS_NAVIGATION, config.navigation)) { - return false; - } - if (!match(AXIS_SCREENSIZE, config.screenSize)) { - return false; - } - if (!match(AXIS_VERSION, config.version)) { - return false; - } - return true; -} - -status_t ResourceTable::flatten(Bundle* bundle, const sp& dest) -{ - ResourceFilter filter; - status_t err = filter.parse(bundle->getConfigurations()); - if (err != NO_ERROR) { - return err; - } - - const size_t N = mOrderedPackages.size(); - size_t pi; - - // Iterate through all data, collecting all values (strings, - // references, etc). - StringPool valueStrings; - for (pi=0; pi p = mOrderedPackages.itemAt(pi); - if (p->getTypes().size() == 0) { - // Empty, skip! - continue; - } - - StringPool typeStrings; - StringPool keyStrings; - - const size_t N = p->getOrderedTypes().size(); - for (size_t ti=0; ti t = p->getOrderedTypes().itemAt(ti); - if (t == NULL) { - typeStrings.add(String16(""), false); - continue; - } - typeStrings.add(t->getName(), false); - - const size_t N = t->getOrderedConfigs().size(); - for (size_t ci=0; ci c = t->getOrderedConfigs().itemAt(ci); - if (c == NULL) { - continue; - } - const size_t N = c->getEntries().size(); - for (size_t ei=0; eigetEntries().keyAt(ei); - if (!filter.match(config)) { - continue; - } - sp e = c->getEntries().valueAt(ei); - if (e == NULL) { - continue; - } - e->setNameIndex(keyStrings.add(e->getName(), true)); - status_t err = e->prepareFlatten(&valueStrings, this); - if (err != NO_ERROR) { - return err; - } - } - } - } - - p->setTypeStrings(typeStrings.createStringBlock()); - p->setKeyStrings(keyStrings.createStringBlock()); - } - - ssize_t strAmt = 0; - - // Now build the array of package chunks. - Vector > flatPackages; - for (pi=0; pi 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 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 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; tigetTypeStrings().stringAt(ti, &len)); - sp t = p->getTypes().valueFor(typeName); - LOG_ALWAYS_FATAL_IF(t == NULL && typeName != String16(""), - "Type name %s not found", - String8(typeName).string()); - - const size_t N = t != NULL ? t->getOrderedConfigs().size() : 0; - - // 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 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; cigetEntries().keyAt(ci))) { - continue; - } - for (size_t cj=ci+1; cjgetEntries().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; cigetUniqueConfigs().itemAt(ci); - - NOISY(printf("Writing config %d config: imsi:%d/%d lang:%c%c cnt:%c%c " - "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%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.touchscreen, - config.density, - config.keyboard, - config.inputFlags, - config.navigation, - config.screenWidth, - config.screenHeight)); - - if (!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 touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%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.touchscreen, - tHeader->config.density, - tHeader->config.keyboard, - tHeader->config.inputFlags, - tHeader->config.navigation, - tHeader->config.screenWidth, - tHeader->config.screenHeight)); - tHeader->config.swapHtoD(); - - // Build the entries inside of this type. - for (size_t ei=0; ei cl = t->getOrderedConfigs().itemAt(ei); - sp 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; - } - } 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); - } - } - - // 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; piwriteData(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, - "\n" - "\n" - "\n"); - - writePublicDefinitions(package, fp, true); - writePublicDefinitions(package, fp, false); - - fprintf(fp, - "\n" - "\n"); -} - -void ResourceTable::writePublicDefinitions(const String16& package, FILE* fp, bool pub) -{ - bool didHeader = false; - - sp pkg = mPackages.valueFor(package); - if (pkg != NULL) { - const size_t NT = pkg->getOrderedTypes().size(); - for (size_t i=0; i 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 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," \n\n"); - } else { - fprintf(fp," \n\n"); - } - didHeader = true; - } - if (!pub) { - const size_t NE = c->getEntries().size(); - for (size_t k=0; kgetEntries().valueAt(k)->getPos(); - if (pos.file != "") { - fprintf(fp," \n", - pos.file.string(), pos.line); - } - } - } - fprintf(fp, " \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* _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* 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* 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::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; ihasBagOrEntry(key, &id16, &package)) { - String16 value("false"); - status_t err = table->addEntry(SourcePos(String8(""), 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("", 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; igetResId(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) -{ - 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)) { - return UNKNOWN_ERROR; - } - } else if (mType == TYPE_BAG) { - const size_t N = mBag.size(); - for (size_t i=0; istringToValue(&it.parsedValue, strings, - it.value, false, true, it.bagKeyId, - &it.style, NULL, &ac, it.format)) { - 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; -} - -ssize_t ResourceTable::Entry::flatten(Bundle* bundle, const sp& 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 items; - for (i=0; iwriteData(&mapHeader, sizeof(mapHeader)); - if (err != NO_ERROR) { - fprintf(stderr, "ERROR: out of memory creating ResTable_entry\n"); - return err; - } - - for (i=0; iwriteData(&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; -} - -sp ResourceTable::Type::getEntry(const String16& entry, - const SourcePos& sourcePos, - const ResTable_config* config, - bool doSetIndex) -{ - int pos = -1; - sp c = mConfigs.valueFor(entry); - if (c == 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 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 w:%d h:%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)); - } 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 > origOrder(mOrderedConfigs); - bool hasError = false; - - size_t i; - for (i=0; i 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 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 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::Package::getType(const String16& type, - const SourcePos& sourcePos, - bool doSetIndex) -{ - sp 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& 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& 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& data, - ResStringPool* strings, - DefaultKeyedVector* 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; iadd(String16(strings->stringAt(i, &len)), i); - } - } - return err; -} - -status_t ResourceTable::Package::applyPublicTypeOrder() -{ - size_t N = mOrderedTypes.size(); - Vector > origOrder(mOrderedTypes); - - size_t i; - for (i=0; i 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 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 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::getPackage(const String16& package) -{ - sp 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::getType(const String16& package, - const String16& type, - const SourcePos& sourcePos, - bool doSetIndex) -{ - sp p = getPackage(package); - if (p == NULL) { - return NULL; - } - return p->getType(type, sourcePos, doSetIndex); -} - -sp ResourceTable::getEntry(const String16& package, - const String16& type, - const String16& name, - const SourcePos& sourcePos, - const ResTable_config* config, - bool doSetIndex) -{ - sp t = getType(package, type, sourcePos, doSetIndex); - if (t == NULL) { - return NULL; - } - return t->getEntry(name, sourcePos, config, doSetIndex); -} - -sp 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 p; - for (i=0; i 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 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 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 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 e = getEntry(resID); - if (e == NULL) { - return NULL; - } - - const size_t N = e->getBag().size(); - for (size_t i=0; igetBag().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 e = getEntry(resID); - const size_t N = e->getBag().size(); - size_t i; - for (i=0; igetBag().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/ResourceTable.h b/ResourceTable.h deleted file mode 100644 index e8fbd9b..0000000 --- a/ResourceTable.h +++ /dev/null @@ -1,534 +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 -#include - -using namespace std; - -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_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& assets, - const sp& target, - ResourceTable* table, - int options = XML_COMPILE_STANDARD_RESOURCE); - -status_t compileResourceFile(Bundle* bundle, - const sp& assets, - const sp& 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; - - ResourceTable(Bundle* bundle, const String16& assetsPackage); - - status_t addIncludedResources(Bundle* bundle, const sp& 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* 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 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* 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& 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); - - size_t size() const; - size_t numLocalResources() const; - bool hasResources() const; - - sp 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& p, - const sp& t, - uint32_t nameId); - - uint32_t getResId(const String16& package, - const String16& type, - const String16& name, - bool onlyPublic = false) const; - - uint32_t getResId(const String16& ref, - const String16* defType = NULL, - const String16* defPackage = NULL, - const char** outErrorMsg = NULL, - bool onlyPublic = false) 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* style = NULL, - String16* outStr = NULL, void* accessorCookie = NULL, - uint32_t attrType = ResTable_map::TYPE_ANY); - - status_t assignResourceIds(); - status_t addSymbols(const sp& outSymbols = NULL); - void addLocalization(const String16& name, const String8& locale); - status_t validateLocalizations(void); - - status_t flatten(Bundle*, const sp& 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* 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* _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 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 setItem(const SourcePos& pos, - const String16& value, - const Vector* 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* 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& 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); - - ssize_t flatten(Bundle*, const sp& data, bool isPublic); - - const SourcePos& getPos() const { return mPos; } - - private: - String16 mName; - String16 mParent; - type mType; - Item mItem; - int32_t mItemFormat; - KeyedVector mBag; - int32_t mNameIndex; - uint32_t mParentId; - SourcePos mPos; - }; - - struct ConfigDescription : public ResTable_config { - ConfigDescription() { - memset(this, 0, sizeof(*this)); - size = sizeof(ResTable_config); - } - ConfigDescription(const ResTable_config&o) { - *static_cast(this) = o; - size = sizeof(ResTable_config); - } - ConfigDescription(const ConfigDescription&o) { - *static_cast(this) = o; - } - - ConfigDescription& operator=(const ResTable_config& o) { - *static_cast(this) = o; - size = sizeof(ResTable_config); - return *this; - } - ConfigDescription& operator=(const ConfigDescription& o) { - *static_cast(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; } - }; - - 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) { - mEntries.add(config, entry); - } - - const DefaultKeyedVector >& getEntries() const { return mEntries; } - private: - const String16 mName; - const SourcePos mPos; - String16 mComment; - String16 mTypeComment; - bool mPublic; - SourcePos mPublicSourcePos; - int32_t mEntryIndex; - DefaultKeyedVector > 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); - - String16 getName() const { return mName; } - sp getEntry(const String16& entry, - const SourcePos& pos, - const ResTable_config* config = NULL, - bool doSetIndex = 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& getUniqueConfigs() const { return mUniqueConfigs; } - - const DefaultKeyedVector >& getConfigs() const { return mConfigs; } - const Vector >& getOrderedConfigs() const { return mOrderedConfigs; } - - const SourcePos& getPos() const { return mPos; } - private: - String16 mName; - SourcePos* mFirstPublicSourcePos; - DefaultKeyedVector mPublic; - SortedVector mUniqueConfigs; - DefaultKeyedVector > mConfigs; - Vector > mOrderedConfigs; - 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 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 getTypeStringsData() const { return mTypeStringsData; } - status_t setTypeStrings(const sp& data); - - const ResStringPool& getKeyStrings() const { return mKeyStrings; } - uint32_t indexOfKeyString(const String16& s) const { return mKeyStringsMapping.valueFor(s); } - const sp getKeyStringsData() const { return mKeyStringsData; } - status_t setKeyStrings(const sp& data); - - status_t applyPublicTypeOrder(); - - const DefaultKeyedVector >& getTypes() const { return mTypes; } - const Vector >& getOrderedTypes() const { return mOrderedTypes; } - - private: - status_t setStrings(const sp& data, - ResStringPool* strings, - DefaultKeyedVector* mappings); - - const String16 mName; - const ssize_t mIncludedId; - DefaultKeyedVector > mTypes; - Vector > mOrderedTypes; - sp mTypeStringsData; - sp mKeyStringsData; - ResStringPool mTypeStrings; - ResStringPool mKeyStrings; - DefaultKeyedVector mTypeStringsMapping; - DefaultKeyedVector mKeyStringsMapping; - }; - -private: - void writePublicDefinitions(const String16& package, FILE* fp, bool pub); - sp getPackage(const String16& package); - sp getType(const String16& package, - const String16& type, - const SourcePos& pos, - bool doSetIndex = false); - sp getEntry(const String16& package, - const String16& type, - const String16& name, - const SourcePos& pos, - const ResTable_config* config = NULL, - bool doSetIndex = false); - sp 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 mAssets; - DefaultKeyedVector > mPackages; - Vector > 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 > mLocalizations; -}; - -class ResourceFilter -{ -public: - ResourceFilter() : mData(), mContainsPseudo(false) {} - status_t parse(const char* arg); - bool match(int axis, uint32_t value); - bool match(const ResTable_config& config); - inline bool containsPseudo() { return mContainsPseudo; } - -private: - KeyedVector > mData; - bool mContainsPseudo; -}; - - -#endif diff --git a/SourcePos.cpp b/SourcePos.cpp deleted file mode 100644 index 2761d18..0000000 --- a/SourcePos.cpp +++ /dev/null @@ -1,171 +0,0 @@ -#include "SourcePos.h" - -#include -#include - -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 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::const_iterator it; - for (it=g_errors.begin(); it!=g_errors.end(); it++) { - it->print(to); - } -} - - - diff --git a/SourcePos.h b/SourcePos.h deleted file mode 100644 index 33f72a9..0000000 --- a/SourcePos.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef SOURCEPOS_H -#define SOURCEPOS_H - -#include -#include - -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/StringPool.cpp b/StringPool.cpp deleted file mode 100644 index 878d3b1..0000000 --- a/StringPool.cpp +++ /dev/null @@ -1,369 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Build resource files from raw assets. -// - -#include "StringPool.h" - -#include - -#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) -{ - const size_t NS = pool->size(); - for (size_t s=0; sstringAt(s, &len)).string()); - } -} - -StringPool::StringPool(bool sorted) - : mSorted(sorted), mValues(-1), mIdents(-1) -{ -} - -ssize_t StringPool::add(const String16& value, bool mergeDuplicates) -{ - return add(String16(), value, mergeDuplicates); -} - -ssize_t StringPool::add(const String16& value, const Vector& spans) -{ - ssize_t res = add(String16(), value, false); - if (res >= 0) { - addStyleSpans(res, spans); - } - return res; -} - -ssize_t StringPool::add(const String16& ident, const String16& value, - bool mergeDuplicates) -{ - if (ident.size() > 0) { - ssize_t idx = mIdents.valueFor(ident); - if (idx >= 0) { - fprintf(stderr, "ERROR: Duplicate string identifier %s\n", - String8(mEntries[idx].value).string()); - return UNKNOWN_ERROR; - } - } - - 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; - } - } - - const bool first = vidx < 0; - if (first || !mergeDuplicates) { - pos = mEntryArray.add(eidx); - if (first) { - vidx = mValues.add(value, pos); - const size_t N = mEntryArrayToValues.size(); - for (size_t i=0; i= vidx) { - e++; - } - } - } - mEntryArrayToValues.add(vidx); - if (!mSorted) { - entry& ent = mEntries.editItemAt(eidx); - ent.indices.add(pos); - } - } - - if (ident.size() > 0) { - mIdents.add(ident, vidx); - } - - 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& spans) -{ - const size_t N=spans.size(); - for (size_t i=0; i StringPool::createStringBlock() -{ - sp pool = new AaptFile(String8(), AaptGroupEntry(), - String8()); - status_t err = writeStringBlock(pool); - return err == NO_ERROR ? pool : NULL; -} - -status_t StringPool::writeStringBlock(const sp& pool) -{ - // Allow appending. Sorry this is a little wacky. - if (pool->getSize() > 0) { - sp 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; ieditData(preSize) == NULL) { - fprintf(stderr, "ERROR: Out of memory for string pool\n"); - return NO_MEMORY; - } - - size_t strPos = 0; - for (i=0; i 0x7fff ? sizeof(uint32_t) : sizeof(uint16_t); - const size_t totalSize = lenSize + ((strSize+1)*sizeof(uint16_t)); - - ent.offset = strPos; - uint16_t* dat = (uint16_t*)pool->editData(preSize + strPos + totalSize); - if (dat == NULL) { - fprintf(stderr, "ERROR: Out of memory for string pool\n"); - return NO_MEMORY; - } - dat += (preSize+strPos)/sizeof(uint16_t); - if (lenSize > sizeof(uint16_t)) { - *dat = htods(0x8000 | ((strSize>>16)&0x7ffff)); - dat++; - } - *dat++ = htods(strSize); - strcpy16_htod(dat, ent.value); - - strPos += lenSize + (strSize+1)*sizeof(uint16_t); - } - - // 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; ieditData(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; iname.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 (mSorted) { - header->flags |= htodl(ResStringPool_header::SORTED_FLAG); - } - header->stringsStart = htodl(preSize); - header->stylesStart = htodl(STYLES > 0 ? (preSize+strPos) : 0); - - // Write string index array. - - uint32_t* index = (uint32_t*)(header+1); - if (mSorted) { - for (i=0; i(entryAt(i)); - ent.indices.clear(); - ent.indices.add(i); - *index++ = htodl(ent.offset); - } - } else { - for (i=0; i* 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* 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/StringPool.h b/StringPool.h deleted file mode 100644 index 9082b37..0000000 --- a/StringPool.h +++ /dev/null @@ -1,148 +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 -#include -#include - -#include -#include -#include -#include -#include - -#include - -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) { } - entry(const entry& o) : value(o.value), offset(o.offset), indices(o.indices) { } - - String16 value; - size_t offset; - Vector indices; - }; - - 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 spans; - }; - - /** - * If 'sorted' is true, then the final strings in the resource data - * structure will be generated in sorted order. This allow for fast - * lookup with ResStringPool::indexOfString() (O(log n)), at the expense - * of support for styled string entries (which requires the same string - * be included multiple times in the pool). - */ - explicit StringPool(bool sorted = 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. Note that - * if this string pool is sorted, the returned index will not be valid - * when the pool is finally written. - */ - ssize_t add(const String16& value, bool mergeDuplicates = false); - - ssize_t add(const String16& value, const Vector& spans); - - ssize_t add(const String16& ident, const String16& value, - bool mergeDuplicates = false); - - status_t addStyleSpan(size_t idx, const String16& name, - uint32_t start, uint32_t end); - status_t addStyleSpans(size_t idx, const Vector& spans); - status_t addStyleSpan(size_t idx, const entry_style_span& span); - - size_t size() const; - - const entry& entryAt(size_t idx) const; - - size_t countIdentifiers() const; - - sp createStringBlock(); - - status_t writeStringBlock(const sp& 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* offsetsForString(const String16& val) const; - -private: - const bool mSorted; - // Raw array of unique strings, in some arbitrary order. - Vector 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). - Vector mEntryArray; - // Optional style span information associated with each index of - // mEntryArray. - Vector mEntryStyleArray; - // Mapping from indices in mEntryArray to indices in mValues. - Vector mEntryArrayToValues; - // Unique set of all the strings added to the pool, mapped to - // the first index of mEntryArray where the value was added. - DefaultKeyedVector mValues; - // Unique set of all (optional) identifiers of strings in the - // pool, mapping to indices in mEntries. - DefaultKeyedVector mIdents; - -}; - -#endif - diff --git a/XMLNode.cpp b/XMLNode.cpp deleted file mode 100644 index d476567..0000000 --- a/XMLNode.cpp +++ /dev/null @@ -1,1295 +0,0 @@ -// -// Copyright 2006 The Android Open Source Project -// -// Build resource files from raw assets. -// - -#include "XMLNode.h" -#include "ResourceTable.h" - -#include -#include -#include -#include - -#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_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_PRV_PREFIX(RESOURCES_ROOT_PRV_NAMESPACE); - -String16 getNamespaceResourcePackage(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)) { - 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 parseStyledString(Bundle* bundle, - const char* fileName, - ResXMLTree* inXml, - const String16& endTag, - String16* outString, - Vector* outSpans, - bool pseudolocalize) -{ - Vector 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 { - 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; igetLineNumber()).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; aigetAttributeCount(); 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(); - - if (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& namespaces, - const uint16_t* ns) -{ - String8 str; - if (ns != NULL) { - str = String8(ns); - const size_t N = namespaces.size(); - for (size_t i=0; irestart(); - - Vector 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 \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; igetAttributeNameResID(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\"", - String8(block->getAttributeStringValue(i, &len)).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\")", String8(val).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 = ""; - } - 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 = ""; - } - 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(), String8(block->getText(&len)).string()); - } - } - - block->restart(); -} - -status_t parseXMLResource(const sp& file, ResXMLTree* outTree, - bool stripAll, bool keepComments, - const char** cDataTags) -{ - sp 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 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::parse(const sp& 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) -{ - if (isNamespace) { - mNamespacePrefix = s1; - mNamespaceUri = s2; - } else { - mNamespaceUri = s1; - mElementName = s2; - } -} - -XMLNode::XMLNode(const String8& filename) - : mFilename(filename) -{ -} - -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 >& XMLNode::getChildren() const -{ - return mChildren; -} - -const Vector& - XMLNode::getAttributes() const -{ - return mAttributes; -} - -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; -} - -status_t XMLNode::addChild(const sp& 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::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; - } - 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 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& 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; isetCurrentXmlPos(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; iparseValues(assets, table); - if (err != NO_ERROR) { - hasErrors = true; - } - } - return hasErrors ? UNKNOWN_ERROR : NO_ERROR; -} - -status_t XMLNode::assignResourceIds(const sp& 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 %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; iassignResourceIds(assets, table); - if (err < NO_ERROR) { - hasErrors = true; - } - } - - return hasErrors ? UNKNOWN_ERROR : NO_ERROR; -} - -status_t XMLNode::flatten(const sp& dest, - bool stripComments, bool stripRawValues) const -{ - StringPool strings; - Vector 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 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; ieditData(); - 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 0) { - elemNs.append(":"); - } - printf("%s E: %s%s", prefix.string(), - elemNs.string(), String8(getElementName()).string()); - int N = mAttributes.size(); - for (i=0; i 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() : "", - String8(getNamespaceUri()).string()); - } else { - printf("%s C: \"%s\"\n", prefix.string(), String8(getCData()).string()); - } - int N = mChildren.size(); - for (i=0; iprint(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 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 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 node = NULL; - if (st->stack.size() == 0) { - return; - } - sp 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 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 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* outResIds, - bool stripComments, bool stripRawValues) const -{ - collect_attr_strings(dest, outResIds, true); - - int i; - 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 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; icollect_strings(dest, outResIds, - stripComments, stripRawValues); - } - - return NO_ERROR; -} - -status_t XMLNode::collect_attr_strings(StringPool* outPool, - Vector* outResIds, bool allAttrs) const { - const int NA = mAttributes.size(); - - for (int i=0; i* 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; jitemAt(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* outResIds) const -{ - collect_attr_strings(outPool, outResIds, false); - - const int NC = mChildren.size(); - - for (int i=0; icollect_resid_strings(outPool, outResIds); - } - - return NO_ERROR; -} - -status_t XMLNode::flatten_node(const StringPool& strings, const sp& 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; - - 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 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)); - - dest->writeData(&node, sizeof(node)); - if (extSize > 0) { - dest->writeData(extData, extSize); - } - - for (i=0; i 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; iflatten_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) { - 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/XMLNode.h b/XMLNode.h deleted file mode 100644 index 86548a2..0000000 --- a/XMLNode.h +++ /dev/null @@ -1,184 +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* outSpans, - bool isPseudolocalizable); - -void printXMLBlock(ResXMLTree* block); - -status_t parseXMLResource(const sp& file, ResXMLTree* outTree, - bool stripAll=true, bool keepComments=false, - const char** cDataTags=NULL); - -class XMLNode : public RefBase -{ -public: - static sp parse(const sp& file); - - static inline - sp newNamespace(const String8& filename, const String16& prefix, const String16& uri) { - return new XMLNode(filename, prefix, uri, true); - } - - static inline - sp newElement(const String8& filename, const String16& ns, const String16& name) { - return new XMLNode(filename, ns, name, false); - } - - static inline - sp 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 >& getChildren() 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& getAttributes() const; - - const String16& getCData() const; - - const String16& getComment() const; - - int32_t getStartLineNumber() const; - int32_t getEndLineNumber() const; - - status_t addChild(const sp& child); - - 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); - - status_t parseValues(const sp& assets, ResourceTable* table); - - status_t assignResourceIds(const sp& assets, - const ResourceTable* table = NULL); - - status_t flatten(const sp& dest, bool stripComments, - bool stripRawValues) const; - - void print(int indent=0); - -private: - struct ParseState - { - String8 filename; - XML_Parser parser; - sp root; - Vector > 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* outResIds, - bool stripComments, bool stripRawValues) const; - - status_t collect_attr_strings(StringPool* outPool, - Vector* outResIds, bool allAttrs) const; - - status_t collect_resid_strings(StringPool* outPool, - Vector* outResIds) const; - - status_t flatten_node(const StringPool& strings, const sp& dest, - bool stripComments, bool stripRawValues) const; - - String16 mNamespacePrefix; - String16 mNamespaceUri; - String16 mElementName; - Vector > mChildren; - Vector mAttributes; - KeyedVector mAttributeOrder; - uint32_t mNextAttributeIndex; - String16 mChars; - Res_value mCharsValue; - String16 mComment; - String8 mFilename; - int32_t mStartLineNumber; - int32_t mEndLineNumber; -}; - -#endif diff --git a/printapk.cpp b/printapk.cpp deleted file mode 100644 index 4cf73d8..0000000 --- a/printapk.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -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; tableIndexsize(); - for (size_t stringIndex=0; stringIndexstringAt(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 - - - diff --git a/tests/plurals/res/values/strings.xml b/tests/plurals/res/values/strings.xml deleted file mode 100644 index 1c1fc19..0000000 --- a/tests/plurals/res/values/strings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - OK - - A dog - Some dogs - - diff --git a/tests/plurals/run.sh b/tests/plurals/run.sh deleted file mode 100755 index 4d39e10..0000000 --- a/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