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