diff options
Diffstat (limited to 'tools/aapt')
-rw-r--r-- | tools/aapt/AaptAssets.cpp | 96 | ||||
-rw-r--r-- | tools/aapt/AaptAssets.h | 61 | ||||
-rw-r--r-- | tools/aapt/Android.mk | 1 | ||||
-rw-r--r-- | tools/aapt/Bundle.h | 25 | ||||
-rw-r--r-- | tools/aapt/Command.cpp | 247 | ||||
-rw-r--r-- | tools/aapt/Images.cpp | 200 | ||||
-rw-r--r-- | tools/aapt/Images.h | 4 | ||||
-rw-r--r-- | tools/aapt/Resource.cpp | 58 | ||||
-rw-r--r-- | tools/aapt/ResourceTable.cpp | 150 | ||||
-rw-r--r-- | tools/aapt/ResourceTable.h | 71 | ||||
-rw-r--r-- | tools/aapt/StringPool.cpp | 315 | ||||
-rw-r--r-- | tools/aapt/StringPool.h | 90 | ||||
-rw-r--r-- | tools/aapt/XMLNode.cpp | 2 | ||||
-rw-r--r-- | tools/aapt/ZipEntry.cpp | 68 | ||||
-rw-r--r-- | tools/aapt/ZipFile.cpp | 96 |
15 files changed, 1176 insertions, 308 deletions
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp index f0c215e..ec61403 100644 --- a/tools/aapt/AaptAssets.cpp +++ b/tools/aapt/AaptAssets.cpp @@ -1084,12 +1084,17 @@ bool AaptGroupEntry::getDensityName(const char* name, if (out) out->density = ResTable_config::DENSITY_HIGH; return true; } - + if (strcmp(name, "xhdpi") == 0) { - if (out) out->density = ResTable_config::DENSITY_MEDIUM*2; + if (out) out->density = ResTable_config::DENSITY_XHIGH; return true; } - + + if (strcmp(name, "xxhdpi") == 0) { + if (out) out->density = ResTable_config::DENSITY_XXHIGH; + return true; + } + char* c = (char*)name; while (*c >= '0' && *c <= '9') { c++; @@ -1832,6 +1837,49 @@ String8 AaptDir::getPrintableSource() const // ========================================================================= // ========================================================================= +status_t AaptSymbols::applyJavaSymbols(const sp<AaptSymbols>& javaSymbols) +{ + status_t err = NO_ERROR; + size_t N = javaSymbols->mSymbols.size(); + for (size_t i=0; i<N; i++) { + const String8& name = javaSymbols->mSymbols.keyAt(i); + const AaptSymbolEntry& entry = javaSymbols->mSymbols.valueAt(i); + ssize_t pos = mSymbols.indexOfKey(name); + if (pos < 0) { + entry.sourcePos.error("Symbol '%s' declared with <java-symbol> not defined\n", name.string()); + err = UNKNOWN_ERROR; + continue; + } + //printf("**** setting symbol #%d/%d %s to isJavaSymbol=%d\n", + // i, N, name.string(), entry.isJavaSymbol ? 1 : 0); + mSymbols.editValueAt(pos).isJavaSymbol = entry.isJavaSymbol; + } + + N = javaSymbols->mNestedSymbols.size(); + for (size_t i=0; i<N; i++) { + const String8& name = javaSymbols->mNestedSymbols.keyAt(i); + const sp<AaptSymbols>& symbols = javaSymbols->mNestedSymbols.valueAt(i); + ssize_t pos = mNestedSymbols.indexOfKey(name); + if (pos < 0) { + SourcePos pos; + pos.error("Java symbol dir %s not defined\n", name.string()); + err = UNKNOWN_ERROR; + continue; + } + //printf("**** applying java symbols in dir %s\n", name.string()); + status_t myerr = mNestedSymbols.valueAt(pos)->applyJavaSymbols(symbols); + if (myerr != NO_ERROR) { + err = myerr; + } + } + + return err; +} + +// ========================================================================= +// ========================================================================= +// ========================================================================= + AaptAssets::AaptAssets() : AaptDir(String8(), String8()), mChanged(false), mHaveIncludedAssets(false), mRes(NULL) @@ -2399,6 +2447,48 @@ sp<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name) return sym; } +sp<AaptSymbols> AaptAssets::getJavaSymbolsFor(const String8& name) +{ + sp<AaptSymbols> sym = mJavaSymbols.valueFor(name); + if (sym == NULL) { + sym = new AaptSymbols(); + mJavaSymbols.add(name, sym); + } + return sym; +} + +status_t AaptAssets::applyJavaSymbols() +{ + size_t N = mJavaSymbols.size(); + for (size_t i=0; i<N; i++) { + const String8& name = mJavaSymbols.keyAt(i); + const sp<AaptSymbols>& symbols = mJavaSymbols.valueAt(i); + ssize_t pos = mSymbols.indexOfKey(name); + if (pos < 0) { + SourcePos pos; + pos.error("Java symbol dir %s not defined\n", name.string()); + return UNKNOWN_ERROR; + } + //printf("**** applying java symbols in dir %s\n", name.string()); + status_t err = mSymbols.valueAt(pos)->applyJavaSymbols(symbols); + if (err != NO_ERROR) { + return err; + } + } + + return NO_ERROR; +} + +bool AaptAssets::isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const { + //printf("isJavaSymbol %s: public=%d, includePrivate=%d, isJavaSymbol=%d\n", + // sym.name.string(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0, + // sym.isJavaSymbol ? 1 : 0); + if (!mHavePrivateSymbols) return true; + if (sym.isPublic) return true; + if (includePrivate && sym.isJavaSymbol) return true; + return false; +} + status_t AaptAssets::buildIncludedResources(Bundle* bundle) { if (!mHaveIncludedAssets) { diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h index d5345b2..5924952 100644 --- a/tools/aapt/AaptAssets.h +++ b/tools/aapt/AaptAssets.h @@ -7,14 +7,14 @@ #define __AAPT_ASSETS_H #include <stdlib.h> -#include <utils/AssetManager.h> +#include <androidfw/AssetManager.h> +#include <androidfw/ResourceTypes.h> #include <utils/KeyedVector.h> -#include <utils/String8.h> -#include <utils/ResourceTypes.h> +#include <utils/RefBase.h> #include <utils/SortedVector.h> #include <utils/String8.h> +#include <utils/String8.h> #include <utils/Vector.h> -#include <utils/RefBase.h> #include "ZipFile.h" #include "Bundle.h" @@ -53,17 +53,6 @@ enum { AXIS_END = AXIS_VERSION, }; -enum { - SDK_CUPCAKE = 3, - SDK_DONUT = 4, - SDK_ECLAIR = 5, - SDK_ECLAIR_0_1 = 6, - SDK_MR1 = 7, - SDK_FROYO = 8, - SDK_HONEYCOMB_MR2 = 13, - SDK_ICE_CREAM_SANDWICH = 14, -}; - /** * This structure contains a specific variation of a single file out * of all the variations it can have that we can have. @@ -326,16 +315,16 @@ class AaptSymbolEntry { public: AaptSymbolEntry() - : isPublic(false), typeCode(TYPE_UNKNOWN) + : isPublic(false), isJavaSymbol(false), typeCode(TYPE_UNKNOWN) { } AaptSymbolEntry(const String8& _name) - : name(_name), isPublic(false), typeCode(TYPE_UNKNOWN) + : name(_name), isPublic(false), isJavaSymbol(false), typeCode(TYPE_UNKNOWN) { } AaptSymbolEntry(const AaptSymbolEntry& o) : name(o.name), sourcePos(o.sourcePos), isPublic(o.isPublic) - , comment(o.comment), typeComment(o.typeComment) + , isJavaSymbol(o.isJavaSymbol), comment(o.comment), typeComment(o.typeComment) , typeCode(o.typeCode), int32Val(o.int32Val), stringVal(o.stringVal) { } @@ -343,6 +332,7 @@ public: { sourcePos = o.sourcePos; isPublic = o.isPublic; + isJavaSymbol = o.isJavaSymbol; comment = o.comment; typeComment = o.typeComment; typeCode = o.typeCode; @@ -355,6 +345,7 @@ public: SourcePos sourcePos; bool isPublic; + bool isJavaSymbol; String16 comment; String16 typeComment; @@ -412,6 +403,15 @@ public: return NO_ERROR; } + status_t makeSymbolJavaSymbol(const String8& name, const SourcePos& pos) { + if (!check_valid_symbol_name(name, pos, "symbol")) { + return BAD_VALUE; + } + AaptSymbolEntry& sym = edit_symbol(name, &pos); + sym.isJavaSymbol = true; + return NO_ERROR; + } + void appendComment(const String8& name, const String16& comment, const SourcePos& pos) { if (comment.size() <= 0) { return; @@ -452,6 +452,8 @@ public: return sym; } + status_t applyJavaSymbols(const sp<AaptSymbols>& javaSymbols); + const KeyedVector<String8, AaptSymbolEntry>& getSymbols() const { return mSymbols; } const DefaultKeyedVector<String8, sp<AaptSymbols> >& getNestedSymbols() const @@ -520,7 +522,11 @@ public: virtual ~AaptAssets() { delete mRes; } const String8& getPackage() const { return mPackage; } - void setPackage(const String8& package) { mPackage = package; mSymbolsPrivatePackage = package; } + void setPackage(const String8& package) { + mPackage = package; + mSymbolsPrivatePackage = package; + mHavePrivateSymbols = false; + } const SortedVector<AaptGroupEntry>& getGroupEntries() const; @@ -543,11 +549,22 @@ public: sp<AaptSymbols> getSymbolsFor(const String8& name); + sp<AaptSymbols> getJavaSymbolsFor(const String8& name); + + status_t applyJavaSymbols(); + const DefaultKeyedVector<String8, sp<AaptSymbols> >& getSymbols() const { return mSymbols; } String8 getSymbolsPrivatePackage() const { return mSymbolsPrivatePackage; } - void setSymbolsPrivatePackage(const String8& pkg) { mSymbolsPrivatePackage = pkg; } - + void setSymbolsPrivatePackage(const String8& pkg) { + mSymbolsPrivatePackage = pkg; + mHavePrivateSymbols = mSymbolsPrivatePackage != mPackage; + } + + bool havePrivateSymbols() const { return mHavePrivateSymbols; } + + bool isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const; + status_t buildIncludedResources(Bundle* bundle); status_t addIncludedResources(const sp<AaptFile>& file); const ResTable& getIncludedResources() const; @@ -587,7 +604,9 @@ private: String8 mPackage; SortedVector<AaptGroupEntry> mGroupEntries; DefaultKeyedVector<String8, sp<AaptSymbols> > mSymbols; + DefaultKeyedVector<String8, sp<AaptSymbols> > mJavaSymbols; String8 mSymbolsPrivatePackage; + bool mHavePrivateSymbols; Vector<sp<AaptDir> > mResDirs; diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk index cb55a9c..d0a81dc 100644 --- a/tools/aapt/Android.mk +++ b/tools/aapt/Android.mk @@ -38,6 +38,7 @@ LOCAL_C_INCLUDES += build/libs/host/include #LOCAL_WHOLE_STATIC_LIBRARIES := LOCAL_STATIC_LIBRARIES := \ libhost \ + libandroidfw \ libutils \ libcutils \ libexpat \ diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h index 2d1060b..daeadc0 100644 --- a/tools/aapt/Bundle.h +++ b/tools/aapt/Bundle.h @@ -14,6 +14,18 @@ #include <utils/String8.h> #include <utils/Vector.h> +enum { + SDK_CUPCAKE = 3, + SDK_DONUT = 4, + SDK_ECLAIR = 5, + SDK_ECLAIR_0_1 = 6, + SDK_MR1 = 7, + SDK_FROYO = 8, + SDK_HONEYCOMB_MR2 = 13, + SDK_ICE_CREAM_SANDWICH = 14, + SDK_ICE_CREAM_SANDWICH_MR1 = 15, +}; + /* * Things we can do. */ @@ -71,7 +83,7 @@ public: bool getForce(void) const { return mForce; } void setForce(bool val) { mForce = val; } void setGrayscaleTolerance(int val) { mGrayscaleTolerance = val; } - int getGrayscaleTolerance() { return mGrayscaleTolerance; } + int getGrayscaleTolerance() const { return mGrayscaleTolerance; } bool getMakePackageDirs(void) const { return mMakePackageDirs; } void setMakePackageDirs(bool val) { mMakePackageDirs = val; } bool getUpdate(void) const { return mUpdate; } @@ -82,7 +94,6 @@ public: void setRequireLocalization(bool val) { mRequireLocalization = val; } bool getPseudolocalize(void) const { return mPseudolocalize; } void setPseudolocalize(bool val) { mPseudolocalize = val; } - bool getWantUTF16(void) const { return mWantUTF16; } void setWantUTF16(bool val) { mWantUTF16 = val; } bool getValues(void) const { return mValues; } void setValues(bool val) { mValues = val; } @@ -103,6 +114,10 @@ public: bool getGenDependencies() { return mGenDependencies; } void setGenDependencies(bool val) { mGenDependencies = val; } + bool getUTF16StringsOption() { + return mWantUTF16 || !isMinSdkAtLeast(SDK_FROYO); + } + /* * Input options. */ @@ -151,14 +166,14 @@ public: void setExtraPackages(const char* val) { mExtraPackages = val; } const char* getMaxResVersion() const { return mMaxResVersion; } void setMaxResVersion(const char * val) { mMaxResVersion = val; } - bool getDebugMode() { return mDebugMode; } + bool getDebugMode() const { return mDebugMode; } void setDebugMode(bool val) { mDebugMode = val; } - bool getNonConstantId() { return mNonConstantId; } + bool getNonConstantId() const { return mNonConstantId; } void setNonConstantId(bool val) { mNonConstantId = val; } const char* getProduct() const { return mProduct; } void setProduct(const char * val) { mProduct = val; } void setUseCrunchCache(bool val) { mUseCrunchCache = val; } - bool getUseCrunchCache() { return mUseCrunchCache; } + bool getUseCrunchCache() const { return mUseCrunchCache; } /* * Set and get the file specification. diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index 637c27d..cbd591f 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -345,6 +345,7 @@ enum { LABEL_ATTR = 0x01010001, ICON_ATTR = 0x01010002, NAME_ATTR = 0x01010003, + DEBUGGABLE_ATTR = 0x0101000f, VERSION_CODE_ATTR = 0x0101021b, VERSION_NAME_ATTR = 0x0101021c, SCREEN_ORIENTATION_ATTR = 0x0101001e, @@ -425,6 +426,7 @@ static void printCompatibleScreens(ResXMLTree& tree) { /* * Handle the "dump" command, to extract select data from an archive. */ +extern char CONSOLE_DATA[2925]; // see EOF int doDump(Bundle* bundle) { status_t result = UNKNOWN_ERROR; @@ -478,6 +480,11 @@ int doDump(Bundle* bundle) #ifndef HAVE_ANDROID_OS res.print(bundle->getValues()); #endif + + } else if (strcmp("strings", option) == 0) { + const ResStringPool* pool = res.getTableStringBlock(0); + printStringPool(pool); + } else if (strcmp("xmltree", option) == 0) { if (bundle->getFileSpecCount() < 3) { fprintf(stderr, "ERROR: no dump xmltree resource file specified\n"); @@ -625,6 +632,20 @@ int doDump(Bundle* bundle) bool actImeService = false; bool actWallpaperService = false; + // These two implement the implicit permissions that are granted + // to pre-1.6 applications. + bool hasWriteExternalStoragePermission = false; + bool hasReadPhoneStatePermission = false; + + // If an app requests write storage, they will also get read storage. + bool hasReadExternalStoragePermission = false; + + // Implement transition to read and write call log. + bool hasReadContactsPermission = false; + bool hasWriteContactsPermission = false; + bool hasReadCallLogPermission = false; + bool hasWriteCallLogPermission = false; + // This next group of variables is used to implement a group of // backward-compatibility heuristics necessitated by the addition of // some new uses-feature constants in 2.1 and 2.2. In most cases, the @@ -810,6 +831,15 @@ int doDump(Bundle* bundle) if (testOnly != 0) { printf("testOnly='%d'\n", testOnly); } + + int32_t debuggable = getResolvedIntegerAttribute(&res, tree, DEBUGGABLE_ATTR, &error, 0); + if (error != "") { + fprintf(stderr, "ERROR getting 'android:debuggable' attribute: %s\n", error.string()); + goto bail; + } + if (debuggable != 0) { + printf("application-debuggable\n"); + } } else if (tag == "uses-sdk") { int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error); if (error != "") { @@ -986,6 +1016,20 @@ int doDump(Bundle* bundle) name == "android.permission.WRITE_APN_SETTINGS" || name == "android.permission.WRITE_SMS") { hasTelephonyPermission = true; + } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") { + hasWriteExternalStoragePermission = true; + } else if (name == "android.permission.READ_EXTERNAL_STORAGE") { + hasReadExternalStoragePermission = true; + } else if (name == "android.permission.READ_PHONE_STATE") { + hasReadPhoneStatePermission = true; + } else if (name == "android.permission.READ_CONTACTS") { + hasReadContactsPermission = true; + } else if (name == "android.permission.WRITE_CONTACTS") { + hasWriteContactsPermission = true; + } else if (name == "android.permission.READ_CALL_LOG") { + hasReadCallLogPermission = true; + } else if (name == "android.permission.WRITE_CALL_LOG") { + hasWriteCallLogPermission = true; } printf("uses-permission:'%s'\n", name.string()); } else { @@ -1144,6 +1188,33 @@ int doDump(Bundle* bundle) } } + // Pre-1.6 implicitly granted permission compatibility logic + if (targetSdk < 4) { + if (!hasWriteExternalStoragePermission) { + printf("uses-permission:'android.permission.WRITE_EXTERNAL_STORAGE'\n"); + hasWriteExternalStoragePermission = true; + } + if (!hasReadPhoneStatePermission) { + printf("uses-permission:'android.permission.READ_PHONE_STATE'\n"); + } + } + + // If the application has requested WRITE_EXTERNAL_STORAGE, we will + // force them to always take READ_EXTERNAL_STORAGE as well. + if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) { + printf("uses-permission:'android.permission.READ_EXTERNAL_STORAGE'\n"); + } + + // Pre-JellyBean call log permission compatibility. + if (targetSdk < 16) { + if (!hasReadCallLogPermission && hasReadContactsPermission) { + printf("uses-permission:'android.permission.READ_CALL_LOG'\n"); + } + if (!hasWriteCallLogPermission && hasWriteContactsPermission) { + printf("uses-permission:'android.permission.WRITE_CALL_LOG'\n"); + } + } + /* The following blocks handle printing "inferred" uses-features, based * on whether related features or permissions are used by the app. * Note that the various spec*Feature variables denote whether the @@ -1361,6 +1432,8 @@ int doDump(Bundle* bundle) } delete dir; } + } else if (strcmp("badger", option) == 0) { + printf("%s", CONSOLE_DATA); } else if (strcmp("configurations", option) == 0) { Vector<ResTable_config> configs; res.getConfigurations(&configs); @@ -1590,6 +1663,12 @@ int doPackage(Bundle* bundle) goto bail; } + // Update symbols with information about which ones are needed as Java symbols. + assets->applyJavaSymbols(); + if (SourcePos::hasErrors()) { + goto bail; + } + // If we've been asked to generate a dependency file, do that here if (bundle->getGenDependencies()) { // If this is the packaging step, generate the dependency file next to @@ -1611,7 +1690,7 @@ int doPackage(Bundle* bundle) } // Write out R.java constants - if (assets->getPackage() == assets->getSymbolsPrivatePackage()) { + if (!assets->havePrivateSymbols()) { if (bundle->getCustomPackage() == NULL) { // Write the R.java file into the appropriate class directory // e.g. gen/com/foo/app/R.java @@ -1709,3 +1788,169 @@ int doCrunch(Bundle* bundle) return NO_ERROR; } + +char CONSOLE_DATA[2925] = { + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63, + 86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83, + 62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81, + 81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59, + 59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, + 59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87, + 58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, + 47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58, + 121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81, + 81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59, + 59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59, + 59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81, + 70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81, + 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109, + 81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, + 32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59, + 59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59, + 60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59, + 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46, + 61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32, + 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81, + 109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81, + 67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58, + 61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37, + 73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, + 32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96, + 46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, + 97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32, + 46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61, + 119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32, + 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119, + 119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81, + 81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41, + 87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, + 45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, + 59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, + 59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59, + 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59, + 61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, + 59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59, + 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33, + 58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, + 61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95, + 32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59, + 61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45, + 59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59, + 59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61, + 46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, + 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59, + 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32, + 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61, + 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, + 59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10 + }; diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp index ffbe875..9de685a 100644 --- a/tools/aapt/Images.cpp +++ b/tools/aapt/Images.cpp @@ -8,7 +8,7 @@ #include "Images.h" -#include <utils/ResourceTypes.h> +#include <androidfw/ResourceTypes.h> #include <utils/ByteOrder.h> #include <png.h> @@ -57,6 +57,13 @@ struct image_info bool is9Patch; Res_png_9patch info9Patch; + // Layout padding, if relevant + bool haveLayoutBounds; + int32_t layoutBoundsLeft; + int32_t layoutBoundsTop; + int32_t layoutBoundsRight; + int32_t layoutBoundsBottom; + png_uint_32 allocHeight; png_bytepp allocRows; }; @@ -129,33 +136,62 @@ static void read_png(const char* imageName, &interlace_type, &compression_type, NULL); } -static bool is_tick(png_bytep p, bool transparent, const char** outError) +#define COLOR_TRANSPARENT 0 +#define COLOR_WHITE 0xFFFFFFFF +#define COLOR_TICK 0xFF000000 +#define COLOR_LAYOUT_BOUNDS_TICK 0xFF0000FF + +enum { + TICK_TYPE_NONE, + TICK_TYPE_TICK, + TICK_TYPE_LAYOUT_BOUNDS, + TICK_TYPE_BOTH +}; + +static int tick_type(png_bytep p, bool transparent, const char** outError) { + png_uint_32 color = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); + if (transparent) { if (p[3] == 0) { - return false; + return TICK_TYPE_NONE; + } + if (color == COLOR_LAYOUT_BOUNDS_TICK) { + return TICK_TYPE_LAYOUT_BOUNDS; } + if (color == COLOR_TICK) { + return TICK_TYPE_TICK; + } + + // Error cases if (p[3] != 0xff) { *outError = "Frame pixels must be either solid or transparent (not intermediate alphas)"; - return false; + return TICK_TYPE_NONE; } if (p[0] != 0 || p[1] != 0 || p[2] != 0) { - *outError = "Ticks in transparent frame must be black"; + *outError = "Ticks in transparent frame must be black or red"; } - return true; + return TICK_TYPE_TICK; } 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 (color == COLOR_WHITE) { + return TICK_TYPE_NONE; + } + if (color == COLOR_TICK) { + return TICK_TYPE_TICK; } + if (color == COLOR_LAYOUT_BOUNDS_TICK) { + return TICK_TYPE_LAYOUT_BOUNDS; + } + if (p[0] != 0 || p[1] != 0 || p[2] != 0) { - *outError = "Ticks in white frame must be black"; - return false; + *outError = "Ticks in white frame must be black or red"; + return TICK_TYPE_NONE; } - return true; + return TICK_TYPE_TICK; } enum { @@ -175,7 +211,7 @@ static status_t get_horizontal_ticks( bool found = false; for (i=1; i<width-1; i++) { - if (is_tick(row+i*4, transparent, outError)) { + if (TICK_TYPE_TICK == tick_type(row+i*4, transparent, outError)) { if (state == TICK_START || (state == TICK_OUTSIDE_1 && multipleAllowed)) { *outLeft = i-1; @@ -224,7 +260,7 @@ static status_t get_vertical_ticks( bool found = false; for (i=1; i<height-1; i++) { - if (is_tick(rows[i]+offset, transparent, outError)) { + if (TICK_TYPE_TICK == tick_type(rows[i]+offset, transparent, outError)) { if (state == TICK_START || (state == TICK_OUTSIDE_1 && multipleAllowed)) { *outTop = i-1; @@ -262,6 +298,83 @@ static status_t get_vertical_ticks( return NO_ERROR; } +static status_t get_horizontal_layout_bounds_ticks( + png_bytep row, int width, bool transparent, bool required, + int32_t* outLeft, int32_t* outRight, const char** outError) +{ + int i; + *outLeft = *outRight = 0; + + // Look for left tick + if (TICK_TYPE_LAYOUT_BOUNDS == tick_type(row + 4, transparent, outError)) { + // Starting with a layout padding tick + i = 1; + while (i < width - 1) { + (*outLeft)++; + i++; + int tick = tick_type(row + i * 4, transparent, outError); + if (tick != TICK_TYPE_LAYOUT_BOUNDS) { + break; + } + } + } + + // Look for right tick + if (TICK_TYPE_LAYOUT_BOUNDS == tick_type(row + (width - 2) * 4, transparent, outError)) { + // Ending with a layout padding tick + i = width - 2; + while (i > 1) { + (*outRight)++; + i--; + int tick = tick_type(row+i*4, transparent, outError); + if (tick != TICK_TYPE_LAYOUT_BOUNDS) { + break; + } + } + } + + return NO_ERROR; +} + +static status_t get_vertical_layout_bounds_ticks( + png_bytepp rows, int offset, int height, bool transparent, bool required, + int32_t* outTop, int32_t* outBottom, const char** outError) +{ + int i; + *outTop = *outBottom = 0; + + // Look for top tick + if (TICK_TYPE_LAYOUT_BOUNDS == tick_type(rows[1] + offset, transparent, outError)) { + // Starting with a layout padding tick + i = 1; + while (i < height - 1) { + (*outTop)++; + i++; + int tick = tick_type(rows[i] + offset, transparent, outError); + if (tick != TICK_TYPE_LAYOUT_BOUNDS) { + break; + } + } + } + + // Look for bottom tick + if (TICK_TYPE_LAYOUT_BOUNDS == tick_type(rows[height - 2] + offset, transparent, outError)) { + // Ending with a layout padding tick + i = height - 2; + while (i > 1) { + (*outBottom)++; + i--; + int tick = tick_type(rows[i] + offset, transparent, outError); + if (tick != TICK_TYPE_LAYOUT_BOUNDS) { + break; + } + } + } + + return NO_ERROR; +} + + static uint32_t get_color( png_bytepp rows, int left, int top, int right, int bottom) { @@ -353,6 +466,9 @@ static status_t do_9patch(const char* imageName, image_info* image) image->info9Patch.paddingLeft = image->info9Patch.paddingRight = image->info9Patch.paddingTop = image->info9Patch.paddingBottom = -1; + image->layoutBoundsLeft = image->layoutBoundsRight = + image->layoutBoundsTop = image->layoutBoundsBottom = 0; + png_bytep p = image->rows[0]; bool transparent = p[3] == 0; bool hasColor = false; @@ -408,6 +524,25 @@ static status_t do_9patch(const char* imageName, image_info* image) goto getout; } + // Find left and right of layout padding... + get_horizontal_layout_bounds_ticks(image->rows[H-1], W, transparent, false, + &image->layoutBoundsLeft, + &image->layoutBoundsRight, &errorMsg); + + get_vertical_layout_bounds_ticks(image->rows, (W-1)*4, H, transparent, false, + &image->layoutBoundsTop, + &image->layoutBoundsBottom, &errorMsg); + + image->haveLayoutBounds = image->layoutBoundsLeft != 0 + || image->layoutBoundsRight != 0 + || image->layoutBoundsTop != 0 + || image->layoutBoundsBottom != 0; + + if (image->haveLayoutBounds) { + NOISY(printf("layoutBounds=%d %d %d %d\n", image->layoutBoundsLeft, image->layoutBoundsTop, + image->layoutBoundsRight, image->layoutBoundsBottom)); + } + // Copy patch data into image image->info9Patch.numXDivs = numXDivs; image->info9Patch.numYDivs = numYDivs; @@ -845,8 +980,9 @@ static void write_png(const char* imageName, int bit_depth, interlace_type, compression_type; int i; - png_unknown_chunk unknowns[1]; + png_unknown_chunk unknowns[2]; unknowns[0].data = NULL; + unknowns[1].data = NULL; png_bytepp outRows = (png_bytepp) malloc((int) imageInfo.height * png_sizeof(png_bytep)); if (outRows == (png_bytepp) 0) { @@ -916,23 +1052,42 @@ static void write_png(const char* imageName, } if (imageInfo.is9Patch) { + int chunk_count = 1 + (imageInfo.haveLayoutBounds ? 1 : 0); + int p_index = imageInfo.haveLayoutBounds ? 1 : 0; + int b_index = 0; + png_byte *chunk_names = imageInfo.haveLayoutBounds + ? (png_byte*)"npLb\0npTc\0" + : (png_byte*)"npTc"; NOISY(printf("Adding 9-patch info...\n")); - strcpy((char*)unknowns[0].name, "npTc"); - unknowns[0].data = (png_byte*)imageInfo.info9Patch.serialize(); - unknowns[0].size = imageInfo.info9Patch.serializedSize(); + strcpy((char*)unknowns[p_index].name, "npTc"); + unknowns[p_index].data = (png_byte*)imageInfo.info9Patch.serialize(); + unknowns[p_index].size = imageInfo.info9Patch.serializedSize(); // TODO: remove the check below when everything works - checkNinePatchSerialization(&imageInfo.info9Patch, unknowns[0].data); + checkNinePatchSerialization(&imageInfo.info9Patch, unknowns[p_index].data); + + if (imageInfo.haveLayoutBounds) { + int chunk_size = sizeof(png_uint_32) * 4; + strcpy((char*)unknowns[b_index].name, "npLb"); + unknowns[b_index].data = (png_byte*) calloc(chunk_size, 1); + memcpy(unknowns[b_index].data, &imageInfo.layoutBoundsLeft, chunk_size); + unknowns[b_index].size = chunk_size; + } + 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); + chunk_names, chunk_count); + png_set_unknown_chunks(write_ptr, write_info, unknowns, chunk_count); // 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); + if (imageInfo.haveLayoutBounds) { + png_set_unknown_chunk_location(write_ptr, write_info, 1, PNG_HAVE_PLTE); + } } + png_write_info(write_ptr, write_info); png_bytepp rows; @@ -954,6 +1109,7 @@ static void write_png(const char* imageName, } free(outRows); free(unknowns[0].data); + free(unknowns[1].data); png_get_IHDR(write_ptr, write_info, &width, &height, &bit_depth, &color_type, &interlace_type, @@ -964,7 +1120,7 @@ static void write_png(const char* imageName, compression_type)); } -status_t preProcessImage(Bundle* bundle, const sp<AaptAssets>& assets, +status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets, const sp<AaptFile>& file, String8* outNewLeafName) { String8 ext(file->getPath().getPathExtension()); @@ -1084,7 +1240,7 @@ bail: return error; } -status_t preProcessImageToCache(Bundle* bundle, String8 source, String8 dest) +status_t preProcessImageToCache(const Bundle* bundle, const String8& source, const String8& dest) { png_structp read_ptr = NULL; png_infop read_info = NULL; diff --git a/tools/aapt/Images.h b/tools/aapt/Images.h index 4816905..91b6554 100644 --- a/tools/aapt/Images.h +++ b/tools/aapt/Images.h @@ -15,10 +15,10 @@ using android::String8; -status_t preProcessImage(Bundle* bundle, const sp<AaptAssets>& assets, +status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets, const sp<AaptFile>& file, String8* outNewLeafName); -status_t preProcessImageToCache(Bundle* bundle, String8 source, String8 dest); +status_t preProcessImageToCache(const Bundle* bundle, const String8& source, const String8& dest); status_t postProcessImage(const sp<AaptAssets>& assets, ResourceTable* table, const sp<AaptFile>& file); diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index 1ecf7da..b9ec30c 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -14,6 +14,8 @@ #include "FileFinder.h" #include "CacheUpdater.h" +#include <utils/WorkQueue.h> + #if HAVE_PRINTF_ZD # define ZD "%zd" # define ZD_TYPE ssize_t @@ -24,6 +26,9 @@ #define NOISY(x) // x +// Number of threads to use for preprocessing images. +static const size_t MAX_THREADS = 4; + // ========================================================================== // ========================================================================== // ========================================================================== @@ -302,21 +307,52 @@ static status_t makeFileResources(Bundle* bundle, const sp<AaptAssets>& assets, return hasErrors ? UNKNOWN_ERROR : NO_ERROR; } -static status_t preProcessImages(Bundle* bundle, const sp<AaptAssets>& assets, +class PreProcessImageWorkUnit : public WorkQueue::WorkUnit { +public: + PreProcessImageWorkUnit(const Bundle* bundle, const sp<AaptAssets>& assets, + const sp<AaptFile>& file, volatile bool* hasErrors) : + mBundle(bundle), mAssets(assets), mFile(file), mHasErrors(hasErrors) { + } + + virtual bool run() { + status_t status = preProcessImage(mBundle, mAssets, mFile, NULL); + if (status) { + *mHasErrors = true; + } + return true; // continue even if there are errors + } + +private: + const Bundle* mBundle; + sp<AaptAssets> mAssets; + sp<AaptFile> mFile; + volatile bool* mHasErrors; +}; + +static status_t preProcessImages(const Bundle* bundle, const sp<AaptAssets>& assets, const sp<ResourceTypeSet>& set, const char* type) { - bool hasErrors = false; + volatile bool hasErrors = false; ssize_t res = NO_ERROR; if (bundle->getUseCrunchCache() == false) { + WorkQueue wq(MAX_THREADS, false); ResourceDirIterator it(set, String8(type)); - Vector<sp<AaptFile> > newNameFiles; - Vector<String8> newNamePaths; while ((res=it.next()) == NO_ERROR) { - res = preProcessImage(bundle, assets, it.getFile(), NULL); - if (res < NO_ERROR) { + PreProcessImageWorkUnit* w = new PreProcessImageWorkUnit( + bundle, assets, it.getFile(), &hasErrors); + status_t status = wq.schedule(w); + if (status) { + fprintf(stderr, "preProcessImages failed: schedule() returned %d\n", status); hasErrors = true; + delete w; + break; } } + status_t status = wq.finish(); + if (status) { + fprintf(stderr, "preProcessImages failed: finish() returned %d\n", status); + hasErrors = true; + } } return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR; } @@ -847,8 +883,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets) * request UTF-16 encoding and the parameters of this package * allow UTF-8 to be used. */ - if (!bundle->getWantUTF16() - && bundle->isMinSdkAtLeast(SDK_FROYO)) { + if (!bundle->getUTF16StringsOption()) { xmlFlags |= XML_COMPILE_UTF8; } @@ -1809,7 +1844,7 @@ static status_t writeSymbolClass( if (sym.typeCode != AaptSymbolEntry::TYPE_INT32) { continue; } - if (!includePrivate && !sym.isPublic) { + if (!assets->isJavaSymbol(sym, includePrivate)) { continue; } String16 name(sym.name); @@ -1865,7 +1900,7 @@ static status_t writeSymbolClass( if (sym.typeCode != AaptSymbolEntry::TYPE_STRING) { continue; } - if (!includePrivate && !sym.isPublic) { + if (!assets->isJavaSymbol(sym, includePrivate)) { continue; } String16 name(sym.name); @@ -1977,7 +2012,8 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets, "\n" "package %s;\n\n", package.string()); - status_t err = writeSymbolClass(fp, assets, includePrivate, symbols, className, 0, bundle->getNonConstantId()); + status_t err = writeSymbolClass(fp, assets, includePrivate, symbols, + className, 0, bundle->getNonConstantId()); if (err != NO_ERROR) { return err; } diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index fdb39ca..0195727 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -9,8 +9,8 @@ #include "XMLNode.h" #include "ResourceFilter.h" +#include <androidfw/ResourceTypes.h> #include <utils/ByteOrder.h> -#include <utils/ResourceTypes.h> #include <stdarg.h> #define NOISY(x) //x @@ -753,6 +753,7 @@ status_t compileResourceFile(Bundle* bundle, const String16 public16("public"); const String16 public_padding16("public-padding"); const String16 private_symbols16("private-symbols"); + const String16 java_symbol16("java-symbol"); const String16 add_resource16("add-resource"); const String16 skip16("skip"); const String16 eat_comment16("eat-comment"); @@ -1058,6 +1059,49 @@ status_t compileResourceFile(Bundle* bundle, } continue; + } else if (strcmp16(block.getElementName(&len), java_symbol16.string()) == 0) { + SourcePos srcPos(in->getPrintableSource(), block.getLineNumber()); + + String16 type; + ssize_t typeIdx = block.indexOfAttribute(NULL, "type"); + if (typeIdx < 0) { + srcPos.error("A 'type' attribute is required for <public>\n"); + hasErrors = localHasErrors = true; + } + type = String16(block.getAttributeStringValue(typeIdx, &len)); + + String16 name; + ssize_t nameIdx = block.indexOfAttribute(NULL, "name"); + if (nameIdx < 0) { + srcPos.error("A 'name' attribute is required for <public>\n"); + hasErrors = localHasErrors = true; + } + name = String16(block.getAttributeStringValue(nameIdx, &len)); + + sp<AaptSymbols> symbols = assets->getJavaSymbolsFor(String8("R")); + if (symbols != NULL) { + symbols = symbols->addNestedSymbol(String8(type), srcPos); + } + if (symbols != NULL) { + symbols->makeSymbolJavaSymbol(String8(name), srcPos); + String16 comment( + block.getComment(&len) ? block.getComment(&len) : nulStr); + symbols->appendComment(String8(name), comment, srcPos); + } else { + srcPos.error("Unable to create symbols!\n"); + hasErrors = localHasErrors = true; + } + + while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { + if (code == ResXMLTree::END_TAG) { + if (strcmp16(block.getElementName(&len), java_symbol16.string()) == 0) { + break; + } + } + } + continue; + + } else if (strcmp16(block.getElementName(&len), add_resource16.string()) == 0) { SourcePos srcPos(in->getPrintableSource(), block.getLineNumber()); @@ -2047,7 +2091,8 @@ bool ResourceTable::stringToValue(Res_value* outValue, StringPool* pool, uint32_t attrID, const Vector<StringPool::entry_style_span>* style, String16* outStr, void* accessorCookie, - uint32_t attrType) + uint32_t attrType, const String8* configTypeName, + const ConfigDescription* config) { String16 finalStr; @@ -2075,10 +2120,19 @@ bool ResourceTable::stringToValue(Res_value* outValue, StringPool* pool, if (outValue->dataType == outValue->TYPE_STRING) { // Should do better merging styles. if (pool) { + String8 configStr; + if (config != NULL) { + configStr = config->toString(); + } else { + configStr = "(null)"; + } + NOISY(printf("Adding to pool string style #%d config %s: %s\n", + style != NULL ? style->size() : 0, + configStr.string(), String8(finalStr).string())); if (style != NULL && style->size() > 0) { - outValue->data = pool->add(finalStr, *style); + outValue->data = pool->add(finalStr, *style, configTypeName, config); } else { - outValue->data = pool->add(finalStr, true); + outValue->data = pool->add(finalStr, true, configTypeName, config); } } else { // Caller will fill this in later. @@ -2250,10 +2304,8 @@ bool ResourceTable::getAttributeFlags( const char16_t* end = name + nameLen; const char16_t* pos = name; - bool failed = false; - while (pos < end && !failed) { + while (pos < end) { const char16_t* start = pos; - end++; while (pos < end && *pos != '|') { pos++; } @@ -2279,9 +2331,7 @@ bool ResourceTable::getAttributeFlags( // Didn't find this flag identifier. return false; } - if (pos < end) { - pos++; - } + pos++; } return true; @@ -2537,16 +2587,19 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest) return err; } + const ConfigDescription nullConfig; + const size_t N = mOrderedPackages.size(); size_t pi; const static String16 mipmap16("mipmap"); - bool useUTF8 = !bundle->getWantUTF16() && bundle->isMinSdkAtLeast(SDK_FROYO); + bool useUTF8 = !bundle->getUTF16StringsOption(); // Iterate through all data, collecting all values (strings, // references, etc). - StringPool valueStrings = StringPool(false, useUTF8); + StringPool valueStrings(useUTF8); + Vector<sp<Entry> > allEntries; for (pi=0; pi<N; pi++) { sp<Package> p = mOrderedPackages.itemAt(pi); if (p->getTypes().size() == 0) { @@ -2554,8 +2607,8 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest) continue; } - StringPool typeStrings = StringPool(false, useUTF8); - StringPool keyStrings = StringPool(false, useUTF8); + StringPool typeStrings(useUTF8); + StringPool keyStrings(useUTF8); const size_t N = p->getOrderedTypes().size(); for (size_t ti=0; ti<N; ti++) { @@ -2567,6 +2620,19 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest) const String16 typeName(t->getName()); typeStrings.add(typeName, false); + // This is a hack to tweak the sorting order of the final strings, + // to put stuff that is generally not language-specific first. + String8 configTypeName(typeName); + if (configTypeName == "drawable" || configTypeName == "layout" + || configTypeName == "color" || configTypeName == "anim" + || configTypeName == "interpolator" || configTypeName == "animator" + || configTypeName == "xml" || configTypeName == "menu" + || configTypeName == "mipmap" || configTypeName == "raw") { + configTypeName = "1complex"; + } else { + configTypeName = "2value"; + } + const bool filterable = (typeName != mipmap16); const size_t N = t->getOrderedConfigs().size(); @@ -2586,10 +2652,21 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest) continue; } e->setNameIndex(keyStrings.add(e->getName(), true)); - status_t err = e->prepareFlatten(&valueStrings, this); + + // If this entry has no values for other configs, + // and is the default config, then it is special. Otherwise + // we want to add it with the config info. + ConfigDescription* valueConfig = NULL; + if (N != 1 || config == nullConfig) { + valueConfig = &config; + } + + status_t err = e->prepareFlatten(&valueStrings, this, + &configTypeName, &config); if (err != NO_ERROR) { return err; } + allEntries.add(e); } } } @@ -2598,6 +2675,17 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest) p->setKeyStrings(keyStrings.createStringBlock()); } + if (bundle->getOutputAPKFile() != NULL) { + // Now we want to sort the value strings for better locality. This will + // cause the positions of the strings to change, so we need to go back + // through out resource entries and update them accordingly. Only need + // to do this if actually writing the output file. + valueStrings.sortByConfig(); + for (pi=0; pi<allEntries.size(); pi++) { + allEntries[pi]->remapStringValue(&valueStrings); + } + } + ssize_t strAmt = 0; // Now build the array of package chunks. @@ -3137,14 +3225,16 @@ status_t ResourceTable::Entry::assignResourceIds(ResourceTable* table, return hasErrors ? UNKNOWN_ERROR : NO_ERROR; } -status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable* table) +status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable* table, + const String8* configTypeName, const ConfigDescription* config) { if (mType == TYPE_ITEM) { Item& it = mItem; AccessorCookie ac(it.sourcePos, String8(mName), String8(it.value)); if (!table->stringToValue(&it.parsedValue, strings, it.value, false, true, 0, - &it.style, NULL, &ac, mItemFormat)) { + &it.style, NULL, &ac, mItemFormat, + configTypeName, config)) { return UNKNOWN_ERROR; } } else if (mType == TYPE_BAG) { @@ -3155,7 +3245,8 @@ status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable AccessorCookie ac(it.sourcePos, String8(key), String8(it.value)); if (!table->stringToValue(&it.parsedValue, strings, it.value, false, true, it.bagKeyId, - &it.style, NULL, &ac, it.format)) { + &it.style, NULL, &ac, it.format, + configTypeName, config)) { return UNKNOWN_ERROR; } } @@ -3167,6 +3258,29 @@ status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable return NO_ERROR; } +status_t ResourceTable::Entry::remapStringValue(StringPool* strings) +{ + if (mType == TYPE_ITEM) { + Item& it = mItem; + if (it.parsedValue.dataType == Res_value::TYPE_STRING) { + it.parsedValue.data = strings->mapOriginalPosToNewPos(it.parsedValue.data); + } + } else if (mType == TYPE_BAG) { + const size_t N = mBag.size(); + for (size_t i=0; i<N; i++) { + Item& it = mBag.editValueAt(i); + if (it.parsedValue.dataType == Res_value::TYPE_STRING) { + it.parsedValue.data = strings->mapOriginalPosToNewPos(it.parsedValue.data); + } + } + } else { + mPos.error("Error: entry %s is not a single item or a bag.\n", + String8(mName).string()); + return UNKNOWN_ERROR; + } + return NO_ERROR; +} + ssize_t ResourceTable::Entry::flatten(Bundle* bundle, const sp<AaptFile>& data, bool isPublic) { size_t amt = 0; diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h index 8123bb3..a3e0666 100644 --- a/tools/aapt/ResourceTable.h +++ b/tools/aapt/ResourceTable.h @@ -76,6 +76,37 @@ public: class Type; class Entry; + struct ConfigDescription : public ResTable_config { + ConfigDescription() { + memset(this, 0, sizeof(*this)); + size = sizeof(ResTable_config); + } + ConfigDescription(const ResTable_config&o) { + *static_cast<ResTable_config*>(this) = o; + size = sizeof(ResTable_config); + } + ConfigDescription(const ConfigDescription&o) { + *static_cast<ResTable_config*>(this) = o; + } + + ConfigDescription& operator=(const ResTable_config& o) { + *static_cast<ResTable_config*>(this) = o; + size = sizeof(ResTable_config); + return *this; + } + ConfigDescription& operator=(const ConfigDescription& o) { + *static_cast<ResTable_config*>(this) = o; + return *this; + } + + inline bool operator<(const ConfigDescription& o) const { return compare(o) < 0; } + inline bool operator<=(const ConfigDescription& o) const { return compare(o) <= 0; } + inline bool operator==(const ConfigDescription& o) const { return compare(o) == 0; } + inline bool operator!=(const ConfigDescription& o) const { return compare(o) != 0; } + inline bool operator>=(const ConfigDescription& o) const { return compare(o) >= 0; } + inline bool operator>(const ConfigDescription& o) const { return compare(o) > 0; } + }; + ResourceTable(Bundle* bundle, const String16& assetsPackage); status_t addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets); @@ -183,7 +214,9 @@ public: uint32_t attrID, const Vector<StringPool::entry_style_span>* style = NULL, String16* outStr = NULL, void* accessorCookie = NULL, - uint32_t attrType = ResTable_map::TYPE_ANY); + uint32_t attrType = ResTable_map::TYPE_ANY, + const String8* configTypeName = NULL, + const ConfigDescription* config = NULL); status_t assignResourceIds(); status_t addSymbols(const sp<AaptSymbols>& outSymbols = NULL); @@ -305,7 +338,10 @@ public: status_t assignResourceIds(ResourceTable* table, const String16& package); - status_t prepareFlatten(StringPool* strings, ResourceTable* table); + status_t prepareFlatten(StringPool* strings, ResourceTable* table, + const String8* configTypeName, const ConfigDescription* config); + + status_t remapStringValue(StringPool* strings); ssize_t flatten(Bundle*, const sp<AaptFile>& data, bool isPublic); @@ -322,37 +358,6 @@ public: 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<ResTable_config*>(this) = o; - size = sizeof(ResTable_config); - } - ConfigDescription(const ConfigDescription&o) { - *static_cast<ResTable_config*>(this) = o; - } - - ConfigDescription& operator=(const ResTable_config& o) { - *static_cast<ResTable_config*>(this) = o; - size = sizeof(ResTable_config); - return *this; - } - ConfigDescription& operator=(const ConfigDescription& o) { - *static_cast<ResTable_config*>(this) = o; - return *this; - } - - inline bool operator<(const ConfigDescription& o) const { return compare(o) < 0; } - inline bool operator<=(const ConfigDescription& o) const { return compare(o) <= 0; } - inline bool operator==(const ConfigDescription& o) const { return compare(o) == 0; } - inline bool operator!=(const ConfigDescription& o) const { return compare(o) != 0; } - inline bool operator>=(const ConfigDescription& o) const { return compare(o) >= 0; } - inline bool operator>(const ConfigDescription& o) const { return compare(o) > 0; } - }; class ConfigList : public RefBase { public: diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp index 9a0a1c4..839eda5 100644 --- a/tools/aapt/StringPool.cpp +++ b/tools/aapt/StringPool.cpp @@ -5,8 +5,11 @@ // #include "StringPool.h" +#include "ResourceTable.h" #include <utils/ByteOrder.h> +#include <utils/SortedVector.h> +#include <cutils/qsort_r_compat.h> #if HAVE_PRINTF_ZD # define ZD "%zd" @@ -30,49 +33,92 @@ void strcpy16_htod(uint16_t* dst, const uint16_t* src) void printStringPool(const ResStringPool* pool) { - const size_t NS = pool->size(); - for (size_t s=0; s<NS; s++) { + SortedVector<const void*> uniqueStrings; + const size_t N = pool->size(); + for (size_t i=0; i<N; i++) { size_t len; - const char *str = (const char*)pool->string8At(s, &len); - if (str == NULL) { - str = String8(pool->stringAt(s, &len)).string(); + if (pool->isUTF8()) { + uniqueStrings.add(pool->string8At(i, &len)); + } else { + uniqueStrings.add(pool->stringAt(i, &len)); } + } - printf("String #" ZD ": %s\n", (ZD_TYPE) s, str); + printf("String pool of " ZD " unique %s %s strings, " ZD " entries and " + ZD " styles using " ZD " bytes:\n", + (ZD_TYPE)uniqueStrings.size(), pool->isUTF8() ? "UTF-8" : "UTF-16", + pool->isSorted() ? "sorted" : "non-sorted", + (ZD_TYPE)N, (ZD_TYPE)pool->styleCount(), (ZD_TYPE)pool->bytes()); + + const size_t NS = pool->size(); + for (size_t s=0; s<NS; s++) { + String8 str = pool->string8ObjectAt(s); + printf("String #" ZD ": %s\n", (ZD_TYPE) s, str.string()); } } -StringPool::StringPool(bool sorted, bool utf8) - : mSorted(sorted), mUTF8(utf8), mValues(-1), mIdents(-1) -{ +String8 StringPool::entry::makeConfigsString() const { + String8 configStr(configTypeName); + if (configStr.size() > 0) configStr.append(" "); + if (configs.size() > 0) { + for (size_t j=0; j<configs.size(); j++) { + if (j > 0) configStr.append(", "); + configStr.append(configs[j].toString()); + } + } else { + configStr = "(none)"; + } + return configStr; } -ssize_t StringPool::add(const String16& value, bool mergeDuplicates) +int StringPool::entry::compare(const entry& o) const { + // Strings with styles go first, to reduce the size of the styles array. + // We don't care about the relative order of these strings. + if (hasStyles) { + return o.hasStyles ? 0 : -1; + } + if (o.hasStyles) { + return 1; + } + + // Sort unstyled strings by type, then by logical configuration. + int comp = configTypeName.compare(o.configTypeName); + if (comp != 0) { + return comp; + } + const size_t LHN = configs.size(); + const size_t RHN = o.configs.size(); + size_t i=0; + while (i < LHN && i < RHN) { + comp = configs[i].compareLogical(o.configs[i]); + if (comp != 0) { + return comp; + } + i++; + } + if (LHN < RHN) return -1; + else if (LHN > RHN) return 1; + return 0; +} + +StringPool::StringPool(bool utf8) : + mUTF8(utf8), mValues(-1) { - return add(String16(), value, mergeDuplicates); } -ssize_t StringPool::add(const String16& value, const Vector<entry_style_span>& spans) +ssize_t StringPool::add(const String16& value, const Vector<entry_style_span>& spans, + const String8* configTypeName, const ResTable_config* config) { - ssize_t res = add(String16(), value, false); + ssize_t res = add(value, false, configTypeName, config); if (res >= 0) { addStyleSpans(res, spans); } return res; } -ssize_t StringPool::add(const String16& ident, const String16& value, - bool mergeDuplicates) +ssize_t StringPool::add(const String16& value, + bool mergeDuplicates, const String8* configTypeName, const ResTable_config* config) { - 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; @@ -84,28 +130,47 @@ ssize_t StringPool::add(const String16& ident, const String16& value, } } - 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<N; i++) { - size_t& e = mEntryArrayToValues.editItemAt(i); - if ((ssize_t)e >= vidx) { - e++; + if (configTypeName != NULL) { + entry& ent = mEntries.editItemAt(eidx); + NOISY(printf("*** adding config type name %s, was %s\n", + configTypeName->string(), ent.configTypeName.string())); + if (ent.configTypeName.size() <= 0) { + ent.configTypeName = *configTypeName; + } else if (ent.configTypeName != *configTypeName) { + ent.configTypeName = " "; + } + } + + if (config != NULL) { + // Add this to the set of configs associated with the string. + entry& ent = mEntries.editItemAt(eidx); + size_t addPos; + for (addPos=0; addPos<ent.configs.size(); addPos++) { + int cmp = ent.configs.itemAt(addPos).compareLogical(*config); + if (cmp >= 0) { + if (cmp > 0) { + NOISY(printf("*** inserting config: %s\n", config->toString().string())); + ent.configs.insertAt(*config, addPos); } + break; } } - mEntryArrayToValues.add(vidx); - if (!mSorted) { - entry& ent = mEntries.editItemAt(eidx); - ent.indices.add(pos); + if (addPos >= ent.configs.size()) { + NOISY(printf("*** adding config: %s\n", config->toString().string())); + ent.configs.add(*config); } } - if (ident.size() > 0) { - mIdents.add(ident, vidx); + const bool first = vidx < 0; + const bool styled = (pos >= 0 && (size_t)pos < mEntryStyleArray.size()) ? + mEntryStyleArray[pos].spans.size() : 0; + if (first || styled || !mergeDuplicates) { + pos = mEntryArray.add(eidx); + if (first) { + vidx = mValues.add(value, pos); + } + entry& ent = mEntries.editItemAt(eidx); + ent.indices.add(pos); } NOISY(printf("Adding string %s to pool: pos=%d eidx=%d vidx=%d\n", @@ -138,8 +203,6 @@ status_t StringPool::addStyleSpans(size_t idx, const Vector<entry_style_span>& s status_t StringPool::addStyleSpan(size_t idx, const entry_style_span& span) { - LOG_ALWAYS_FATAL_IF(mSorted, "Can't use styles with sorted string pools."); - // Place blank entries in the span array up to this index. while (mEntryStyleArray.size() <= idx) { mEntryStyleArray.add(); @@ -147,26 +210,136 @@ status_t StringPool::addStyleSpan(size_t idx, const entry_style_span& span) entry_style& style = mEntryStyleArray.editItemAt(idx); style.spans.add(span); + mEntries.editItemAt(mEntryArray[idx]).hasStyles = true; return NO_ERROR; } -size_t StringPool::size() const +int StringPool::config_sort(void* state, const void* lhs, const void* rhs) { - return mSorted ? mValues.size() : mEntryArray.size(); + StringPool* pool = (StringPool*)state; + const entry& lhe = pool->mEntries[pool->mEntryArray[*static_cast<const size_t*>(lhs)]]; + const entry& rhe = pool->mEntries[pool->mEntryArray[*static_cast<const size_t*>(rhs)]]; + return lhe.compare(rhe); } -const StringPool::entry& StringPool::entryAt(size_t idx) const +void StringPool::sortByConfig() { - if (!mSorted) { - return mEntries[mEntryArray[idx]]; - } else { - return mEntries[mEntryArray[mValues.valueAt(idx)]]; + LOG_ALWAYS_FATAL_IF(mOriginalPosToNewPos.size() > 0, "Can't sort string pool after already sorted."); + + const size_t N = mEntryArray.size(); + + // This is a vector that starts out with a 1:1 mapping to entries + // in the array, which we will sort to come up with the desired order. + // At that point it maps from the new position in the array to the + // original position the entry appeared. + Vector<size_t> newPosToOriginalPos; + newPosToOriginalPos.setCapacity(N); + for (size_t i=0; i < N; i++) { + newPosToOriginalPos.add(i); } -} -size_t StringPool::countIdentifiers() const -{ - return mIdents.size(); + // Sort the array. + NOISY(printf("SORTING STRINGS BY CONFIGURATION...\n")); + // Vector::sort uses insertion sort, which is very slow for this data set. + // Use quicksort instead because we don't need a stable sort here. + qsort_r_compat(newPosToOriginalPos.editArray(), N, sizeof(size_t), this, config_sort); + //newPosToOriginalPos.sort(config_sort, this); + NOISY(printf("DONE SORTING STRINGS BY CONFIGURATION.\n")); + + // Create the reverse mapping from the original position in the array + // to the new position where it appears in the sorted array. This is + // so that clients can re-map any positions they had previously stored. + mOriginalPosToNewPos = newPosToOriginalPos; + for (size_t i=0; i<N; i++) { + mOriginalPosToNewPos.editItemAt(newPosToOriginalPos[i]) = i; + } + +#if 0 + SortedVector<entry> entries; + + for (size_t i=0; i<N; i++) { + printf("#%d was %d: %s\n", i, newPosToOriginalPos[i], + mEntries[mEntryArray[newPosToOriginalPos[i]]].makeConfigsString().string()); + entries.add(mEntries[mEntryArray[i]]); + } + + for (size_t i=0; i<entries.size(); i++) { + printf("Sorted config #%d: %s\n", i, + entries[i].makeConfigsString().string()); + } +#endif + + // Now we rebuild the arrays. + Vector<entry> newEntries; + Vector<size_t> newEntryArray; + Vector<entry_style> newEntryStyleArray; + DefaultKeyedVector<size_t, size_t> origOffsetToNewOffset; + + for (size_t i=0; i<N; i++) { + // We are filling in new offset 'i'; oldI is where we can find it + // in the original data structure. + size_t oldI = newPosToOriginalPos[i]; + // This is the actual entry associated with the old offset. + const entry& oldEnt = mEntries[mEntryArray[oldI]]; + // This is the same entry the last time we added it to the + // new entry array, if any. + ssize_t newIndexOfOffset = origOffsetToNewOffset.indexOfKey(oldI); + size_t newOffset; + if (newIndexOfOffset < 0) { + // This is the first time we have seen the entry, so add + // it. + newOffset = newEntries.add(oldEnt); + newEntries.editItemAt(newOffset).indices.clear(); + } else { + // We have seen this entry before, use the existing one + // instead of adding it again. + newOffset = origOffsetToNewOffset.valueAt(newIndexOfOffset); + } + // Update the indices to include this new position. + newEntries.editItemAt(newOffset).indices.add(i); + // And add the offset of the entry to the new entry array. + newEntryArray.add(newOffset); + // Add any old style to the new style array. + if (mEntryStyleArray.size() > 0) { + if (oldI < mEntryStyleArray.size()) { + newEntryStyleArray.add(mEntryStyleArray[oldI]); + } else { + newEntryStyleArray.add(entry_style()); + } + } + } + + // Now trim any entries at the end of the new style array that are + // not needed. + for (ssize_t i=newEntryStyleArray.size()-1; i>=0; i--) { + const entry_style& style = newEntryStyleArray[i]; + if (style.spans.size() > 0) { + // That's it. + break; + } + // This one is not needed; remove. + newEntryStyleArray.removeAt(i); + } + + // All done, install the new data structures and upate mValues with + // the new positions. + mEntries = newEntries; + mEntryArray = newEntryArray; + mEntryStyleArray = newEntryStyleArray; + mValues.clear(); + for (size_t i=0; i<mEntries.size(); i++) { + const entry& ent = mEntries[i]; + mValues.add(ent.value, ent.indices[0]); + } + +#if 0 + printf("FINAL SORTED STRING CONFIGS:\n"); + for (size_t i=0; i<mEntries.size(); i++) { + const entry& ent = mEntries[i]; + printf("#" ZD " %s: %s\n", (ZD_TYPE)i, ent.makeConfigsString().string(), + String8(ent.value).string()); + } +#endif } sp<AaptFile> StringPool::createStringBlock() @@ -222,7 +395,7 @@ status_t StringPool::writeStringBlock(const sp<AaptFile>& pool) } } - const size_t ENTRIES = size(); + const size_t ENTRIES = mEntryArray.size(); // Now build the pool of unique strings. @@ -356,9 +529,6 @@ status_t StringPool::writeStringBlock(const sp<AaptFile>& pool) header->header.size = htodl(pool->getSize()); header->stringCount = htodl(ENTRIES); header->styleCount = htodl(STYLES); - if (mSorted) { - header->flags |= htodl(ResStringPool_header::SORTED_FLAG); - } if (mUTF8) { header->flags |= htodl(ResStringPool_header::UTF8_FLAG); } @@ -368,33 +538,18 @@ status_t StringPool::writeStringBlock(const sp<AaptFile>& pool) // Write string index array. uint32_t* index = (uint32_t*)(header+1); - if (mSorted) { - for (i=0; i<ENTRIES; i++) { - entry& ent = const_cast<entry&>(entryAt(i)); - ent.indices.clear(); - ent.indices.add(i); - *index++ = htodl(ent.offset); - } - } else { - for (i=0; i<ENTRIES; i++) { - entry& ent = mEntries.editItemAt(mEntryArray[i]); - *index++ = htodl(ent.offset); - NOISY(printf("Writing entry #%d: \"%s\" ent=%d off=%d\n", i, - String8(ent.value).string(), - mEntryArray[i], ent.offset)); - } + for (i=0; i<ENTRIES; i++) { + entry& ent = mEntries.editItemAt(mEntryArray[i]); + *index++ = htodl(ent.offset); + NOISY(printf("Writing entry #%d: \"%s\" ent=%d off=%d\n", i, + String8(ent.value).string(), + mEntryArray[i], ent.offset)); } // Write style index array. - if (mSorted) { - for (i=0; i<STYLES; i++) { - LOG_ALWAYS_FATAL("Shouldn't be here!"); - } - } else { - for (i=0; i<STYLES; i++) { - *index++ = htodl(mEntryStyleArray[i].offset); - } + for (i=0; i<STYLES; i++) { + *index++ = htodl(mEntryStyleArray[i].offset); } return NO_ERROR; diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h index 7275259..d501008 100644 --- a/tools/aapt/StringPool.h +++ b/tools/aapt/StringPool.h @@ -10,9 +10,10 @@ #include "Main.h" #include "AaptAssets.h" -#include <utils/ResourceTypes.h> +#include <androidfw/ResourceTypes.h> #include <utils/String16.h> #include <utils/TextOutput.h> +#include <utils/TypeHelpers.h> #include <sys/types.h> #include <sys/stat.h> @@ -40,12 +41,28 @@ 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) { } + entry(const String16& _value) : value(_value), offset(0), hasStyles(false) { } + entry(const entry& o) : value(o.value), offset(o.offset), + hasStyles(o.hasStyles), indices(o.indices), + configTypeName(o.configTypeName), configs(o.configs) { } String16 value; size_t offset; + bool hasStyles; Vector<size_t> indices; + String8 configTypeName; + Vector<ResTable_config> configs; + + String8 makeConfigsString() const; + + int compare(const entry& o) const; + + inline bool operator<(const entry& o) const { return compare(o) < 0; } + inline bool operator<=(const entry& o) const { return compare(o) <= 0; } + inline bool operator==(const entry& o) const { return compare(o) == 0; } + inline bool operator!=(const entry& o) const { return compare(o) != 0; } + inline bool operator>=(const entry& o) const { return compare(o) >= 0; } + inline bool operator>(const entry& o) const { return compare(o) > 0; } }; struct entry_style_span { @@ -63,16 +80,10 @@ public: }; /** - * 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). - * * If 'utf8' is true, strings will be encoded with UTF-8 instead of * left in Java's native UTF-16. */ - explicit StringPool(bool sorted = false, bool utf8 = false); + explicit StringPool(bool utf8 = false); /** * Add a new string to the pool. If mergeDuplicates is true, thenif @@ -80,27 +91,30 @@ public: * 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. + * Returns the index in the entry array of the new string entry. */ - ssize_t add(const String16& value, bool mergeDuplicates = false); - - ssize_t add(const String16& value, const Vector<entry_style_span>& spans); + ssize_t add(const String16& value, bool mergeDuplicates = false, + const String8* configTypeName = NULL, const ResTable_config* config = NULL); - ssize_t add(const String16& ident, const String16& value, - bool mergeDuplicates = false); + ssize_t add(const String16& value, const Vector<entry_style_span>& spans, + const String8* configTypeName = NULL, const ResTable_config* config = NULL); status_t addStyleSpan(size_t idx, const String16& name, uint32_t start, uint32_t end); status_t addStyleSpans(size_t idx, const Vector<entry_style_span>& spans); status_t addStyleSpan(size_t idx, const entry_style_span& span); - size_t size() const; - - const entry& entryAt(size_t idx) const; + // Sort the contents of the string block by the configuration associated + // with each item. After doing this you can use mapOriginalPosToNewPos() + // to find out the new position given the position originally returned by + // add(). + void sortByConfig(); - size_t countIdentifiers() const; + // For use after sortByConfig() to map from the original position of + // a string to its new sorted position. + size_t mapOriginalPosToNewPos(size_t originalPos) const { + return mOriginalPosToNewPos.itemAt(originalPos); + } sp<AaptFile> createStringBlock(); @@ -125,27 +139,45 @@ public: const Vector<size_t>* offsetsForString(const String16& val) const; private: - const bool mSorted; + static int config_sort(void* state, const void* lhs, const void* rhs); + const bool mUTF8; - // Raw array of unique strings, in some arbitrary order. + + // The following data structures represent the actual structures + // that will be generated for the final string pool. + + // Raw array of unique strings, in some arbitrary order. This is the + // actual strings that appear in the final string pool, in the order + // that they will be written. Vector<entry> mEntries; // Array of indices into mEntries, in the order they were // added to the pool. This can be different than mEntries // if the same string was added multiple times (it will appear // once in mEntries, with multiple occurrences in this array). + // This is the lookup array that will be written for finding + // the string for each offset/position in the string pool. Vector<size_t> mEntryArray; // Optional style span information associated with each index of // mEntryArray. Vector<entry_style> mEntryStyleArray; - // Mapping from indices in mEntryArray to indices in mValues. - Vector<size_t> mEntryArrayToValues; + + // The following data structures are used for book-keeping as the + // string pool is constructed. + // Unique set of all the strings added to the pool, mapped to // the first index of mEntryArray where the value was added. DefaultKeyedVector<String16, ssize_t> mValues; - // Unique set of all (optional) identifiers of strings in the - // pool, mapping to indices in mEntries. - DefaultKeyedVector<String16, ssize_t> mIdents; + // This array maps from the original position a string was placed at + // in mEntryArray to its new position after being sorted with sortByConfig(). + Vector<size_t> mOriginalPosToNewPos; +}; +// The entry types are trivially movable because all fields they contain, including +// the vectors and strings, are trivially movable. +namespace android { + ANDROID_TRIVIAL_MOVE_TRAIT(StringPool::entry); + ANDROID_TRIVIAL_MOVE_TRAIT(StringPool::entry_style_span); + ANDROID_TRIVIAL_MOVE_TRAIT(StringPool::entry_style); }; #endif diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp index 8d7acee..0dba950 100644 --- a/tools/aapt/XMLNode.cpp +++ b/tools/aapt/XMLNode.cpp @@ -973,7 +973,7 @@ status_t XMLNode::assignResourceIds(const sp<AaptAssets>& assets, status_t XMLNode::flatten(const sp<AaptFile>& dest, bool stripComments, bool stripRawValues) const { - StringPool strings = StringPool(false, mUTF8); + StringPool strings(mUTF8); Vector<uint32_t> resids; // First collect just the strings for attribute names that have a diff --git a/tools/aapt/ZipEntry.cpp b/tools/aapt/ZipEntry.cpp index a0b54c2..b575988 100644 --- a/tools/aapt/ZipEntry.cpp +++ b/tools/aapt/ZipEntry.cpp @@ -42,12 +42,12 @@ status_t ZipEntry::initFromCDE(FILE* fp) long posn; bool hasDD; - //LOGV("initFromCDE ---\n"); + //ALOGV("initFromCDE ---\n"); /* read the CDE */ result = mCDE.read(fp); if (result != NO_ERROR) { - LOGD("mCDE.read failed\n"); + ALOGD("mCDE.read failed\n"); return result; } @@ -56,14 +56,14 @@ status_t ZipEntry::initFromCDE(FILE* fp) /* using the info in the CDE, go load up the LFH */ posn = ftell(fp); if (fseek(fp, mCDE.mLocalHeaderRelOffset, SEEK_SET) != 0) { - LOGD("local header seek failed (%ld)\n", + ALOGD("local header seek failed (%ld)\n", mCDE.mLocalHeaderRelOffset); return UNKNOWN_ERROR; } result = mLFH.read(fp); if (result != NO_ERROR) { - LOGD("mLFH.read failed\n"); + ALOGD("mLFH.read failed\n"); return result; } @@ -81,7 +81,7 @@ status_t ZipEntry::initFromCDE(FILE* fp) hasDD = (mLFH.mGPBitFlag & kUsesDataDescr) != 0; if (hasDD) { // do something clever - //LOGD("+++ has data descriptor\n"); + //ALOGD("+++ has data descriptor\n"); } /* @@ -90,7 +90,7 @@ status_t ZipEntry::initFromCDE(FILE* fp) * prefer the CDE values.) */ if (!hasDD && !compareHeaders()) { - LOGW("warning: header mismatch\n"); + ALOGW("warning: header mismatch\n"); // keep going? } @@ -200,7 +200,7 @@ status_t ZipEntry::addPadding(int padding) if (padding <= 0) return INVALID_OPERATION; - //LOGI("HEY: adding %d pad bytes to existing %d in %s\n", + //ALOGI("HEY: adding %d pad bytes to existing %d in %s\n", // padding, mLFH.mExtraFieldLength, mCDE.mFileName); if (mLFH.mExtraFieldLength > 0) { @@ -280,50 +280,50 @@ void ZipEntry::setDataInfo(long uncompLen, long compLen, unsigned long crc32, bool ZipEntry::compareHeaders(void) const { if (mCDE.mVersionToExtract != mLFH.mVersionToExtract) { - LOGV("cmp: VersionToExtract\n"); + ALOGV("cmp: VersionToExtract\n"); return false; } if (mCDE.mGPBitFlag != mLFH.mGPBitFlag) { - LOGV("cmp: GPBitFlag\n"); + ALOGV("cmp: GPBitFlag\n"); return false; } if (mCDE.mCompressionMethod != mLFH.mCompressionMethod) { - LOGV("cmp: CompressionMethod\n"); + ALOGV("cmp: CompressionMethod\n"); return false; } if (mCDE.mLastModFileTime != mLFH.mLastModFileTime) { - LOGV("cmp: LastModFileTime\n"); + ALOGV("cmp: LastModFileTime\n"); return false; } if (mCDE.mLastModFileDate != mLFH.mLastModFileDate) { - LOGV("cmp: LastModFileDate\n"); + ALOGV("cmp: LastModFileDate\n"); return false; } if (mCDE.mCRC32 != mLFH.mCRC32) { - LOGV("cmp: CRC32\n"); + ALOGV("cmp: CRC32\n"); return false; } if (mCDE.mCompressedSize != mLFH.mCompressedSize) { - LOGV("cmp: CompressedSize\n"); + ALOGV("cmp: CompressedSize\n"); return false; } if (mCDE.mUncompressedSize != mLFH.mUncompressedSize) { - LOGV("cmp: UncompressedSize\n"); + ALOGV("cmp: UncompressedSize\n"); return false; } if (mCDE.mFileNameLength != mLFH.mFileNameLength) { - LOGV("cmp: FileNameLength\n"); + ALOGV("cmp: FileNameLength\n"); return false; } #if 0 // this seems to be used for padding, not real data if (mCDE.mExtraFieldLength != mLFH.mExtraFieldLength) { - LOGV("cmp: ExtraFieldLength\n"); + ALOGV("cmp: ExtraFieldLength\n"); return false; } #endif if (mCDE.mFileName != NULL) { if (strcmp((char*) mCDE.mFileName, (char*) mLFH.mFileName) != 0) { - LOGV("cmp: FileName\n"); + ALOGV("cmp: FileName\n"); return false; } } @@ -413,7 +413,7 @@ status_t ZipEntry::LocalFileHeader::read(FILE* fp) } if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) { - LOGD("whoops: didn't find expected signature\n"); + ALOGD("whoops: didn't find expected signature\n"); result = UNKNOWN_ERROR; goto bail; } @@ -506,17 +506,17 @@ status_t ZipEntry::LocalFileHeader::write(FILE* fp) */ void ZipEntry::LocalFileHeader::dump(void) const { - LOGD(" LocalFileHeader contents:\n"); - LOGD(" versToExt=%u gpBits=0x%04x compression=%u\n", + ALOGD(" LocalFileHeader contents:\n"); + ALOGD(" versToExt=%u gpBits=0x%04x compression=%u\n", mVersionToExtract, mGPBitFlag, mCompressionMethod); - LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n", + ALOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n", mLastModFileTime, mLastModFileDate, mCRC32); - LOGD(" compressedSize=%lu uncompressedSize=%lu\n", + ALOGD(" compressedSize=%lu uncompressedSize=%lu\n", mCompressedSize, mUncompressedSize); - LOGD(" filenameLen=%u extraLen=%u\n", + ALOGD(" filenameLen=%u extraLen=%u\n", mFileNameLength, mExtraFieldLength); if (mFileName != NULL) - LOGD(" filename: '%s'\n", mFileName); + ALOGD(" filename: '%s'\n", mFileName); } @@ -549,7 +549,7 @@ status_t ZipEntry::CentralDirEntry::read(FILE* fp) } if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) { - LOGD("Whoops: didn't find expected signature\n"); + ALOGD("Whoops: didn't find expected signature\n"); result = UNKNOWN_ERROR; goto bail; } @@ -675,22 +675,22 @@ status_t ZipEntry::CentralDirEntry::write(FILE* fp) */ void ZipEntry::CentralDirEntry::dump(void) const { - LOGD(" CentralDirEntry contents:\n"); - LOGD(" versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n", + ALOGD(" CentralDirEntry contents:\n"); + ALOGD(" versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n", mVersionMadeBy, mVersionToExtract, mGPBitFlag, mCompressionMethod); - LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n", + ALOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n", mLastModFileTime, mLastModFileDate, mCRC32); - LOGD(" compressedSize=%lu uncompressedSize=%lu\n", + ALOGD(" compressedSize=%lu uncompressedSize=%lu\n", mCompressedSize, mUncompressedSize); - LOGD(" filenameLen=%u extraLen=%u commentLen=%u\n", + ALOGD(" filenameLen=%u extraLen=%u commentLen=%u\n", mFileNameLength, mExtraFieldLength, mFileCommentLength); - LOGD(" diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n", + ALOGD(" diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n", mDiskNumberStart, mInternalAttrs, mExternalAttrs, mLocalHeaderRelOffset); if (mFileName != NULL) - LOGD(" filename: '%s'\n", mFileName); + ALOGD(" filename: '%s'\n", mFileName); if (mFileComment != NULL) - LOGD(" comment: '%s'\n", mFileComment); + ALOGD(" comment: '%s'\n", mFileComment); } diff --git a/tools/aapt/ZipFile.cpp b/tools/aapt/ZipFile.cpp index 62c9383..3994c31 100644 --- a/tools/aapt/ZipFile.cpp +++ b/tools/aapt/ZipFile.cpp @@ -20,8 +20,8 @@ #define LOG_TAG "zip" -#include <utils/ZipUtils.h> #include <utils/Log.h> +#include <utils/ZipUtils.h> #include "ZipFile.h" @@ -78,7 +78,7 @@ status_t ZipFile::open(const char* zipFileName, int flags) newArchive = (access(zipFileName, F_OK) != 0); if (!(flags & kOpenCreate) && newArchive) { /* not creating, must already exist */ - LOGD("File %s does not exist", zipFileName); + ALOGD("File %s does not exist", zipFileName); return NAME_NOT_FOUND; } } @@ -96,7 +96,7 @@ status_t ZipFile::open(const char* zipFileName, int flags) mZipFp = fopen(zipFileName, openflags); if (mZipFp == NULL) { int err = errno; - LOGD("fopen failed: %d\n", err); + ALOGD("fopen failed: %d\n", err); return errnoToStatus(err); } @@ -215,14 +215,14 @@ status_t ZipFile::readCentralDir(void) /* too small to be a ZIP archive? */ if (fileLength < EndOfCentralDir::kEOCDLen) { - LOGD("Length is %ld -- too small\n", (long)fileLength); + ALOGD("Length is %ld -- too small\n", (long)fileLength); result = INVALID_OPERATION; goto bail; } buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch]; if (buf == NULL) { - LOGD("Failure allocating %d bytes for EOCD search", + ALOGD("Failure allocating %d bytes for EOCD search", EndOfCentralDir::kMaxEOCDSearch); result = NO_MEMORY; goto bail; @@ -236,14 +236,14 @@ status_t ZipFile::readCentralDir(void) readAmount = (long) fileLength; } if (fseek(mZipFp, seekStart, SEEK_SET) != 0) { - LOGD("Failure seeking to end of zip at %ld", (long) seekStart); + ALOGD("Failure seeking to end of zip at %ld", (long) seekStart); result = UNKNOWN_ERROR; goto bail; } /* read the last part of the file into the buffer */ if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) { - LOGD("short file? wanted %ld\n", readAmount); + ALOGD("short file? wanted %ld\n", readAmount); result = UNKNOWN_ERROR; goto bail; } @@ -253,12 +253,12 @@ status_t ZipFile::readCentralDir(void) if (buf[i] == 0x50 && ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature) { - LOGV("+++ Found EOCD at buf+%d\n", i); + ALOGV("+++ Found EOCD at buf+%d\n", i); break; } } if (i < 0) { - LOGD("EOCD not found, not Zip\n"); + ALOGD("EOCD not found, not Zip\n"); result = INVALID_OPERATION; goto bail; } @@ -266,7 +266,7 @@ status_t ZipFile::readCentralDir(void) /* extract eocd values */ result = mEOCD.readBuf(buf + i, readAmount - i); if (result != NO_ERROR) { - LOGD("Failure reading %ld bytes of EOCD values", readAmount - i); + ALOGD("Failure reading %ld bytes of EOCD values", readAmount - i); goto bail; } //mEOCD.dump(); @@ -274,7 +274,7 @@ status_t ZipFile::readCentralDir(void) if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 || mEOCD.mNumEntries != mEOCD.mTotalNumEntries) { - LOGD("Archive spanning not supported\n"); + ALOGD("Archive spanning not supported\n"); result = INVALID_OPERATION; goto bail; } @@ -294,7 +294,7 @@ status_t ZipFile::readCentralDir(void) * we're hoping to preserve. */ if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) { - LOGD("Failure seeking to central dir offset %ld\n", + ALOGD("Failure seeking to central dir offset %ld\n", mEOCD.mCentralDirOffset); result = UNKNOWN_ERROR; goto bail; @@ -303,14 +303,14 @@ status_t ZipFile::readCentralDir(void) /* * Loop through and read the central dir entries. */ - LOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries); + ALOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries); int entry; for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) { ZipEntry* pEntry = new ZipEntry; result = pEntry->initFromCDE(mZipFp); if (result != NO_ERROR) { - LOGD("initFromCDE failed\n"); + ALOGD("initFromCDE failed\n"); delete pEntry; goto bail; } @@ -325,16 +325,16 @@ status_t ZipFile::readCentralDir(void) { unsigned char checkBuf[4]; if (fread(checkBuf, 1, 4, mZipFp) != 4) { - LOGD("EOCD check read failed\n"); + ALOGD("EOCD check read failed\n"); result = INVALID_OPERATION; goto bail; } if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) { - LOGD("EOCD read check failed\n"); + ALOGD("EOCD read check failed\n"); result = UNKNOWN_ERROR; goto bail; } - LOGV("+++ EOCD read check passed\n"); + ALOGV("+++ EOCD read check passed\n"); } bail: @@ -416,7 +416,7 @@ status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size, bool failed = false; result = compressFpToFp(mZipFp, inputFp, data, size, &crc); if (result != NO_ERROR) { - LOGD("compression failed, storing\n"); + ALOGD("compression failed, storing\n"); failed = true; } else { /* @@ -427,7 +427,7 @@ status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size, long src = inputFp ? ftell(inputFp) : size; long dst = ftell(mZipFp) - startPosn; if (dst + (dst / 10) > src) { - LOGD("insufficient compression (src=%ld dst=%ld), storing\n", + ALOGD("insufficient compression (src=%ld dst=%ld), storing\n", src, dst); failed = true; } @@ -449,7 +449,7 @@ status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size, } if (result != NO_ERROR) { // don't need to truncate; happens in CDE rewrite - LOGD("failed copying data in\n"); + ALOGD("failed copying data in\n"); goto bail; } } @@ -468,14 +468,14 @@ status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size, scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen, &compressedLen, &crc); if (!scanResult || method != ZipEntry::kCompressDeflated) { - LOGD("this isn't a deflated gzip file?"); + ALOGD("this isn't a deflated gzip file?"); result = UNKNOWN_ERROR; goto bail; } result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL); if (result != NO_ERROR) { - LOGD("failed copying gzip data in\n"); + ALOGD("failed copying gzip data in\n"); goto bail; } } else { @@ -603,7 +603,7 @@ status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry, if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL) != NO_ERROR) { - LOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName); + ALOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName); result = UNKNOWN_ERROR; goto bail; } @@ -660,7 +660,7 @@ status_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32) *pCRC32 = crc32(*pCRC32, tmpBuf, count); if (fwrite(tmpBuf, 1, count, dstFp) != count) { - LOGD("fwrite %d bytes failed\n", (int) count); + ALOGD("fwrite %d bytes failed\n", (int) count); return UNKNOWN_ERROR; } } @@ -682,7 +682,7 @@ status_t ZipFile::copyDataToFp(FILE* dstFp, if (size > 0) { *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size); if (fwrite(data, 1, size, dstFp) != size) { - LOGD("fwrite %d bytes failed\n", (int) size); + ALOGD("fwrite %d bytes failed\n", (int) size); return UNKNOWN_ERROR; } } @@ -716,7 +716,7 @@ status_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length, count = fread(tmpBuf, 1, readSize, srcFp); if ((long) count != readSize) { // error or unexpected EOF - LOGD("fread %d bytes failed\n", (int) readSize); + ALOGD("fread %d bytes failed\n", (int) readSize); return UNKNOWN_ERROR; } @@ -724,7 +724,7 @@ status_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length, *pCRC32 = crc32(*pCRC32, tmpBuf, count); if (fwrite(tmpBuf, 1, count, dstFp) != count) { - LOGD("fwrite %d bytes failed\n", (int) count); + ALOGD("fwrite %d bytes failed\n", (int) count); return UNKNOWN_ERROR; } @@ -780,10 +780,10 @@ status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp, if (zerr != Z_OK) { result = UNKNOWN_ERROR; if (zerr == Z_VERSION_ERROR) { - LOGE("Installed zlib is not compatible with linked version (%s)\n", + ALOGE("Installed zlib is not compatible with linked version (%s)\n", ZLIB_VERSION); } else { - LOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr); + ALOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr); } goto bail; } @@ -799,7 +799,7 @@ status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp, /* only read if the input buffer is empty */ if (zstream.avail_in == 0 && !atEof) { - LOGV("+++ reading %d bytes\n", (int)kBufSize); + ALOGV("+++ reading %d bytes\n", (int)kBufSize); if (data) { getSize = size > kBufSize ? kBufSize : size; memcpy(inBuf, data, getSize); @@ -808,12 +808,12 @@ status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp, } else { getSize = fread(inBuf, 1, kBufSize, srcFp); if (ferror(srcFp)) { - LOGD("deflate read failed (errno=%d)\n", errno); + ALOGD("deflate read failed (errno=%d)\n", errno); goto z_bail; } } if (getSize < kBufSize) { - LOGV("+++ got %d bytes, EOF reached\n", + ALOGV("+++ got %d bytes, EOF reached\n", (int)getSize); atEof = true; } @@ -831,7 +831,7 @@ status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp, zerr = deflate(&zstream, flush); if (zerr != Z_OK && zerr != Z_STREAM_END) { - LOGD("zlib deflate call failed (zerr=%d)\n", zerr); + ALOGD("zlib deflate call failed (zerr=%d)\n", zerr); result = UNKNOWN_ERROR; goto z_bail; } @@ -840,11 +840,11 @@ status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp, if (zstream.avail_out == 0 || (zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize)) { - LOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf)); + ALOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf)); if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) != (size_t)(zstream.next_out - outBuf)) { - LOGD("write %d failed in deflate\n", + ALOGD("write %d failed in deflate\n", (int) (zstream.next_out - outBuf)); goto z_bail; } @@ -931,7 +931,7 @@ status_t ZipFile::flush(void) * of wasted space at the end of the file. Remove it now. */ if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) { - LOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno)); + ALOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno)); // not fatal } @@ -1019,7 +1019,7 @@ status_t ZipFile::crunchArchive(void) pEntry->getLFHOffset(), span); if (result != NO_ERROR) { /* this is why you use a temp file */ - LOGE("error during crunch - archive is toast\n"); + ALOGE("error during crunch - archive is toast\n"); return result; } @@ -1061,23 +1061,23 @@ status_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n) getSize = n; if (fseek(fp, (long) src, SEEK_SET) != 0) { - LOGD("filemove src seek %ld failed\n", (long) src); + ALOGD("filemove src seek %ld failed\n", (long) src); return UNKNOWN_ERROR; } if (fread(readBuf, 1, getSize, fp) != getSize) { - LOGD("filemove read %ld off=%ld failed\n", + ALOGD("filemove read %ld off=%ld failed\n", (long) getSize, (long) src); return UNKNOWN_ERROR; } if (fseek(fp, (long) dst, SEEK_SET) != 0) { - LOGD("filemove dst seek %ld failed\n", (long) dst); + ALOGD("filemove dst seek %ld failed\n", (long) dst); return UNKNOWN_ERROR; } if (fwrite(readBuf, 1, getSize, fp) != getSize) { - LOGD("filemove write %ld off=%ld failed\n", + ALOGD("filemove write %ld off=%ld failed\n", (long) getSize, (long) dst); return UNKNOWN_ERROR; } @@ -1104,7 +1104,7 @@ time_t ZipFile::getModTime(int fd) struct stat sb; if (fstat(fd, &sb) < 0) { - LOGD("HEY: fstat on fd %d failed\n", fd); + ALOGD("HEY: fstat on fd %d failed\n", fd); return (time_t) -1; } @@ -1129,7 +1129,7 @@ int ZipFile::getZipFd(void) const int fd; fd = dup(fileno(mZipFp)); if (fd < 0) { - LOGD("didn't work, errno=%d\n", errno); + ALOGD("didn't work, errno=%d\n", errno); } return fd; @@ -1224,7 +1224,7 @@ status_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len) if (len < kEOCDLen) { /* looks like ZIP file got truncated */ - LOGD(" Zip EOCD: expected >= %d bytes, found %d\n", + ALOGD(" Zip EOCD: expected >= %d bytes, found %d\n", kEOCDLen, len); return INVALID_OPERATION; } @@ -1245,7 +1245,7 @@ status_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len) if (mCommentLen > 0) { if (kEOCDLen + mCommentLen > len) { - LOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n", + ALOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n", kEOCDLen, mCommentLen, len); return UNKNOWN_ERROR; } @@ -1288,10 +1288,10 @@ status_t ZipFile::EndOfCentralDir::write(FILE* fp) */ void ZipFile::EndOfCentralDir::dump(void) const { - LOGD(" EndOfCentralDir contents:\n"); - LOGD(" diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n", + ALOGD(" EndOfCentralDir contents:\n"); + ALOGD(" diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n", mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries); - LOGD(" centDirSize=%lu centDirOff=%lu commentLen=%u\n", + ALOGD(" centDirSize=%lu centDirOff=%lu commentLen=%u\n", mCentralDirSize, mCentralDirOffset, mCommentLen); } |