platform_build/tools/zipalign/ZipAlign.cpp
Jingwen Owen Ou 303213915d Fix reporting wrong error message for zipalign output file
The problem is due to using variable inFileName instead of outFileName for printing out error message for output file.

Change-Id: Ie53a21b077fea5e7cd106fe6884cea159d2629a2
2012-08-17 16:21:11 -07:00

269 lines
7.5 KiB
C++

/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Zip alignment tool
*/
#include "ZipFile.h"
#include <stdlib.h>
#include <stdio.h>
using namespace android;
/*
* Show program usage.
*/
void usage(void)
{
fprintf(stderr, "Zip alignment utility\n");
fprintf(stderr, "Copyright (C) 2009 The Android Open Source Project\n\n");
fprintf(stderr,
"Usage: zipalign [-f] [-v] <align> infile.zip outfile.zip\n"
" zipalign -c [-v] <align> infile.zip\n\n" );
fprintf(stderr,
" <align>: alignment in bytes, e.g. '4' provides 32-bit alignment\n");
fprintf(stderr, " -c: check alignment only (does not modify file)\n");
fprintf(stderr, " -f: overwrite existing outfile.zip\n");
fprintf(stderr, " -v: verbose output\n");
}
/*
* Copy all entries from "pZin" to "pZout", aligning as needed.
*/
static int copyAndAlign(ZipFile* pZin, ZipFile* pZout, int alignment)
{
int numEntries = pZin->getNumEntries();
ZipEntry* pEntry;
int bias = 0;
status_t status;
for (int i = 0; i < numEntries; i++) {
ZipEntry* pNewEntry;
int padding = 0;
pEntry = pZin->getEntryByIndex(i);
if (pEntry == NULL) {
fprintf(stderr, "ERROR: unable to retrieve entry %d\n", i);
return 1;
}
if (pEntry->isCompressed()) {
/* copy the entry without padding */
//printf("--- %s: orig at %ld len=%ld (compressed)\n",
// pEntry->getFileName(), (long) pEntry->getFileOffset(),
// (long) pEntry->getUncompressedLen());
} else {
/*
* Copy the entry, adjusting as required. We assume that the
* file position in the new file will be equal to the file
* position in the original.
*/
long newOffset = pEntry->getFileOffset() + bias;
padding = (alignment - (newOffset % alignment)) % alignment;
//printf("--- %s: orig at %ld(+%d) len=%ld, adding pad=%d\n",
// pEntry->getFileName(), (long) pEntry->getFileOffset(),
// bias, (long) pEntry->getUncompressedLen(), padding);
}
status = pZout->add(pZin, pEntry, padding, &pNewEntry);
if (status != NO_ERROR)
return 1;
bias += padding;
//printf(" added '%s' at %ld (pad=%d)\n",
// pNewEntry->getFileName(), (long) pNewEntry->getFileOffset(),
// padding);
}
return 0;
}
/*
* Process a file. We open the input and output files, failing if the
* output file exists and "force" wasn't specified.
*/
static int process(const char* inFileName, const char* outFileName,
int alignment, bool force)
{
ZipFile zin, zout;
//printf("PROCESS: align=%d in='%s' out='%s' force=%d\n",
// alignment, inFileName, outFileName, force);
/* this mode isn't supported -- do a trivial check */
if (strcmp(inFileName, outFileName) == 0) {
fprintf(stderr, "Input and output can't be same file\n");
return 1;
}
/* don't overwrite existing unless given permission */
if (!force && access(outFileName, F_OK) == 0) {
fprintf(stderr, "Output file '%s' exists\n", outFileName);
return 1;
}
if (zin.open(inFileName, ZipFile::kOpenReadOnly) != NO_ERROR) {
fprintf(stderr, "Unable to open '%s' as zip archive\n", inFileName);
return 1;
}
if (zout.open(outFileName,
ZipFile::kOpenReadWrite|ZipFile::kOpenCreate|ZipFile::kOpenTruncate)
!= NO_ERROR)
{
fprintf(stderr, "Unable to open '%s' as zip archive\n", outFileName);
return 1;
}
int result = copyAndAlign(&zin, &zout, alignment);
if (result != 0) {
printf("zipalign: failed rewriting '%s' to '%s'\n",
inFileName, outFileName);
}
return result;
}
/*
* Verify the alignment of a zip archive.
*/
static int verify(const char* fileName, int alignment, bool verbose)
{
ZipFile zipFile;
bool foundBad = false;
if (verbose)
printf("Verifying alignment of %s (%d)...\n", fileName, alignment);
if (zipFile.open(fileName, ZipFile::kOpenReadOnly) != NO_ERROR) {
fprintf(stderr, "Unable to open '%s' for verification\n", fileName);
return 1;
}
int numEntries = zipFile.getNumEntries();
ZipEntry* pEntry;
for (int i = 0; i < numEntries; i++) {
pEntry = zipFile.getEntryByIndex(i);
if (pEntry->isCompressed()) {
if (verbose) {
printf("%8ld %s (OK - compressed)\n",
(long) pEntry->getFileOffset(), pEntry->getFileName());
}
} else {
long offset = pEntry->getFileOffset();
if ((offset % alignment) != 0) {
if (verbose) {
printf("%8ld %s (BAD - %ld)\n",
(long) offset, pEntry->getFileName(),
offset % alignment);
}
foundBad = true;
} else {
if (verbose) {
printf("%8ld %s (OK)\n",
(long) offset, pEntry->getFileName());
}
}
}
}
if (verbose)
printf("Verification %s\n", foundBad ? "FAILED" : "succesful");
return foundBad ? 1 : 0;
}
/*
* Parse args.
*/
int main(int argc, char* const argv[])
{
bool wantUsage = false;
bool check = false;
bool force = false;
bool verbose = false;
int result = 1;
int alignment;
char* endp;
if (argc < 4) {
wantUsage = true;
goto bail;
}
argc--;
argv++;
while (argc && argv[0][0] == '-') {
const char* cp = argv[0] +1;
while (*cp != '\0') {
switch (*cp) {
case 'c':
check = true;
break;
case 'f':
force = true;
break;
case 'v':
verbose = true;
break;
default:
fprintf(stderr, "ERROR: unknown flag -%c\n", *cp);
wantUsage = true;
goto bail;
}
cp++;
}
argc--;
argv++;
}
if (!((check && argc == 2) || (!check && argc == 3))) {
wantUsage = true;
goto bail;
}
alignment = strtol(argv[0], &endp, 10);
if (*endp != '\0' || alignment <= 0) {
fprintf(stderr, "Invalid value for alignment: %s\n", argv[0]);
wantUsage = true;
goto bail;
}
if (check) {
/* check existing archive for correct alignment */
result = verify(argv[1], alignment, verbose);
} else {
/* create the new archive */
result = process(argv[1], argv[2], alignment, force);
/* trust, but verify */
if (result == 0)
result = verify(argv[2], alignment, verbose);
}
bail:
if (wantUsage) {
usage();
result = 2;
}
return result;
}