Merge "Refactor zipalign to allow unit tests"

This commit is contained in:
Treehugger Robot 2020-11-05 19:10:22 +00:00 committed by Gerrit Code Review
commit 6be3371c23
8 changed files with 254 additions and 129 deletions

View file

@ -4,20 +4,31 @@
// Zip alignment tool // Zip alignment tool
// //
cc_binary_host { cc_defaults {
name: "zipalign", name: "zipalign_defaults",
target: {
windows: {
host_ldlibs: ["-lpthread"],
enabled: true,
},
},
}
cc_library_host_static {
name: "libzipalign",
srcs: [ srcs: [
"ZipAlign.cpp", "ZipAlign.cpp",
"ZipEntry.cpp", "ZipEntry.cpp",
"ZipFile.cpp", "ZipFile.cpp",
], ],
export_include_dirs: [
"include",
],
cflags: ["-Wall", "-Werror"], cflags: ["-Wall", "-Werror"],
// NOTE: Do not add any shared_libs dependencies because they will break the // NOTE: Do not add any shared_libs dependencies because they will break the
// static_sdk_tools target. // static_sdk_tools target.
static_libs: [ whole_static_libs: [
"libutils", "libutils",
"libcutils", "libcutils",
"liblog", "liblog",
@ -26,11 +37,32 @@ cc_binary_host {
"libbase", "libbase",
"libzopfli", "libzopfli",
], ],
defaults: ["zipalign_defaults"],
target: { }
windows: {
host_ldlibs: ["-lpthread"], cc_binary_host {
enabled: true, name: "zipalign",
}, srcs: [
}, "ZipAlignMain.cpp",
],
cflags: ["-Wall", "-Werror"],
static_libs: [
"libzipalign",
],
defaults: ["zipalign_defaults"],
}
cc_test_host {
name: "zipalign_tests",
srcs: [
"tests/src/*_test.cpp",
],
static_libs: [
"libzipalign",
"libgmock",
],
data: [
"tests/data/unaligned.zip",
],
defaults: ["zipalign_defaults"],
} }

View file

@ -14,35 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
/*
* Zip alignment tool
*/
#include "ZipFile.h" #include "ZipFile.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
using namespace android; 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] [-p] [-v] [-z] <align> infile.zip outfile.zip\n"
" zipalign -c [-p] [-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, " -p: memory page alignment for stored shared object files\n");
fprintf(stderr, " -v: verbose output\n");
fprintf(stderr, " -z: recompress using Zopfli\n");
}
static int getAlignment(bool pageAlignSharedLibs, int defaultAlignment, static int getAlignment(bool pageAlignSharedLibs, int defaultAlignment,
ZipEntry* pEntry) { ZipEntry* pEntry) {
@ -126,7 +104,7 @@ static int copyAndAlign(ZipFile* pZin, ZipFile* pZout, int alignment, bool zopfl
* Process a file. We open the input and output files, failing if the * Process a file. We open the input and output files, failing if the
* output file exists and "force" wasn't specified. * output file exists and "force" wasn't specified.
*/ */
static int process(const char* inFileName, const char* outFileName, int process(const char* inFileName, const char* outFileName,
int alignment, bool force, bool zopfli, bool pageAlignSharedLibs) int alignment, bool force, bool zopfli, bool pageAlignSharedLibs)
{ {
ZipFile zin, zout; ZipFile zin, zout;
@ -169,7 +147,7 @@ static int process(const char* inFileName, const char* outFileName,
/* /*
* Verify the alignment of a zip archive. * Verify the alignment of a zip archive.
*/ */
static int verify(const char* fileName, int alignment, bool verbose, int verify(const char* fileName, int alignment, bool verbose,
bool pageAlignSharedLibs) bool pageAlignSharedLibs)
{ {
ZipFile zipFile; ZipFile zipFile;
@ -218,92 +196,4 @@ static int verify(const char* fileName, int alignment, bool verbose,
return foundBad ? 1 : 0; return foundBad ? 1 : 0;
} }
/* } // namespace android
* Parse args.
*/
int main(int argc, char* const argv[])
{
bool wantUsage = false;
bool check = false;
bool force = false;
bool verbose = false;
bool zopfli = false;
bool pageAlignSharedLibs = 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;
case 'z':
zopfli = true;
break;
case 'p':
pageAlignSharedLibs = 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, pageAlignSharedLibs);
} else {
/* create the new archive */
result = process(argv[1], argv[2], alignment, force, zopfli, pageAlignSharedLibs);
/* trust, but verify */
if (result == 0) {
result = verify(argv[2], alignment, verbose, pageAlignSharedLibs);
}
}
bail:
if (wantUsage) {
usage();
result = 2;
}
return result;
}

View file

@ -0,0 +1,136 @@
/*
* 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 "ZipAlign.h"
#include <stdio.h>
#include <stdlib.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] [-p] [-v] [-z] <align> infile.zip outfile.zip\n"
" zipalign -c [-p] [-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, " -p: memory page alignment for stored shared object files\n");
fprintf(stderr, " -v: verbose output\n");
fprintf(stderr, " -z: recompress using Zopfli\n");
}
/*
* Parse args.
*/
int main(int argc, char* const argv[])
{
bool wantUsage = false;
bool check = false;
bool force = false;
bool verbose = false;
bool zopfli = false;
bool pageAlignSharedLibs = 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;
case 'z':
zopfli = true;
break;
case 'p':
pageAlignSharedLibs = 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, pageAlignSharedLibs);
} else {
/* create the new archive */
result = process(argv[1], argv[2], alignment, force, zopfli, pageAlignSharedLibs);
/* trust, but verify */
if (result == 0) {
result = verify(argv[2], alignment, verbose, pageAlignSharedLibs);
}
}
bail:
if (wantUsage) {
usage();
result = 2;
}
return result;
}

View file

@ -29,7 +29,7 @@
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
using namespace android; namespace android {
/* /*
* Initialize a new ZipEntry structure from a FILE* positioned at a * Initialize a new ZipEntry structure from a FILE* positioned at a
@ -696,3 +696,5 @@ void ZipEntry::CentralDirEntry::dump(void) const
ALOGD(" comment: '%s'\n", mFileComment); ALOGD(" comment: '%s'\n", mFileComment);
} }
} // namespace android

View file

@ -35,7 +35,7 @@
#include <assert.h> #include <assert.h>
#include <inttypes.h> #include <inttypes.h>
using namespace android; namespace android {
/* /*
* Some environments require the "b", some choke on it. * Some environments require the "b", some choke on it.
@ -134,7 +134,7 @@ status_t ZipFile::open(const char* zipFileName, int flags)
/* /*
* Return the Nth entry in the archive. * Return the Nth entry in the archive.
*/ */
android::ZipEntry* ZipFile::getEntryByIndex(int idx) const ZipEntry* ZipFile::getEntryByIndex(int idx) const
{ {
if (idx < 0 || idx >= (int) mEntries.size()) if (idx < 0 || idx >= (int) mEntries.size())
return NULL; return NULL;
@ -145,7 +145,7 @@ android::ZipEntry* ZipFile::getEntryByIndex(int idx) const
/* /*
* Find an entry by name. * Find an entry by name.
*/ */
android::ZipEntry* ZipFile::getEntryByName(const char* fileName) const ZipEntry* ZipFile::getEntryByName(const char* fileName) const
{ {
/* /*
* Do a stupid linear string-compare search. * Do a stupid linear string-compare search.
@ -1397,3 +1397,4 @@ void ZipFile::EndOfCentralDir::dump(void) const
mCentralDirSize, mCentralDirOffset, mCommentLen); mCentralDirSize, mCentralDirOffset, mCommentLen);
} }
} // namespace android

View file

@ -0,0 +1,49 @@
/*
* Copyright (C) 2020 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.
*/
#ifndef ZIPALIGN_H
#define ZIPALIGN_H
namespace android {
/*
* Generate a new, aligned, zip "output" from an "input" zip.
* - alignTo: Alignment (in bytes) for uncompressed entries.
* - force : Overwrite output if it exists, fail otherwise.
* - zopfli : Recompress compressed entries with more efficient algorithm.
* Copy compressed entries as-is, and unaligned, otherwise.
* - pageAlignSharedLibs: Align .so files to 4096 and other files to
* alignTo, or all files to alignTo if false..
*
* Returns 0 on success.
*/
int process(const char* input, const char* output, int alignTo, bool force,
bool zopfli, bool pageAlignSharedLibs);
/*
* Verify the alignment of a zip archive.
* - alignTo: Alignment (in bytes) for uncompressed entries.
* - pageAlignSharedLibs: Align .so files to 4096 and other files to
* alignTo, or all files to alignTo if false..
*
* Returns 0 on success.
*/
int verify(const char* fileName, int alignTo, bool verbose,
bool pageAlignSharedLibs);
} // namespace android
#endif // ZIPALIGN_H

Binary file not shown.

View file

@ -0,0 +1,15 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "ZipAlign.h"
#include <stdio.h>
using namespace android;
TEST(Align, Unaligned) {
const char* src = "tests/data/unaligned.zip";
const char* dst = "tests/data/unaligned_out.zip";
int result = process(src, dst, 4, true, false, 4096);
ASSERT_EQ(0, result);
}