From a189615a5671748c348da8ab79042e9e2746eb5e Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Thu, 15 Jan 2009 16:12:10 -0800 Subject: [PATCH 1/1] auto import from //branches/cupcake/...@126645 --- AaptAssets.cpp | 136 +++++++++++++++--------------- AaptAssets.h | 12 +++ Bundle.h | 15 ++-- Command.cpp | 4 +- Images.cpp | 206 +++++++++++++++++++++++++++++----------------- Main.cpp | 23 +++++- Resource.cpp | 121 +++++++++++++++++++++++---- ResourceTable.cpp | 32 ++++--- ResourceTable.h | 7 +- 9 files changed, 373 insertions(+), 183 deletions(-) diff --git a/AaptAssets.cpp b/AaptAssets.cpp index 027662d..6bc1ee6 100644 --- a/AaptAssets.cpp +++ b/AaptAssets.cpp @@ -17,7 +17,6 @@ static const char* kWildcardName = "any"; static const char* kAssetDir = "assets"; static const char* kResourceDir = "res"; static const char* kInvalidChars = "/\\:"; -static const char* kExcludeExtension = ".EXCLUDE"; static const size_t kMaxAssetFileName = 100; static const String8 kResString(kResourceDir); @@ -100,7 +99,7 @@ static bool isHidden(const char *root, const char *path) return true; } - + // ========================================================================= // ========================================================================= // ========================================================================= @@ -159,28 +158,28 @@ AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value) *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; @@ -319,7 +318,7 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType) // touchscreen if (getTouchscreenName(part.string())) { touch = part; - + index++; if (index == N) { goto success; @@ -328,11 +327,11 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType) } else { //printf("not touchscreen: %s\n", part.string()); } - + // keyboard hidden if (getKeysHiddenName(part.string())) { keysHidden = part; - + index++; if (index == N) { goto success; @@ -341,11 +340,11 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType) } else { //printf("not keysHidden: %s\n", part.string()); } - + // keyboard if (getKeyboardName(part.string())) { key = part; - + index++; if (index == N) { goto success; @@ -354,10 +353,10 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType) } else { //printf("not keyboard: %s\n", part.string()); } - + if (getNavigationName(part.string())) { nav = part; - + index++; if (index == N) { goto success; @@ -366,10 +365,10 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType) } else { //printf("not navigation: %s\n", part.string()); } - + if (getScreenSizeName(part.string())) { size = part; - + index++; if (index == N) { goto success; @@ -378,10 +377,10 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType) } else { //printf("not screen size: %s\n", part.string()); } - + if (getVersionName(part.string())) { vers = part; - + index++; if (index == N) { goto success; @@ -390,7 +389,7 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType) } else { //printf("not version: %s\n", part.string()); } - + // if there are extra parts, it doesn't match return false; @@ -488,7 +487,7 @@ AaptGroupEntry::toDirName(const String8& resType) const s += "-"; s += version; } - + return s; } @@ -506,9 +505,9 @@ bool AaptGroupEntry::getMccName(const char* name, c++; if (tolower(*c) != 'c') return false; c++; - + const char* val = c; - + while (*c >= '0' && *c <= '9') { c++; } @@ -538,9 +537,9 @@ bool AaptGroupEntry::getMncName(const char* name, c++; if (tolower(*c) != 'c') return false; c++; - + const char* val = c; - + while (*c >= '0' && *c <= '9') { c++; } @@ -621,7 +620,7 @@ bool AaptGroupEntry::getOrientationName(const char* name, if (out) out->orientation = out->ORIENTATION_SQUARE; return true; } - + return false; } @@ -677,7 +676,7 @@ bool AaptGroupEntry::getTouchscreenName(const char* name, if (out) out->touchscreen = out->TOUCHSCREEN_FINGER; return true; } - + return false; } @@ -699,12 +698,12 @@ bool AaptGroupEntry::getKeysHiddenName(const char* name, mask = out->MASK_KEYSHIDDEN; value = out->KEYSHIDDEN_SOFT; } - + if (mask != 0) { if (out) out->inputFlags = (out->inputFlags&~mask) | value; return true; } - + return false; } @@ -724,7 +723,7 @@ bool AaptGroupEntry::getKeyboardName(const char* name, if (out) out->keyboard = out->KEYBOARD_12KEY; return true; } - + return false; } @@ -747,7 +746,7 @@ bool AaptGroupEntry::getNavigationName(const char* name, if (out) out->navigation = out->NAVIGATION_WHEEL; return true; } - + return false; } @@ -761,29 +760,29 @@ bool AaptGroupEntry::getScreenSizeName(const char* name, } 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; } @@ -797,22 +796,22 @@ bool AaptGroupEntry::getVersionName(const char* name, } 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; } @@ -1081,29 +1080,29 @@ ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir, { 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); } @@ -1315,7 +1314,7 @@ void AaptAssets::addResource(const String8& leafName, const String8& path, sp subdir = res->makeDir(dirname); sp grr = new AaptGroup(leafName, path); grr->addFile(file); - + subdir->addFile(leafName, grr); } @@ -1324,10 +1323,10 @@ ssize_t AaptAssets::slurpFromArgs(Bundle* bundle) { int count; int totalCount = 0; - int i; - int arg = 0; FileType type; - const char* res; + const Vector& resDirs = bundle->getResourceSourceDirs(); + const size_t dirCount =resDirs.size(); + sp current = this; const int N = bundle->getFileSpecCount(); @@ -1380,28 +1379,35 @@ ssize_t AaptAssets::slurpFromArgs(Bundle* bundle) /* * If a directory of resource-specific assets was supplied, slurp 'em up. */ - res = bundle->getResourceSourceDir(); - if (res) { - type = getFileType(res); - if (type == kFileTypeNonexistent) { - fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res); - return UNKNOWN_ERROR; - } - if (type == kFileTypeDirectory) { - count = slurpResourceTree(bundle, String8(res)); + 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; + if (count < 0) { + totalCount = count; + goto bail; + } + totalCount += count; + } + else { + fprintf(stderr, "ERROR: '%s' is not a directory\n", res); + return UNKNOWN_ERROR; } - totalCount += count; - } - else { - fprintf(stderr, "ERROR: '%s' is not a directory\n", res); - return UNKNOWN_ERROR; } + } - /* * Now do any additional raw files. */ diff --git a/AaptAssets.h b/AaptAssets.h index 6ab0ae5..01c8140 100644 --- a/AaptAssets.h +++ b/AaptAssets.h @@ -441,6 +441,8 @@ private: AaptSymbolEntry mDefSymbol; }; +class ResourceTypeSet; + /** * Asset hierarchy being operated on. */ @@ -491,6 +493,13 @@ public: 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; @@ -501,6 +510,9 @@ private: bool mHaveIncludedAssets; AssetManager mIncludedAssets; + + sp mOverlay; + KeyedVector >* mRes; }; #endif // __AAPT_ASSETS_H diff --git a/Bundle.h b/Bundle.h index 99fac2f..2d8471b 100644 --- a/Bundle.h +++ b/Bundle.h @@ -31,11 +31,11 @@ class Bundle { public: Bundle(void) : mCmd(kCommandUnknown), mVerbose(false), mAndroidList(false), - mForce(false), mMakePackageDirs(false), + mForce(false), mGrayscaleTolerance(0), mMakePackageDirs(false), mUpdate(false), mExtending(false), mRequireLocalization(false), mPseudolocalize(false), mCompressionMethod(0), mOutputAPKFile(NULL), - mAssetSourceDir(NULL), mResourceSourceDir(NULL), + mAssetSourceDir(NULL), mAndroidManifestFile(NULL), mPublicOutputFile(NULL), mRClassDir(NULL), mResourceIntermediatesDir(NULL), mArgc(0), mArgv(NULL) @@ -58,6 +58,8 @@ public: 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; } @@ -78,8 +80,8 @@ public: */ const char* getAssetSourceDir() const { return mAssetSourceDir; } void setAssetSourceDir(const char* dir) { mAssetSourceDir = dir; } - const char* getResourceSourceDir() const { return mResourceSourceDir; } - void setResourceSourceDir(const char* dir) { mResourceSourceDir = 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; } @@ -130,6 +132,7 @@ private: bool mVerbose; bool mAndroidList; bool mForce; + int mGrayscaleTolerance; bool mMakePackageDirs; bool mUpdate; bool mExtending; @@ -138,7 +141,6 @@ private: int mCompressionMethod; const char* mOutputAPKFile; const char* mAssetSourceDir; - const char* mResourceSourceDir; const char* mAndroidManifestFile; const char* mPublicOutputFile; const char* mRClassDir; @@ -147,7 +149,8 @@ private: android::Vector mPackageIncludes; android::Vector mJarFiles; android::Vector mNoCompressExtensions; - + android::Vector mResourceSourceDirs; + /* file specification */ int mArgc; char* const* mArgv; diff --git a/Command.cpp b/Command.cpp index 9f75d4b..bff0423 100644 --- a/Command.cpp +++ b/Command.cpp @@ -761,7 +761,7 @@ int doPackage(Bundle* bundle) } N = bundle->getFileSpecCount(); - if (N < 1 && bundle->getResourceSourceDir() == NULL && bundle->getJarFiles().size() == 0 + 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; @@ -793,7 +793,7 @@ int doPackage(Bundle* bundle) } // If they asked for any files that need to be compiled, do so. - if (bundle->getResourceSourceDir() || bundle->getAndroidManifestFile()) { + if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) { err = buildResources(bundle, assets); if (err != 0) { goto bail; diff --git a/Images.cpp b/Images.cpp index 7c4963f..a516a5a 100644 --- a/Images.cpp +++ b/Images.cpp @@ -33,7 +33,7 @@ png_flush_aapt_file(png_structp png_ptr) // This holds an image as 8bpp RGBA. struct image_info { - image_info() : rows(NULL), hasTransparency(true), is9Patch(false), allocRows(NULL) { } + image_info() : rows(NULL), is9Patch(false), allocRows(NULL) { } ~image_info() { if (rows && rows != allocRows) { free(rows); @@ -50,8 +50,6 @@ struct image_info png_uint_32 height; png_bytepp rows; - bool hasTransparency; - // 9-patch info. bool is9Patch; Res_png_9patch info9Patch; @@ -326,22 +324,6 @@ static uint32_t get_color(image_info* image, int hpatch, int vpatch) return c; } -static void examine_image(image_info* image) -{ - bool hasTrans = false; - for (int i=0; i<(int)image->height && !hasTrans; i++) { - png_bytep p = image->rows[i]; - for (int j=0; j<(int)image->width; j++) { - if (p[(j*4)+3] != 0xFF) { - hasTrans = true; - break; - } - } - } - - image->hasTransparency = hasTrans; -} - static status_t do_9patch(const char* imageName, image_info* image) { image->is9Patch = true; @@ -618,17 +600,57 @@ static bool patch_equals(Res_png_9patch& patch1, Res_png_9patch& patch2) { return true; } +static void dump_image(int w, int h, png_bytepp rows, int bpp) +{ + int i, j, rr, gg, bb, aa; + + 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(image_info &imageInfo, png_colorp rgbPalette, png_bytep alphaPalette, +static void analyze_image(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; - bool trans = imageInfo.hasTransparency; 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; @@ -638,6 +660,10 @@ static void analyze_image(image_info &imageInfo, png_colorp rgbPalette, png_byte // 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, 4); + for (j = 0; j < h; j++) { png_bytep row = imageInfo.rows[j]; png_bytep out = outRows[j]; @@ -646,23 +672,32 @@ static void analyze_image(image_info &imageInfo, png_colorp rgbPalette, png_byte gg = *row++; bb = *row++; aa = *row++; - if (!trans) { - // Ignore the actually byte and assume alpha == 255 - aa = 0xff; + + 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) { - isGrayscale = false; - } + 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) { - isOpaque = false; - } + 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 @@ -682,6 +717,7 @@ static void analyze_image(image_info &imageInfo, png_colorp rgbPalette, png_byte *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; @@ -696,6 +732,13 @@ static void analyze_image(image_info &imageInfo, png_colorp rgbPalette, png_byte 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 @@ -719,7 +762,12 @@ static void analyze_image(image_info &imageInfo, png_colorp rgbPalette, png_byte } else if (isPalette && (paletteSize < bpp * w * h)) { *colorType = PNG_COLOR_TYPE_PALETTE; } else { - *colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; + if (maxGrayDeviation <= grayscaleTolerance) { + NOISY(printf("Forcing image to gray (max deviation = %d)\n", 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 @@ -748,11 +796,15 @@ static void analyze_image(image_info &imageInfo, png_colorp rgbPalette, png_byte bb = *row++; aa = *row++; - *out++ = rr; + if (isGrayscale) { + *out++ = rr; + } else { + *out++ = (png_byte) (rr * 0.2126f + gg * 0.7152f + bb * 0.0722f); + } if (!isOpaque) { *out++ = aa; } - } + } } } } @@ -760,7 +812,7 @@ static void analyze_image(image_info &imageInfo, png_colorp rgbPalette, png_byte static void write_png(const char* imageName, png_structp write_ptr, png_infop write_info, - image_info& imageInfo) + image_info& imageInfo, int grayscaleTolerance) { bool optimize = true; png_uint_32 width, height; @@ -785,42 +837,34 @@ static void write_png(const char* imageName, png_set_compression_level(write_ptr, Z_BEST_COMPRESSION); - NOISY(printf("Writing image %s: w = %d, h = %d, trans = %s\n", imageName, - (int) imageInfo.width, (int) imageInfo.height, - imageInfo.hasTransparency ? "true" : "false")); + 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; - if (optimize) { - analyze_image(imageInfo, 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; - } - } else { - // Force RGB or RGB_ALPHA color type, copy transparency from input - paletteEntries = 0; - hasTransparency = imageInfo.hasTransparency; - color_type = hasTransparency ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB; + analyze_image(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, @@ -856,16 +900,31 @@ static void write_png(const char* imageName, } png_write_info(write_ptr, write_info); - - if (!imageInfo.hasTransparency) { - png_set_filler(write_ptr, 0, PNG_FILLER_AFTER); - } + png_bytepp rows; if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) { - png_write_image(write_ptr, imageInfo.rows); + png_set_filler(write_ptr, 0, PNG_FILLER_AFTER); + rows = imageInfo.rows; } else { - png_write_image(write_ptr, outRows); - } + rows = outRows; + } + png_write_image(write_ptr, rows); + +// 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) { +// bpp = 4; +// } else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { +// bpp = 4; +// } else { +// printf("Uknknown color type %d, exiting.\n", color_type); +// exit(1); +// } +// NOISY(printf("Final image data:\n")); +// dump_image(imageInfo.width, imageInfo.height, rows, bpp); png_write_end(write_ptr, write_info); @@ -937,8 +996,6 @@ status_t preProcessImage(Bundle* bundle, const sp& assets, read_png(printableName.string(), read_ptr, read_info, &imageInfo); - examine_image(&imageInfo); - if (nameLen > 6) { const char* name = file->getPath().string(); if (name[nameLen-5] == '9' && name[nameLen-6] == '.') { @@ -969,7 +1026,8 @@ status_t preProcessImage(Bundle* bundle, const sp& assets, goto bail; } - write_png(printableName.string(), write_ptr, write_info, imageInfo); + write_png(printableName.string(), write_ptr, write_info, imageInfo, + bundle->getGrayscaleTolerance()); error = NO_ERROR; diff --git a/Main.cpp b/Main.cpp index a1978da..ee0dbad 100644 --- a/Main.cpp +++ b/Main.cpp @@ -53,11 +53,14 @@ void usage(void) " 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] [-f][-u][-m][-v][-x][-M AndroidManifest.xml] \\\n" + " %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] [-F apk-file] [-J R-file-dir] \\\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" @@ -91,6 +94,7 @@ void usage(void) " 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 @@ -107,7 +111,8 @@ void usage(void) " -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\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"); @@ -201,6 +206,16 @@ int main(int argc, char* const argv[]) 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; + } + bundle.setGrayscaleTolerance(atoi(argv[0])); + break; case 'm': bundle.setMakePackageDirs(true); break; @@ -304,7 +319,7 @@ int main(int argc, char* const argv[]) goto bail; } convertPath(argv[0]); - bundle.setResourceSourceDir(argv[0]); + bundle.addResourceSourceDir(argv[0]); break; case '0': argc--; diff --git a/Resource.cpp b/Resource.cpp index fd6ddb5..b2bd9ff 100644 --- a/Resource.cpp +++ b/Resource.cpp @@ -433,11 +433,73 @@ static void checkForIds(const String8& path, ResXMLParser& parser) } } +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)); \ + ssize_t index = resources->indexOfKey(String8(#n)); \ if (index >= 0) { \ - n ## s = resources.valueAt(index); \ + n ## s = resources->valueAt(index); \ } \ } while (0) @@ -468,18 +530,16 @@ status_t buildResources(Bundle* bundle, const sp& assets) NOISY(printf("Found %d included resource packages\n", (int)table.size())); - sp res = assets->getDirs().valueFor(String8("res")); - // -------------------------------------------------------------- // First, gather all resource information. // -------------------------------------------------------------- // resType -> leafName -> group - KeyedVector > resources; - collect_files(assets, &resources); + KeyedVector > *resources = + new KeyedVector >; + collect_files(assets, resources); sp drawables; - sp valuess; sp layouts; sp anims; sp xmls; @@ -492,10 +552,28 @@ status_t buildResources(Bundle* bundle, const sp& assets) ASSIGN_IT(anim); ASSIGN_IT(xml); ASSIGN_IT(raw); - ASSIGN_IT(values); 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) { @@ -538,17 +616,26 @@ status_t buildResources(Bundle* bundle, const sp& assets) } } - if (valuess != NULL) { - ResourceDirIterator it(valuess, String8("values")); - ssize_t res; - while ((res=it.next()) == NO_ERROR) { - sp file = it.getFile(); - - res = compileResourceFile(bundle, assets, file, it.getParams(), &table); - if (res != 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) { diff --git a/ResourceTable.cpp b/ResourceTable.cpp index 33f8f72..877763d 100644 --- a/ResourceTable.cpp +++ b/ResourceTable.cpp @@ -546,6 +546,7 @@ status_t parseAndAddBag(Bundle* bundle, const String16& itemIdent, int32_t curFormat, bool pseudolocalize, + const bool overwrite, ResourceTable* outTable) { status_t err; @@ -572,7 +573,7 @@ status_t parseAndAddBag(Bundle* bundle, err = outTable->addBag(SourcePos(in->getPrintableSource(), block->getLineNumber()), myPackage, curType, ident, parentIdent, itemIdent, str, - &spans, &config, false, false, curFormat); + &spans, &config, overwrite, false, curFormat); return err; } @@ -588,6 +589,7 @@ status_t parseAndAddEntry(Bundle* bundle, bool curIsStyled, int32_t curFormat, bool pseudolocalize, + const bool overwrite, ResourceTable* outTable) { status_t err; @@ -610,7 +612,7 @@ status_t parseAndAddEntry(Bundle* bundle, err = outTable->addEntry(SourcePos(in->getPrintableSource(), block->getLineNumber()), myPackage, curType, ident, str, &spans, &config, - false, curFormat); + false, curFormat, overwrite); return err; } @@ -619,6 +621,7 @@ status_t compileResourceFile(Bundle* bundle, const sp& assets, const sp& in, const ResTable_config& defParams, + const bool overwrite, ResourceTable* outTable) { ResXMLTree block; @@ -979,7 +982,7 @@ status_t compileResourceFile(Bundle* bundle, if (locale.size() > 0) { fprintf(stderr, "aapt: warning: string '%s' in %s marked untranslatable but exists" " in locale '%s'\n", String8(name).string(), - bundle->getResourceSourceDir(), + bundle->getResourceSourceDirs()[0], locale.string()); // hasErrors = localHasErrors = true; } else { @@ -1172,7 +1175,8 @@ status_t compileResourceFile(Bundle* bundle, block.getPosition(&parserPosition); err = parseAndAddBag(bundle, in, &block, curParams, myPackage, curType, - ident, parentIdent, itemIdent, curFormat, false, outTable); + ident, parentIdent, itemIdent, curFormat, + false, overwrite, outTable); if (err == NO_ERROR) { if (curIsPseudolocalizable && localeIsDefined(curParams) && bundle->getPseudolocalize()) { @@ -1181,7 +1185,7 @@ status_t compileResourceFile(Bundle* bundle, block.setPosition(parserPosition); err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage, curType, ident, parentIdent, itemIdent, curFormat, true, - outTable); + overwrite, outTable); #endif } } @@ -1204,7 +1208,7 @@ status_t compileResourceFile(Bundle* bundle, block.getPosition(&parserPosition); err = parseAndAddEntry(bundle, in, &block, curParams, myPackage, curType, ident, - *curTag, curIsStyled, curFormat, false, outTable); + *curTag, curIsStyled, curFormat, false, overwrite, outTable); if (err < NO_ERROR) { // Why err < NO_ERROR instead of err != NO_ERROR? hasErrors = localHasErrors = true; @@ -1215,7 +1219,7 @@ status_t compileResourceFile(Bundle* bundle, // pseudolocalize here block.setPosition(parserPosition); err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType, - ident, *curTag, curIsStyled, curFormat, true, outTable); + ident, *curTag, curIsStyled, curFormat, true, false, outTable); if (err != NO_ERROR) { hasErrors = localHasErrors = true; } @@ -1360,7 +1364,8 @@ status_t ResourceTable::addEntry(const SourcePos& sourcePos, const Vector* style, const ResTable_config* params, const bool doSetIndex, - const int32_t format) + 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. @@ -1384,7 +1389,7 @@ status_t ResourceTable::addEntry(const SourcePos& sourcePos, if (e == NULL) { return UNKNOWN_ERROR; } - status_t err = e->setItem(sourcePos, value, style, format); + status_t err = e->setItem(sourcePos, value, style, format, overwrite); if (err == NO_ERROR) { mNumLocal++; } @@ -2125,7 +2130,7 @@ ResourceTable::validateLocalizations(void) // 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->getResourceSourceDir()); + String8(nameIter->first).string(), mBundle->getResourceSourceDirs()[0]); for (set::iterator locales = configSet.begin(); locales != configSet.end(); locales++) { @@ -2167,7 +2172,7 @@ ResourceTable::validateLocalizations(void) "for '%s' in %s\n", String8(nameIter->first).string(), config.string(), - mBundle->getResourceSourceDir()); + mBundle->getResourceSourceDirs()[0]); //err = UNKNOWN_ERROR; } } @@ -2728,7 +2733,8 @@ status_t ResourceTable::Entry::makeItABag(const SourcePos& sourcePos) status_t ResourceTable::Entry::setItem(const SourcePos& sourcePos, const String16& value, const Vector* style, - int32_t format) + int32_t format, + const bool overwrite) { Item item(sourcePos, false, value, style); @@ -2740,7 +2746,7 @@ status_t ResourceTable::Entry::setItem(const SourcePos& sourcePos, item.sourcePos.file.string(), item.sourcePos.line); return UNKNOWN_ERROR; } - if (mType != TYPE_UNKNOWN) { + if ( (mType != TYPE_UNKNOWN) && (overwrite == false) ) { sourcePos.error("Resource entry %s is already defined.\n" "%s:%d: Originally defined here.\n", String8(mName).string(), diff --git a/ResourceTable.h b/ResourceTable.h index fff4f49..e8fbd9b 100644 --- a/ResourceTable.h +++ b/ResourceTable.h @@ -38,6 +38,7 @@ status_t compileResourceFile(Bundle* bundle, const sp& assets, const sp& in, const ResTable_config& defParams, + const bool overwrite, ResourceTable* outTable); struct AccessorCookie @@ -79,7 +80,8 @@ public: const Vector* style = NULL, const ResTable_config* params = NULL, const bool doSetIndex = false, - const int32_t format = ResTable_map::TYPE_ANY); + const int32_t format = ResTable_map::TYPE_ANY, + const bool overwrite = false); status_t startBag(const SourcePos& pos, const String16& package, @@ -256,7 +258,8 @@ public: status_t setItem(const SourcePos& pos, const String16& value, const Vector* style = NULL, - int32_t format = ResTable_map::TYPE_ANY); + int32_t format = ResTable_map::TYPE_ANY, + const bool overwrite = false); status_t addToBag(const SourcePos& pos, const String16& key, const String16& value, -- 2.45.2