OSDN Git Service

am fc133135: am 29d225c9: Set a default value for TARGET_BUILD_DENSITY
[android-x86/build.git] / tools / zipalign / ZipAlign.cpp
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * Zip alignment tool
19  */
20 #include "ZipFile.h"
21
22 #include <stdlib.h>
23 #include <stdio.h>
24
25 using namespace android;
26
27 /*
28  * Show program usage.
29  */
30 void usage(void)
31 {
32     fprintf(stderr, "Zip alignment utility\n");
33     fprintf(stderr, "Copyright (C) 2009 The Android Open Source Project\n\n");
34     fprintf(stderr,
35         "Usage: zipalign [-f] [-v] [-z] <align> infile.zip outfile.zip\n"
36         "       zipalign -c [-v] <align> infile.zip\n\n" );
37     fprintf(stderr,
38         "  <align>: alignment in bytes, e.g. '4' provides 32-bit alignment\n");
39     fprintf(stderr, "  -c: check alignment only (does not modify file)\n");
40     fprintf(stderr, "  -f: overwrite existing outfile.zip\n");
41     fprintf(stderr, "  -v: verbose output\n");
42     fprintf(stderr, "  -z: recompress using Zopfli\n");
43 }
44
45 /*
46  * Copy all entries from "pZin" to "pZout", aligning as needed.
47  */
48 static int copyAndAlign(ZipFile* pZin, ZipFile* pZout, int alignment, bool zopfli)
49 {
50     int numEntries = pZin->getNumEntries();
51     ZipEntry* pEntry;
52     int bias = 0;
53     status_t status;
54
55     for (int i = 0; i < numEntries; i++) {
56         ZipEntry* pNewEntry;
57         int padding = 0;
58
59         pEntry = pZin->getEntryByIndex(i);
60         if (pEntry == NULL) {
61             fprintf(stderr, "ERROR: unable to retrieve entry %d\n", i);
62             return 1;
63         }
64
65         if (pEntry->isCompressed()) {
66             /* copy the entry without padding */
67             //printf("--- %s: orig at %ld len=%ld (compressed)\n",
68             //    pEntry->getFileName(), (long) pEntry->getFileOffset(),
69             //    (long) pEntry->getUncompressedLen());
70
71             if (zopfli) {
72                 status = pZout->addRecompress(pZin, pEntry, &pNewEntry);
73                 bias += pNewEntry->getCompressedLen() - pEntry->getCompressedLen();
74             } else {
75                 status = pZout->add(pZin, pEntry, padding, &pNewEntry);
76             }
77         } else {
78             /*
79              * Copy the entry, adjusting as required.  We assume that the
80              * file position in the new file will be equal to the file
81              * position in the original.
82              */
83             long newOffset = pEntry->getFileOffset() + bias;
84             padding = (alignment - (newOffset % alignment)) % alignment;
85
86             //printf("--- %s: orig at %ld(+%d) len=%ld, adding pad=%d\n",
87             //    pEntry->getFileName(), (long) pEntry->getFileOffset(),
88             //    bias, (long) pEntry->getUncompressedLen(), padding);
89             status = pZout->add(pZin, pEntry, padding, &pNewEntry);
90         }
91
92         if (status != NO_ERROR)
93             return 1;
94         bias += padding;
95         //printf(" added '%s' at %ld (pad=%d)\n",
96         //    pNewEntry->getFileName(), (long) pNewEntry->getFileOffset(),
97         //    padding);
98     }
99
100     return 0;
101 }
102
103 /*
104  * Process a file.  We open the input and output files, failing if the
105  * output file exists and "force" wasn't specified.
106  */
107 static int process(const char* inFileName, const char* outFileName,
108     int alignment, bool force, bool zopfli)
109 {
110     ZipFile zin, zout;
111
112     //printf("PROCESS: align=%d in='%s' out='%s' force=%d\n",
113     //    alignment, inFileName, outFileName, force);
114
115     /* this mode isn't supported -- do a trivial check */
116     if (strcmp(inFileName, outFileName) == 0) {
117         fprintf(stderr, "Input and output can't be same file\n");
118         return 1;
119     }
120
121     /* don't overwrite existing unless given permission */
122     if (!force && access(outFileName, F_OK) == 0) {
123         fprintf(stderr, "Output file '%s' exists\n", outFileName);
124         return 1;
125     }
126
127     if (zin.open(inFileName, ZipFile::kOpenReadOnly) != NO_ERROR) {
128         fprintf(stderr, "Unable to open '%s' as zip archive\n", inFileName);
129         return 1;
130     }
131     if (zout.open(outFileName,
132             ZipFile::kOpenReadWrite|ZipFile::kOpenCreate|ZipFile::kOpenTruncate)
133         != NO_ERROR)
134     {
135         fprintf(stderr, "Unable to open '%s' as zip archive\n", outFileName);
136         return 1;
137     }
138
139     int result = copyAndAlign(&zin, &zout, alignment, zopfli);
140     if (result != 0) {
141         printf("zipalign: failed rewriting '%s' to '%s'\n",
142             inFileName, outFileName);
143     }
144     return result;
145 }
146
147 /*
148  * Verify the alignment of a zip archive.
149  */
150 static int verify(const char* fileName, int alignment, bool verbose)
151 {
152     ZipFile zipFile;
153     bool foundBad = false;
154
155     if (verbose)
156         printf("Verifying alignment of %s (%d)...\n", fileName, alignment);
157
158     if (zipFile.open(fileName, ZipFile::kOpenReadOnly) != NO_ERROR) {
159         fprintf(stderr, "Unable to open '%s' for verification\n", fileName);
160         return 1;
161     }
162
163     int numEntries = zipFile.getNumEntries();
164     ZipEntry* pEntry;
165
166     for (int i = 0; i < numEntries; i++) {
167         pEntry = zipFile.getEntryByIndex(i);
168         if (pEntry->isCompressed()) {
169             if (verbose) {
170                 printf("%8ld %s (OK - compressed)\n",
171                     (long) pEntry->getFileOffset(), pEntry->getFileName());
172             }
173         } else {
174             long offset = pEntry->getFileOffset();
175             if ((offset % alignment) != 0) {
176                 if (verbose) {
177                     printf("%8ld %s (BAD - %ld)\n",
178                         (long) offset, pEntry->getFileName(),
179                         offset % alignment);
180                 }
181                 foundBad = true;
182             } else {
183                 if (verbose) {
184                     printf("%8ld %s (OK)\n",
185                         (long) offset, pEntry->getFileName());
186                 }
187             }
188         }
189     }
190
191     if (verbose)
192         printf("Verification %s\n", foundBad ? "FAILED" : "succesful");
193
194     return foundBad ? 1 : 0;
195 }
196
197 /*
198  * Parse args.
199  */
200 int main(int argc, char* const argv[])
201 {
202     bool wantUsage = false;
203     bool check = false;
204     bool force = false;
205     bool verbose = false;
206     bool zopfli = false;
207     int result = 1;
208     int alignment;
209     char* endp;
210
211     if (argc < 4) {
212         wantUsage = true;
213         goto bail;
214     }
215
216     argc--;
217     argv++;
218
219     while (argc && argv[0][0] == '-') {
220         const char* cp = argv[0] +1;
221
222         while (*cp != '\0') {
223             switch (*cp) {
224             case 'c':
225                 check = true;
226                 break;
227             case 'f':
228                 force = true;
229                 break;
230             case 'v':
231                 verbose = true;
232                 break;
233             case 'z':
234                 zopfli = true;
235                 break;
236             default:
237                 fprintf(stderr, "ERROR: unknown flag -%c\n", *cp);
238                 wantUsage = true;
239                 goto bail;
240             }
241
242             cp++;
243         }
244
245         argc--;
246         argv++;
247     }
248
249     if (!((check && argc == 2) || (!check && argc == 3))) {
250         wantUsage = true;
251         goto bail;
252     }
253
254     alignment = strtol(argv[0], &endp, 10);
255     if (*endp != '\0' || alignment <= 0) {
256         fprintf(stderr, "Invalid value for alignment: %s\n", argv[0]);
257         wantUsage = true;
258         goto bail;
259     }
260
261     if (check) {
262         /* check existing archive for correct alignment */
263         result = verify(argv[1], alignment, verbose);
264     } else {
265         /* create the new archive */
266         result = process(argv[1], argv[2], alignment, force, zopfli);
267
268         /* trust, but verify */
269         if (result == 0)
270             result = verify(argv[2], alignment, verbose);
271     }
272
273 bail:
274     if (wantUsage) {
275         usage();
276         result = 2;
277     }
278
279     return result;
280 }