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