1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// 2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// Copyright 2006 The Android Open Source Project 3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// 4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// Package assets into Zip files. 5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// 6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "Main.h" 7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "AaptAssets.h" 8fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski#include "OutputSet.h" 9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "ResourceTable.h" 10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "ResourceFilter.h" 11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <androidfw/misc.h> 13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/Log.h> 15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/threads.h> 16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/List.h> 17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/Errors.h> 18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/misc.h> 19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <sys/types.h> 21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <dirent.h> 22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <ctype.h> 23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <errno.h> 24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiusing namespace android; 26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const char* kExcludeExtension = ".EXCLUDE"; 28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* these formats are already compressed, or don't compress well */ 30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const char* kNoCompressExt[] = { 31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ".jpg", ".jpeg", ".png", ".gif", 32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ".wav", ".mp2", ".mp3", ".ogg", ".aac", 33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet", 34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ".rtttl", ".imy", ".xmf", ".mp4", ".m4a", 35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2", 36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ".amr", ".awb", ".wma", ".wmv" 37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}; 38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* fwd decls, so I can write this downward */ 40fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinskissize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& outputSet); 41fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinskibool processFile(Bundle* bundle, ZipFile* zip, String8 storageName, const sp<const AaptFile>& file); 42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool okayToCompress(Bundle* bundle, const String8& pathName); 43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskissize_t processJarFiles(Bundle* bundle, ZipFile* zip); 44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* 46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * The directory hierarchy looks like this: 47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * "outputDir" and "assetRoot" are existing directories. 48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * On success, "bundle->numPackages" will be the number of Zip packages 50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * we created. 51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 52fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinskistatus_t writeAPK(Bundle* bundle, const String8& outputFile, const sp<OutputSet>& outputSet) 53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{ 54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski #if BENCHMARK 55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(stdout, "BENCHMARK: Starting APK Bundling \n"); 56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski long startAPKTime = clock(); 57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski #endif /* BENCHMARK */ 58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski status_t result = NO_ERROR; 60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ZipFile* zip = NULL; 61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int count; 62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski //bundle->setPackageCount(0); 64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /* 66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Prep the Zip archive. 67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * If the file already exists, fail unless "update" or "force" is set. 69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * If "update" is set, update the contents of the existing archive. 70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Else, if "force" is set, remove the existing archive. 71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski FileType fileType = getFileType(outputFile.string()); 73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (fileType == kFileTypeNonexistent) { 74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // okay, create it below 75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else if (fileType == kFileTypeRegular) { 76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bundle->getUpdate()) { 77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // okay, open it below 78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else if (bundle->getForce()) { 79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (unlink(outputFile.string()) != 0) { 80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(stderr, "ERROR: unable to remove '%s': %s\n", outputFile.string(), 81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski strerror(errno)); 82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski goto bail; 83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else { 85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(stderr, "ERROR: '%s' exists (use '-f' to force overwrite)\n", 86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski outputFile.string()); 87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski goto bail; 88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else { 90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(stderr, "ERROR: '%s' exists and is not a regular file\n", outputFile.string()); 91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski goto bail; 92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bundle->getVerbose()) { 95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski printf("%s '%s'\n", (fileType == kFileTypeNonexistent) ? "Creating" : "Opening", 96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski outputFile.string()); 97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski status_t status; 100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski zip = new ZipFile; 101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski status = zip->open(outputFile.string(), ZipFile::kOpenReadWrite | ZipFile::kOpenCreate); 102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (status != NO_ERROR) { 103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(stderr, "ERROR: unable to open '%s' as Zip file for writing\n", 104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski outputFile.string()); 105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski goto bail; 106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bundle->getVerbose()) { 109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski printf("Writing all files...\n"); 110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 112fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski count = processAssets(bundle, zip, outputSet); 113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (count < 0) { 114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(stderr, "ERROR: unable to process assets while packaging '%s'\n", 115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski outputFile.string()); 116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski result = count; 117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski goto bail; 118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bundle->getVerbose()) { 121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski printf("Generated %d file%s\n", count, (count==1) ? "" : "s"); 122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski count = processJarFiles(bundle, zip); 125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (count < 0) { 126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(stderr, "ERROR: unable to process jar files while packaging '%s'\n", 127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski outputFile.string()); 128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski result = count; 129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski goto bail; 130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bundle->getVerbose()) 133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski printf("Included %d file%s from jar/zip files.\n", count, (count==1) ? "" : "s"); 134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski result = NO_ERROR; 136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /* 138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Check for cruft. We set the "marked" flag on all entries we created 139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * or decided not to update. If the entry isn't already slated for 140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * deletion, remove it now. 141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski { 143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bundle->getVerbose()) 144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski printf("Checking for deleted files\n"); 145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int i, removed = 0; 146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for (i = 0; i < zip->getNumEntries(); i++) { 147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ZipEntry* entry = zip->getEntryByIndex(i); 148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (!entry->getMarked() && entry->getDeleted()) { 150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bundle->getVerbose()) { 151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski printf(" (removing crufty '%s')\n", 152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski entry->getFileName()); 153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski zip->remove(entry); 155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski removed++; 156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bundle->getVerbose() && removed > 0) 159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski printf("Removed %d file%s\n", removed, (removed==1) ? "" : "s"); 160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /* tell Zip lib to process deletions and other pending changes */ 163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski result = zip->flush(); 164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (result != NO_ERROR) { 165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(stderr, "ERROR: Zip flush failed, archive may be hosed\n"); 166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski goto bail; 167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /* anything here? */ 170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (zip->getNumEntries() == 0) { 171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bundle->getVerbose()) { 172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski printf("Archive is empty -- removing %s\n", outputFile.getPathLeaf().string()); 173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski delete zip; // close the file so we can remove it in Win32 175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski zip = NULL; 176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (unlink(outputFile.string()) != 0) { 177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.string()); 178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // If we've been asked to generate a dependency file for the .ap_ package, 182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // do so here 183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bundle->getGenDependencies()) { 184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // The dependency file gets output to the same directory 185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // as the specified output file with an additional .d extension. 186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // e.g. bin/resources.ap_.d 187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski String8 dependencyFile = outputFile; 188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski dependencyFile.append(".d"); 189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski FILE* fp = fopen(dependencyFile.string(), "a"); 191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // Add this file to the dependency file 192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(fp, "%s \\\n", outputFile.string()); 193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fclose(fp); 194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski assert(result == NO_ERROR); 197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail: 199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski delete zip; // must close before remove in Win32 200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (result != NO_ERROR) { 201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bundle->getVerbose()) { 202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski printf("Removing %s due to earlier failures\n", outputFile.string()); 203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (unlink(outputFile.string()) != 0) { 205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.string()); 206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (result == NO_ERROR && bundle->getVerbose()) 210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski printf("Done!\n"); 211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski #if BENCHMARK 213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(stdout, "BENCHMARK: End APK Bundling. Time Elapsed: %f ms \n",(clock() - startAPKTime)/1000.0); 214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski #endif /* BENCHMARK */ 215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return result; 216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski} 217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 218fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinskissize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& outputSet) 219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{ 220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ssize_t count = 0; 221fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski const std::set<OutputEntry>& entries = outputSet->getEntries(); 222fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski std::set<OutputEntry>::const_iterator iter = entries.begin(); 223fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski for (; iter != entries.end(); iter++) { 224fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski const OutputEntry& entry = *iter; 225fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski if (entry.getFile() == NULL) { 226fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski fprintf(stderr, "warning: null file being processed.\n"); 227fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski } else { 228fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski String8 storagePath(entry.getPath()); 229fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski storagePath.convertToResPath(); 230fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski if (!processFile(bundle, zip, storagePath, entry.getFile())) { 231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return UNKNOWN_ERROR; 232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski count++; 234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return count; 237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski} 238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* 240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Process a regular file, adding it to the archive if appropriate. 241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * If we're in "update" mode, and the file already exists in the archive, 243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * delete the existing entry before adding the new one. 244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool processFile(Bundle* bundle, ZipFile* zip, 246fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski String8 storageName, const sp<const AaptFile>& file) 247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{ 248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski const bool hasData = file->hasData(); 249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ZipEntry* entry; 251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski bool fromGzip = false; 252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski status_t result; 253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /* 255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * See if the filename ends in ".EXCLUDE". We can't use 256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * String8::getPathExtension() because the length of what it considers 257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * to be an extension is capped. 258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * The Asset Manager doesn't check for ".EXCLUDE" in Zip archives, 260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * so there's no value in adding them (and it makes life easier on 261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * the AssetManager lib if we don't). 262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * NOTE: this restriction has been removed. If you're in this code, you 264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * should clean this up, but I'm in here getting rid of Path Name, and I 265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * don't want to make other potentially breaking changes --joeo 266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int fileNameLen = storageName.length(); 268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int excludeExtensionLen = strlen(kExcludeExtension); 269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (fileNameLen > excludeExtensionLen 270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski && (0 == strcmp(storageName.string() + (fileNameLen - excludeExtensionLen), 271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski kExcludeExtension))) { 272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(stderr, "warning: '%s' not added to Zip\n", storageName.string()); 273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return true; 274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (strcasecmp(storageName.getPathExtension().string(), ".gz") == 0) { 277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fromGzip = true; 278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski storageName = storageName.getBasePath(); 279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bundle->getUpdate()) { 282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski entry = zip->getEntryByName(storageName.string()); 283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (entry != NULL) { 284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /* file already exists in archive; there can be only one */ 285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (entry->getMarked()) { 286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(stderr, 287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski "ERROR: '%s' exists twice (check for with & w/o '.gz'?)\n", 288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski file->getPrintableSource().string()); 289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return false; 290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (!hasData) { 292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski const String8& srcName = file->getSourceFile(); 293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski time_t fileModWhen; 294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fileModWhen = getFileModDate(srcName.string()); 295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (fileModWhen == (time_t) -1) { // file existence tested earlier, 296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return false; // not expecting an error here 297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (fileModWhen > entry->getModWhen()) { 300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // mark as deleted so add() will succeed 301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bundle->getVerbose()) { 302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski printf(" (removing old '%s')\n", storageName.string()); 303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski zip->remove(entry); 306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else { 307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // version in archive is newer 308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bundle->getVerbose()) { 309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski printf(" (not updating '%s')\n", storageName.string()); 310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski entry->setMarked(true); 312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return true; 313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else { 315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // Generated files are always replaced. 316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski zip->remove(entry); 317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski //android_setMinPriority(NULL, ANDROID_LOG_VERBOSE); 322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (fromGzip) { 324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski result = zip->addGzip(file->getSourceFile().string(), storageName.string(), &entry); 325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else if (!hasData) { 326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /* don't compress certain files, e.g. PNGs */ 327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int compressionMethod = bundle->getCompressionMethod(); 328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (!okayToCompress(bundle, storageName)) { 329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski compressionMethod = ZipEntry::kCompressStored; 330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski result = zip->add(file->getSourceFile().string(), storageName.string(), compressionMethod, 332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski &entry); 333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else { 334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski result = zip->add(file->getData(), file->getSize(), storageName.string(), 335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski file->getCompressionMethod(), &entry); 336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (result == NO_ERROR) { 338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (bundle->getVerbose()) { 339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski printf(" '%s'%s", storageName.string(), fromGzip ? " (from .gz)" : ""); 340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (entry->getCompressionMethod() == ZipEntry::kCompressStored) { 341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski printf(" (not compressed)\n"); 342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else { 343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski printf(" (compressed %d%%)\n", calcPercent(entry->getUncompressedLen(), 344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski entry->getCompressedLen())); 345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski entry->setMarked(true); 348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else { 349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (result == ALREADY_EXISTS) { 350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(stderr, " Unable to add '%s': file already in archive (try '-u'?)\n", 351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski file->getPrintableSource().string()); 352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else { 353fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski fprintf(stderr, " Unable to add '%s': Zip add failed (%d)\n", 354fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski file->getPrintableSource().string(), result); 355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return false; 357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return true; 360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski} 361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* 363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Determine whether or not we want to try to compress this file based 364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * on the file extension. 365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool okayToCompress(Bundle* bundle, const String8& pathName) 367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{ 368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski String8 ext = pathName.getPathExtension(); 369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int i; 370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (ext.length() == 0) 372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return true; 373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for (i = 0; i < NELEM(kNoCompressExt); i++) { 375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (strcasecmp(ext.string(), kNoCompressExt[i]) == 0) 376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return false; 377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski const android::Vector<const char*>& others(bundle->getNoCompressExtensions()); 380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for (i = 0; i < (int)others.size(); i++) { 381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski const char* str = others[i]; 382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int pos = pathName.length() - strlen(str); 383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (pos < 0) { 384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski continue; 385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski const char* path = pathName.string(); 387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (strcasecmp(path + pos, str) == 0) { 388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return false; 389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return true; 393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski} 394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool endsWith(const char* haystack, const char* needle) 396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{ 397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski size_t a = strlen(haystack); 398282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski size_t b = strlen(needle); 399282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (a < b) return false; 400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return strcasecmp(haystack+(a-b), needle) == 0; 401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski} 402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskissize_t processJarFile(ZipFile* jar, ZipFile* out) 404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{ 405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski status_t err; 406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski size_t N = jar->getNumEntries(); 407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski size_t count = 0; 408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for (size_t i=0; i<N; i++) { 409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ZipEntry* entry = jar->getEntryByIndex(i); 410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski const char* storageName = entry->getFileName(); 411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (endsWith(storageName, ".class")) { 412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int compressionMethod = entry->getCompressionMethod(); 413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski size_t size = entry->getUncompressedLen(); 414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski const void* data = jar->uncompress(entry); 415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (data == NULL) { 416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(stderr, "ERROR: unable to uncompress entry '%s'\n", 417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski storageName); 418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return -1; 419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski out->add(data, size, storageName, compressionMethod, NULL); 421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski free((void*)data); 422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski count++; 424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return count; 426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski} 427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskissize_t processJarFiles(Bundle* bundle, ZipFile* zip) 429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{ 430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski status_t err; 431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ssize_t count = 0; 432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski const android::Vector<const char*>& jars = bundle->getJarFiles(); 433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski size_t N = jars.size(); 435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for (size_t i=0; i<N; i++) { 436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ZipFile jar; 437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski err = jar.open(jars[i], ZipFile::kOpenReadOnly); 438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (err != 0) { 439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(stderr, "ERROR: unable to open '%s' as a zip file: %d\n", 440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski jars[i], err); 441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return err; 442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski err += processJarFile(&jar, zip); 444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (err < 0) { 445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fprintf(stderr, "ERROR: unable to process '%s'\n", jars[i]); 446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return err; 447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski count += err; 449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return count; 452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski} 453