Main.cpp revision 19138468caf7050d482dc15f35a344eab11bb756
1//
2// Copyright 2006 The Android Open Source Project
3//
4// Android Asset Packaging Tool main entry point.
5//
6#include "Main.h"
7#include "Bundle.h"
8
9#include <utils/Log.h>
10#include <utils/threads.h>
11#include <utils/List.h>
12#include <utils/Errors.h>
13
14#include <stdlib.h>
15#include <getopt.h>
16#include <assert.h>
17
18using namespace android;
19
20static const char* gProgName = "aapt";
21
22/*
23 * When running under Cygwin on Windows, this will convert slash-based
24 * paths into back-slash-based ones. Otherwise the ApptAssets file comparisons
25 * fail later as they use back-slash separators under Windows.
26 *
27 * This operates in-place on the path string.
28 */
29void convertPath(char *path) {
30  if (path != NULL && OS_PATH_SEPARATOR != '/') {
31    for (; *path; path++) {
32      if (*path == '/') {
33        *path = OS_PATH_SEPARATOR;
34      }
35    }
36  }
37}
38
39/*
40 * Print usage info.
41 */
42void usage(void)
43{
44    fprintf(stderr, "Android Asset Packaging Tool\n\n");
45    fprintf(stderr, "Usage:\n");
46    fprintf(stderr,
47        " %s l[ist] [-v] [-a] file.{zip,jar,apk}\n"
48        "   List contents of Zip-compatible archive.\n\n", gProgName);
49    fprintf(stderr,
50        " %s d[ump] [--values] WHAT file.{apk} [asset [asset ...]]\n"
51        "   badging          Print the label and icon for the app declared in APK.\n"
52        "   permissions      Print the permissions from the APK.\n"
53        "   resources        Print the resource table from the APK.\n"
54        "   configurations   Print the configurations in the APK.\n"
55        "   xmltree          Print the compiled xmls in the given assets.\n"
56        "   xmlstrings       Print the strings of the given compiled xml assets.\n\n", gProgName);
57    fprintf(stderr,
58        " %s p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \\\n"
59        "        [-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \\\n"
60        "        [--min-sdk-version VAL] [--target-sdk-version VAL] \\\n"
61        "        [--max-sdk-version VAL] [--app-version VAL] \\\n"
62        "        [--app-version-name TEXT]\\\n"
63        "        [-I base-package [-I base-package ...]] \\\n"
64        "        [-A asset-source-dir]  [-G class-list-file] [-P public-definitions-file] \\\n"
65        "        [-S resource-sources [-S resource-sources ...]] "
66        "        [-F apk-file] [-J R-file-dir] \\\n"
67        "        [raw-files-dir [raw-files-dir] ...]\n"
68        "\n"
69        "   Package the android resources.  It will read assets and resources that are\n"
70        "   supplied with the -M -A -S or raw-files-dir arguments.  The -J -P -F and -R\n"
71        "   options control which files are output.\n\n"
72        , gProgName);
73    fprintf(stderr,
74        " %s r[emove] [-v] file.{zip,jar,apk} file1 [file2 ...]\n"
75        "   Delete specified files from Zip-compatible archive.\n\n",
76        gProgName);
77    fprintf(stderr,
78        " %s a[dd] [-v] file.{zip,jar,apk} file1 [file2 ...]\n"
79        "   Add specified files to Zip-compatible archive.\n\n", gProgName);
80    fprintf(stderr,
81        " %s v[ersion]\n"
82        "   Print program version.\n\n", gProgName);
83    fprintf(stderr,
84        " Modifiers:\n"
85        "   -a  print Android-specific data (resources, manifest) when listing\n"
86        "   -c  specify which configurations to include.  The default is all\n"
87        "       configurations.  The value of the parameter should be a comma\n"
88        "       separated list of configuration values.  Locales should be specified\n"
89        "       as either a language or language-region pair.  Some examples:\n"
90        "            en\n"
91        "            port,en\n"
92        "            port,land,en_US\n"
93        "       If you put the special locale, zz_ZZ on the list, it will perform\n"
94        "       pseudolocalization on the default locale, modifying all of the\n"
95        "       strings so you can look for strings that missed the\n"
96        "       internationalization process.  For example:\n"
97        "            port,land,zz_ZZ\n"
98        "   -d  one or more device assets to include, separated by commas\n"
99        "   -f  force overwrite of existing files\n"
100        "   -g  specify a pixel tolerance to force images to grayscale, default 0\n"
101        "   -j  specify a jar or zip file containing classes to include\n"
102        "   -k  junk path of file(s) added\n"
103        "   -m  make package directories under location specified by -J\n"
104#if 0
105        "   -p  pseudolocalize the default configuration\n"
106#endif
107        "   -u  update existing packages (add new, replace older, remove deleted files)\n"
108        "   -v  verbose output\n"
109        "   -x  create extending (non-application) resource IDs\n"
110        "   -z  require localization of resource attributes marked with\n"
111        "       localization=\"suggested\"\n"
112        "   -A  additional directory in which to find raw asset files\n"
113        "   -G  A file to output proguard options into.\n"
114        "   -F  specify the apk file to output\n"
115        "   -I  add an existing package to base include set\n"
116        "   -J  specify where to output R.java resource constant definitions\n"
117        "   -M  specify full path to AndroidManifest.xml to include in zip\n"
118        "   -P  specify where to output public resource definitions\n"
119        "   -S  directory in which to find resources.  Multiple directories will be scanned"
120        "       and the first match found (left to right) will take precedence."
121        "   -8  Encode string resources in UTF-8.\n"
122        "   -0  specifies an additional extension for which such files will not\n"
123        "       be stored compressed in the .apk.  An empty string means to not\n"
124        "       compress any files at all.\n"
125        "   --min-sdk-version\n"
126        "       inserts android:minSdkVersion in to manifest.\n"
127        "   --target-sdk-version\n"
128        "       inserts android:targetSdkVersion in to manifest.\n"
129        "   --max-sdk-version\n"
130        "       inserts android:maxSdkVersion in to manifest.\n"
131        "   --values\n"
132        "       when used with \"dump resources\" also includes resource values.\n"
133        "   --version-code\n"
134        "       inserts android:versionCode in to manifest.\n"
135        "   --version-name\n"
136        "       inserts android:versionName in to manifest.\n");
137}
138
139/*
140 * Dispatch the command.
141 */
142int handleCommand(Bundle* bundle)
143{
144    //printf("--- command %d (verbose=%d force=%d):\n",
145    //    bundle->getCommand(), bundle->getVerbose(), bundle->getForce());
146    //for (int i = 0; i < bundle->getFileSpecCount(); i++)
147    //    printf("  %d: '%s'\n", i, bundle->getFileSpecEntry(i));
148
149    switch (bundle->getCommand()) {
150    case kCommandVersion:   return doVersion(bundle);
151    case kCommandList:      return doList(bundle);
152    case kCommandDump:      return doDump(bundle);
153    case kCommandAdd:       return doAdd(bundle);
154    case kCommandRemove:    return doRemove(bundle);
155    case kCommandPackage:   return doPackage(bundle);
156    default:
157        fprintf(stderr, "%s: requested command not yet supported\n", gProgName);
158        return 1;
159    }
160}
161
162/*
163 * Parse args.
164 */
165int main(int argc, char* const argv[])
166{
167    char *prog = argv[0];
168    Bundle bundle;
169    bool wantUsage = false;
170    int result = 1;    // pessimistically assume an error.
171    int tolerance = 0;
172
173    /* default to compression */
174    bundle.setCompressionMethod(ZipEntry::kCompressDeflated);
175
176    if (argc < 2) {
177        wantUsage = true;
178        goto bail;
179    }
180
181    if (argv[1][0] == 'v')
182        bundle.setCommand(kCommandVersion);
183    else if (argv[1][0] == 'd')
184        bundle.setCommand(kCommandDump);
185    else if (argv[1][0] == 'l')
186        bundle.setCommand(kCommandList);
187    else if (argv[1][0] == 'a')
188        bundle.setCommand(kCommandAdd);
189    else if (argv[1][0] == 'r')
190        bundle.setCommand(kCommandRemove);
191    else if (argv[1][0] == 'p')
192        bundle.setCommand(kCommandPackage);
193    else {
194        fprintf(stderr, "ERROR: Unknown command '%s'\n", argv[1]);
195        wantUsage = true;
196        goto bail;
197    }
198    argc -= 2;
199    argv += 2;
200
201    /*
202     * Pull out flags.  We support "-fv" and "-f -v".
203     */
204    while (argc && argv[0][0] == '-') {
205        /* flag(s) found */
206        const char* cp = argv[0] +1;
207
208        while (*cp != '\0') {
209            switch (*cp) {
210            case 'v':
211                bundle.setVerbose(true);
212                break;
213            case 'a':
214                bundle.setAndroidList(true);
215                break;
216            case 'c':
217                argc--;
218                argv++;
219                if (!argc) {
220                    fprintf(stderr, "ERROR: No argument supplied for '-c' option\n");
221                    wantUsage = true;
222                    goto bail;
223                }
224                bundle.addConfigurations(argv[0]);
225                break;
226            case 'f':
227                bundle.setForce(true);
228                break;
229            case 'g':
230                argc--;
231                argv++;
232                if (!argc) {
233                    fprintf(stderr, "ERROR: No argument supplied for '-g' option\n");
234                    wantUsage = true;
235                    goto bail;
236                }
237                tolerance = atoi(argv[0]);
238                bundle.setGrayscaleTolerance(tolerance);
239                printf("%s: Images with deviation <= %d will be forced to grayscale.\n", prog, tolerance);
240                break;
241            case 'k':
242                bundle.setJunkPath(true);
243                break;
244            case 'm':
245                bundle.setMakePackageDirs(true);
246                break;
247#if 0
248            case 'p':
249                bundle.setPseudolocalize(true);
250                break;
251#endif
252            case 'u':
253                bundle.setUpdate(true);
254                break;
255            case 'x':
256                bundle.setExtending(true);
257                break;
258            case 'z':
259                bundle.setRequireLocalization(true);
260                break;
261            case 'j':
262                argc--;
263                argv++;
264                if (!argc) {
265                    fprintf(stderr, "ERROR: No argument supplied for '-j' option\n");
266                    wantUsage = true;
267                    goto bail;
268                }
269                convertPath(argv[0]);
270                bundle.addJarFile(argv[0]);
271                break;
272            case 'A':
273                argc--;
274                argv++;
275                if (!argc) {
276                    fprintf(stderr, "ERROR: No argument supplied for '-A' option\n");
277                    wantUsage = true;
278                    goto bail;
279                }
280                convertPath(argv[0]);
281                bundle.setAssetSourceDir(argv[0]);
282                break;
283            case 'G':
284                argc--;
285                argv++;
286                if (!argc) {
287                    fprintf(stderr, "ERROR: No argument supplied for '-G' option\n");
288                    wantUsage = true;
289                    goto bail;
290                }
291                convertPath(argv[0]);
292                bundle.setProguardFile(argv[0]);
293                break;
294            case 'I':
295                argc--;
296                argv++;
297                if (!argc) {
298                    fprintf(stderr, "ERROR: No argument supplied for '-I' option\n");
299                    wantUsage = true;
300                    goto bail;
301                }
302                convertPath(argv[0]);
303                bundle.addPackageInclude(argv[0]);
304                break;
305            case 'F':
306                argc--;
307                argv++;
308                if (!argc) {
309                    fprintf(stderr, "ERROR: No argument supplied for '-F' option\n");
310                    wantUsage = true;
311                    goto bail;
312                }
313                convertPath(argv[0]);
314                bundle.setOutputAPKFile(argv[0]);
315                break;
316            case 'J':
317                argc--;
318                argv++;
319                if (!argc) {
320                    fprintf(stderr, "ERROR: No argument supplied for '-J' option\n");
321                    wantUsage = true;
322                    goto bail;
323                }
324                convertPath(argv[0]);
325                bundle.setRClassDir(argv[0]);
326                break;
327            case 'M':
328                argc--;
329                argv++;
330                if (!argc) {
331                    fprintf(stderr, "ERROR: No argument supplied for '-M' option\n");
332                    wantUsage = true;
333                    goto bail;
334                }
335                convertPath(argv[0]);
336                bundle.setAndroidManifestFile(argv[0]);
337                break;
338            case 'P':
339                argc--;
340                argv++;
341                if (!argc) {
342                    fprintf(stderr, "ERROR: No argument supplied for '-P' option\n");
343                    wantUsage = true;
344                    goto bail;
345                }
346                convertPath(argv[0]);
347                bundle.setPublicOutputFile(argv[0]);
348                break;
349            case 'S':
350                argc--;
351                argv++;
352                if (!argc) {
353                    fprintf(stderr, "ERROR: No argument supplied for '-S' option\n");
354                    wantUsage = true;
355                    goto bail;
356                }
357                convertPath(argv[0]);
358                bundle.addResourceSourceDir(argv[0]);
359                break;
360            case '0':
361                argc--;
362                argv++;
363                if (!argc) {
364                    fprintf(stderr, "ERROR: No argument supplied for '-e' option\n");
365                    wantUsage = true;
366                    goto bail;
367                }
368                if (argv[0][0] != 0) {
369                    bundle.addNoCompressExtension(argv[0]);
370                } else {
371                    bundle.setCompressionMethod(ZipEntry::kCompressStored);
372                }
373                break;
374            case '8':
375                bundle.setUTF8(true);
376                break;
377            case '-':
378                if (strcmp(cp, "-min-sdk-version") == 0) {
379                    argc--;
380                    argv++;
381                    if (!argc) {
382                        fprintf(stderr, "ERROR: No argument supplied for '--min-sdk-version' option\n");
383                        wantUsage = true;
384                        goto bail;
385                    }
386                    bundle.setMinSdkVersion(argv[0]);
387                } else if (strcmp(cp, "-target-sdk-version") == 0) {
388                    argc--;
389                    argv++;
390                    if (!argc) {
391                        fprintf(stderr, "ERROR: No argument supplied for '--target-sdk-version' option\n");
392                        wantUsage = true;
393                        goto bail;
394                    }
395                    bundle.setTargetSdkVersion(argv[0]);
396                } else if (strcmp(cp, "-max-sdk-version") == 0) {
397                    argc--;
398                    argv++;
399                    if (!argc) {
400                        fprintf(stderr, "ERROR: No argument supplied for '--max-sdk-version' option\n");
401                        wantUsage = true;
402                        goto bail;
403                    }
404                    bundle.setMaxSdkVersion(argv[0]);
405                } else if (strcmp(cp, "-version-code") == 0) {
406                    argc--;
407                    argv++;
408                    if (!argc) {
409                        fprintf(stderr, "ERROR: No argument supplied for '--version-code' option\n");
410                        wantUsage = true;
411                        goto bail;
412                    }
413                    bundle.setVersionCode(argv[0]);
414                } else if (strcmp(cp, "-version-name") == 0) {
415                    argc--;
416                    argv++;
417                    if (!argc) {
418                        fprintf(stderr, "ERROR: No argument supplied for '--version-name' option\n");
419                        wantUsage = true;
420                        goto bail;
421                    }
422                    bundle.setVersionName(argv[0]);
423                } else if (strcmp(cp, "-values") == 0) {
424                    bundle.setValues(true);
425                } else {
426                    fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp);
427                    wantUsage = true;
428                    goto bail;
429                }
430                cp += strlen(cp) - 1;
431                break;
432            default:
433                fprintf(stderr, "ERROR: Unknown flag '-%c'\n", *cp);
434                wantUsage = true;
435                goto bail;
436            }
437
438            cp++;
439        }
440        argc--;
441        argv++;
442    }
443
444    /*
445     * We're past the flags.  The rest all goes straight in.
446     */
447    bundle.setFileSpec(argv, argc);
448
449    result = handleCommand(&bundle);
450
451bail:
452    if (wantUsage) {
453        usage();
454        result = 2;
455    }
456
457    //printf("--> returning %d\n", result);
458    return result;
459}
460