Improve zipcmp output.
diff --git a/developer-xcode/libzip.xcodeproj/project.pbxproj b/developer-xcode/libzip.xcodeproj/project.pbxproj
index 41dfdf5..02262ff 100644
--- a/developer-xcode/libzip.xcodeproj/project.pbxproj
+++ b/developer-xcode/libzip.xcodeproj/project.pbxproj
@@ -164,6 +164,7 @@
4B0454BA1E8E3E08002FA1F9 /* zip_source_compress.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0454B61E8E3DF7002FA1F9 /* zip_source_compress.c */; };
4B0454BC1E8E3E24002FA1F9 /* zip_algorithm_bzip2.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0454B41E8E3DF7002FA1F9 /* zip_algorithm_bzip2.c */; };
4B0454BD1E8E3E24002FA1F9 /* zip_algorithm_deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0454B51E8E3DF7002FA1F9 /* zip_algorithm_deflate.c */; };
+ 4B20D28726021D3600D77FA8 /* diff_output.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B20D28626021D3600D77FA8 /* diff_output.c */; };
4B30B50225F11684002CE070 /* zip_algorithm_zstd.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B9E577A24C7026B00CEE0D6 /* zip_algorithm_zstd.c */; };
4B30B53425F117C4002CE070 /* libzstd.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B30B53325F117C4002CE070 /* libzstd.dylib */; };
4B3A5F521DF96EB4005A53A1 /* zip_fseek.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B3A5F4D1DF96D83005A53A1 /* zip_fseek.c */; };
@@ -541,6 +542,11 @@
4B1E46E91A08CB7600A376D2 /* zip_error_set.mdoc */ = {isa = PBXFileReference; lastKnownFileType = text; path = zip_error_set.mdoc; sourceTree = "<group>"; };
4B1E46EA1A08CB7600A376D2 /* zip_error_strerror.mdoc */ = {isa = PBXFileReference; lastKnownFileType = text; path = zip_error_strerror.mdoc; sourceTree = "<group>"; };
4B1E46EB1A08CB7600A376D2 /* zip_error_system_type.mdoc */ = {isa = PBXFileReference; lastKnownFileType = text; path = zip_error_system_type.mdoc; sourceTree = "<group>"; };
+ 4B20D28526021D3600D77FA8 /* diff_output.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = diff_output.h; sourceTree = "<group>"; };
+ 4B20D28626021D3600D77FA8 /* diff_output.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = diff_output.c; sourceTree = "<group>"; };
+ 4B20D2982602314A00D77FA8 /* zipcmp_zip_dir.test */ = {isa = PBXFileReference; lastKnownFileType = text; path = zipcmp_zip_dir.test; sourceTree = "<group>"; };
+ 4B20D2992602314A00D77FA8 /* add_from_file_unchange.test */ = {isa = PBXFileReference; lastKnownFileType = text; path = add_from_file_unchange.test; sourceTree = "<group>"; };
+ 4B20D29A2602314A00D77FA8 /* encryption-stat.test */ = {isa = PBXFileReference; lastKnownFileType = text; path = "encryption-stat.test"; sourceTree = "<group>"; };
4B26FF151A07DF1A000E9788 /* zip_file_get_external_attributes.mdoc */ = {isa = PBXFileReference; lastKnownFileType = text; path = zip_file_get_external_attributes.mdoc; sourceTree = "<group>"; };
4B26FF161A07DF1A000E9788 /* zip_file_set_external_attributes.mdoc */ = {isa = PBXFileReference; lastKnownFileType = text; path = zip_file_set_external_attributes.mdoc; sourceTree = "<group>"; };
4B26FF171A07DF1A000E9788 /* zip_file_set_mtime.mdoc */ = {isa = PBXFileReference; lastKnownFileType = text; path = zip_file_set_mtime.mdoc; sourceTree = "<group>"; };
@@ -1068,6 +1074,8 @@
isa = PBXGroup;
children = (
4B55D93F2475274B00CE8C38 /* CMakeLists.txt */,
+ 4B20D28626021D3600D77FA8 /* diff_output.c */,
+ 4B20D28526021D3600D77FA8 /* diff_output.h */,
4B01D72115B2F572002D5007 /* zipcmp.c */,
4B01D72215B2F572002D5007 /* zipmerge.c */,
4BACD57C15BC2AEF00920691 /* ziptool.c */,
@@ -1208,8 +1216,8 @@
4BC03F9A1FDD5617003C7B62 /* fseek.c */,
4B30B4D025F0ECF7002CE070 /* fuzz_main.c */,
4BD6CB5E19E71B3B00710654 /* hole.c */,
- 4B30B4BF25F0ECC8002CE070 /* liboverride.c */,
4B30B4D125F0EE6D002CE070 /* liboverride-test.c */,
+ 4B30B4BF25F0ECC8002CE070 /* liboverride.c */,
4BC03F9C1FDD5617003C7B62 /* malloc.c */,
4B4CB5572483D7B7005C5428 /* nihtest.conf.in */,
4BD155CE191CD28D0046F012 /* NiHTest.pm */,
@@ -1232,6 +1240,7 @@
4BD35E421A33366200256CB7 /* add_from_buffer.test */,
4BD35E431A33366200256CB7 /* add_from_file_duplicate.test */,
4BD35E441A33366200256CB7 /* add_from_file_twice_duplicate.test */,
+ 4B20D2992602314A00D77FA8 /* add_from_file_unchange.test */,
4BD35E451A33366200256CB7 /* add_from_file.test */,
4BD35E461A33366200256CB7 /* add_from_filep.test */,
4BD35E471A33366200256CB7 /* add_from_stdin.test */,
@@ -1276,6 +1285,7 @@
4BC03F831FDD55C2003C7B62 /* encryption-nonrandom-aes256.test */,
4B00CA2A242F5C2500E0B71C /* encryption-nonrandom-pkware.test */,
4BC03F881FDD55C3003C7B62 /* encryption-remove.test */,
+ 4B20D29A2602314A00D77FA8 /* encryption-stat.test */,
4BD35E5C1A33366200256CB7 /* extra_add_multiple.test */,
4BD35E5D1A33366200256CB7 /* extra_add.test */,
4BD35E5E1A33366200256CB7 /* extra_count_by_id.test */,
@@ -1363,6 +1373,7 @@
4BC03F781FDD55C1003C7B62 /* zip-in-archive-comment.test */,
4BD35EE31A33366300256CB7 /* zip64_creation.test */,
4BD35EE41A33366300256CB7 /* zip64_stored_creation.test */,
+ 4B20D2982602314A00D77FA8 /* zipcmp_zip_dir.test */,
);
name = "test cases";
sourceTree = "<group>";
@@ -2058,6 +2069,7 @@
buildActionMask = 2147483647;
files = (
4B01D72515B2F57B002D5007 /* zipcmp.c in Sources */,
+ 4B20D28726021D3600D77FA8 /* diff_output.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/man/zipcmp.mdoc b/man/zipcmp.mdoc
index c29ee69..aa553d4 100644
--- a/man/zipcmp.mdoc
+++ b/man/zipcmp.mdoc
@@ -29,7 +29,7 @@
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd March 4, 2021
+.Dd March 17, 2021
.Dt ZIPCMP 1
.Os
.Sh NAME
@@ -61,8 +61,9 @@
Compare names ignoring case distinctions.
.It Fl p
Enable paranoid checks.
-Compares extra fields and other meta data.
+Compares extra fields, comments, and other meta data.
(Automatically disabled if one of the archives is a directory.)
+These checks are skipped for files where the data differs.
.It Fl q
Quiet mode.
Compare
diff --git a/regress/zipcmp_zip_dir.test b/regress/zipcmp_zip_dir.test
index e8ba46e..91413bc 100644
--- a/regress/zipcmp_zip_dir.test
+++ b/regress/zipcmp_zip_dir.test
@@ -8,7 +8,7 @@
return 1
stdout --- zipcmp_zip_dir.zip
stdout +++ a
-stdout - 0 00000000 00-empty-dir/
-stdout - 1 e8b7be43 dir-with-file/a
-stdout + 0 00000000 empty-dir-in-dir/
-stdout - 0 00000000 empty-dir/
+stdout - file '00-empty-dir/', size 0, crc 00000000
+stdout - file 'dir-with-file/a', size 1, crc e8b7be43
+stdout + file 'empty-dir-in-dir/', size 0, crc 00000000
+stdout - file 'empty-dir/', size 0, crc 00000000
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b6eb0b1..5d75b8a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -10,4 +10,5 @@
target_sources(${PROGRAM} PRIVATE getopt.c)
endif(NOT HAVE_GETOPT)
endforeach()
+target_sources(zipcmp PRIVATE diff_output.c)
target_link_libraries(zipcmp ${FTS_LIB} ZLIB::ZLIB)
diff --git a/src/diff_output.c b/src/diff_output.c
new file mode 100644
index 0000000..472ee89
--- /dev/null
+++ b/src/diff_output.c
@@ -0,0 +1,101 @@
+#include "diff_output.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "compat.h"
+
+static void ensure_header(diff_output_t *output) {
+ if (output->archive_names[0] != NULL) {
+ printf("--- %s\n", output->archive_names[0]);
+ printf("+++ %s\n", output->archive_names[1]);
+ output->archive_names[0] = NULL;
+ output->archive_names[1] = NULL;
+ }
+}
+
+void diff_output_init(diff_output_t *output, int verbose, char *const archive_names[]) {
+ output->archive_names[0] = archive_names[0];
+ output->archive_names[1] = archive_names[1];
+ output->verbose = verbose;
+ output->file_name = NULL;
+ output->file_size = 0;
+ output->file_crc = 0;
+}
+
+void diff_output_start_file(diff_output_t *output, const char *name, zip_uint64_t size, zip_uint32_t crc) {
+ output->file_name = name;
+ output->file_size = size;
+ output->file_crc = crc;
+}
+
+void diff_output_end_file(diff_output_t *output) {
+ output->file_name = NULL;
+}
+
+void diff_output(diff_output_t *output, int side, const char *fmt, ...) {
+ va_list ap;
+
+ if (!output->verbose) {
+ return;
+ }
+
+ ensure_header(output);
+
+ if (output->file_name != NULL) {
+ diff_output_file(output, ' ', output->file_name, output->file_size, output->file_crc);
+ output->file_name = NULL;
+ }
+
+ printf("%c ", side);
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+ printf("\n");
+}
+
+void diff_output_file(diff_output_t *output, char side, const char *name, zip_uint64_t size, zip_uint32_t crc) {
+ if (!output->verbose) {
+ return;
+ }
+
+ ensure_header(output);
+
+ printf("%c file '%s', size %" PRIu64 ", crc %08x\n", side, name, size, crc);
+}
+
+#define MAX_BYTES 64
+void diff_output_data(diff_output_t *output, int side, const zip_uint8_t *data, zip_uint64_t data_length, const char *fmt, ...) {
+ char hexdata[MAX_BYTES * 3 + 6];
+ size_t i, offset;
+ va_list ap;
+ char *prefix;
+
+ if (!output->verbose) {
+ return;
+ }
+
+ offset = 0;
+ for (i = 0; i < data_length; i++) {
+ hexdata[offset++] = (i == 0 ? '<' : ' ');
+
+ if (i >= MAX_BYTES) {
+ sprintf(hexdata + offset, "...");
+ break;
+ }
+ sprintf(hexdata + offset, "%02x", data[i]);
+ offset += 2;
+ }
+
+ hexdata[offset++] = '>';
+ hexdata[offset] = '\0';
+
+ va_start(ap, fmt);
+ vasprintf(&prefix, fmt, ap);
+ va_end(ap);
+
+ diff_output(output, side, "%s, length %" PRIu64 ", data %s", prefix, data_length, hexdata);
+
+ free(prefix);
+}
diff --git a/src/diff_output.h b/src/diff_output.h
new file mode 100644
index 0000000..6ed9396
--- /dev/null
+++ b/src/diff_output.h
@@ -0,0 +1,23 @@
+#ifndef HAD_DIFF_OUTPUT_H
+#define HAD_DIFF_OUTPUT_H
+
+#include <zip.h>
+
+typedef struct {
+ const char *archive_names[2];
+ const char *file_name;
+ zip_uint64_t file_size;
+ zip_uint32_t file_crc;
+ int verbose;
+} diff_output_t;
+
+void diff_output_init(diff_output_t *output, int verbose, char *const archive_names[]);
+void diff_output_start_file(diff_output_t *output, const char *name, zip_uint64_t size, zip_uint32_t crc);
+void diff_output_end_file(diff_output_t *output);
+
+void diff_output(diff_output_t *output, int side, const char *fmt, ...) __attribute__((__format__(__printf__, 3, 4)));
+void diff_output_data(diff_output_t *output, int side, const zip_uint8_t *data, zip_uint64_t data_length, const char *fmt, ...) __attribute__((__format__(__printf__, 5, 6)));
+void diff_output_file(diff_output_t *output, char side, const char *name, zip_uint64_t size, zip_uint32_t crc);
+
+
+#endif /* HAD_DIFF_OUTPUT_H */
diff --git a/src/zipcmp.c b/src/zipcmp.c
index 66e4b24..41a36ea 100644
--- a/src/zipcmp.c
+++ b/src/zipcmp.c
@@ -55,6 +55,8 @@
#include "compat.h"
+#include "diff_output.h"
+
struct archive {
const char *name;
zip_t *za;
@@ -84,6 +86,100 @@
};
+typedef struct {
+ uint32_t value;
+ const char * const name;
+} enum_map_t;
+
+const enum_map_t comp_methods[] = {
+ { 0, "Stored (no compression)" },
+ { 1, "Shrunk" },
+ { 2, "Reduced with compression factor 1" },
+ { 3, "Reduced with compression factor 2" },
+ { 4, "Reduced with compression factor 3" },
+ { 5, "Reduced with compression factor 4" },
+ { 6, "Imploded" },
+ { 7, "Reserved for Tokenizing compression algorithm" },
+ { 8, "Deflated" },
+ { 9, "Enhanced Deflating using Deflate64(tm)" },
+ { 10, "PKWARE Data Compression Library Imploding (old IBM TERSE)" },
+ { 11, "11 (Reserved by PKWARE)" },
+ { 12, "BZIP2" },
+ { 13, "13 (Reserved by PKWARE)" },
+ { 14, "LZMA (EFS)" },
+ { 15, "15 (Reserved by PKWARE)" },
+ { 16, "16 (Reserved by PKWARE)" },
+ { 17, "17 (Reserved by PKWARE)" },
+ { 18, "IBM TERSE (new)" },
+ { 19, "IBM LZ77 z Architecture (PFS)" },
+ { 20, "Zstandard compressed data (obsolete)" },
+ { 93, "Zstandard compressed data" },
+ { 95, "XZ compressed data" },
+ { 97, "WavPack compressed data" },
+ { 98, "PPMd version I, Rev 1" },
+ { 99, "WinZIP AES Encryption" },
+ { UINT32_MAX, NULL }
+};
+
+const enum_map_t extra_fields[] = {
+ /* PKWARE defined */
+ { 0x0001, "Zip64 extended information Extra field" },
+ { 0x0007, "AV Info" },
+ { 0x0008, "Reserved for extended language encoding data (PFS)" },
+ { 0x0009, "OS/2" },
+ { 0x000a, "NTFS" },
+ { 0x000c, "OpenVMS" },
+ { 0x000d, "UNIX" },
+ { 0x000e, "Reserved for file stream and fork descriptors" },
+ { 0x000f, "Patch Descriptor" },
+ { 0x0014, "PKCS#7 Store for X.509 Certificates" },
+ { 0x0015, "X.509 Certificate ID and Signature for individual file" },
+ { 0x0016, "X.509 Certificate ID for Central Directory" },
+ { 0x0017, "Strong Encryption Header" },
+ { 0x0018, "Record Management Controls" },
+ { 0x0019, "PKCS#7 Encryption Recipient Certificate List" },
+ { 0x0065, "IBM S/390 (Z390), AS/400 (I400) attributes - uncompressed" },
+ { 0x0066, "Reserved for IBM S/390 (Z390), AS/400 (I400) attributes - compressed" },
+ { 0x4690, "POSZIP 4690 (reserved)" },
+
+ /* Third-Party defined; see InfoZIP unzip sources proginfo/extrafld.txt */
+ { 0x07c8, "Info-ZIP Macintosh (old)" },
+ { 0x2605, "ZipIt Macintosh (first version)" },
+ { 0x2705, "ZipIt Macintosh 1.3.5+ (w/o full filename)" },
+ { 0x2805, "ZipIt Macintosh 1.3.5+" },
+ { 0x334d, "Info-ZIP Macintosh (new)" },
+ { 0x4154, "Tandem NSK" },
+ { 0x4341, "Acorn/SparkFS" },
+ { 0x4453, "Windows NT security descriptor" },
+ { 0x4704, "VM/CMS" },
+ { 0x470f, "MVS" },
+ { 0x4854, "Theos, old inofficial port" },
+ { 0x4b46, "FWKCS MD5" },
+ { 0x4c41, "OS/2 access control list (text ACL)" },
+ { 0x4d49, "Info-ZIP OpenVMS (obsolete)" },
+ { 0x4d63, "Macintosh SmartZIP" },
+ { 0x4f4c, "Xceed original location extra field" },
+ { 0x5356, "AOS/VS (ACL)" },
+ { 0x5455, "extended timestamp" },
+ { 0x554e, "Xceed unicode extra field" },
+ { 0x5855, "Info-ZIP UNIX (original)" },
+ { 0x6375, "Info-ZIP UTF-8 comment field" },
+ { 0x6542, "BeOS (BeBox, PowerMac, etc.)" },
+ { 0x6854, "Theos" },
+ { 0x7075, "Info-ZIP UTF-8 name field" },
+ { 0x7441, "AtheOS (AtheOS/Syllable attributes)" },
+ { 0x756e, "ASi UNIX" },
+ { 0x7855, "Info-ZIP UNIX" },
+ { 0x7875, "Info-ZIP UNIX 3rd generation" },
+ { 0x9901, "WinZIP AES encryption" },
+ { 0xa220, "Microsoft Open Packaging Growth Hint" },
+ { 0xcafe, "executable Java JAR file" },
+ { 0xfb4a, "SMS/QDOS" }, /* per InfoZIP extrafld.txt */
+ { 0xfd4a, "SMS/QDOS" }, /* per appnote.txt */
+ { UINT32_MAX, NULL }
+};
+
+
const char *progname;
#define PROGRAM "zipcmp"
@@ -114,16 +210,19 @@
#define BOTH_ARE_ZIPS(a) (a[0].za && a[1].za)
static int comment_compare(const char *c1, size_t l1, const char *c2, size_t l2);
-static int compare_list(char *const name[], const void *l[], const zip_uint64_t n[], int size, int (*cmp)(const void *, const void *), int (*ignore)(const void *l, int last, const void *o), int (*checks)(char *const name[2], const void *, const void *), void (*print)(const void *));
+static int compare_list(char *const name[2], const void *list[2], const zip_uint64_t list_length[2], int element_size, int (*cmp)(const void *a, const void *b), int (*ignore)(const void *list, int last, const void *other), int (*check)(char *const name[2], const void *a, const void *b), void (*print)(char side, const void *element), void (*start_file)(const void *element));
static int compare_zip(char *const zn[]);
static int ef_compare(char *const name[2], const struct entry *e1, const struct entry *e2);
static int ef_order(const void *a, const void *b);
-static void ef_print(const void *p);
+static void ef_print(char side, const void *p);
static int ef_read(zip_t *za, zip_uint64_t idx, struct entry *e);
static int entry_cmp(const void *p1, const void *p2);
static int entry_ignore(const void *p1, int last, const void *o);
static int entry_paranoia_checks(char *const name[2], const void *p1, const void *p2);
-static void entry_print(const void *p);
+static void entry_print(char side, const void *p);
+static void entry_start_file(const void *p);
+static const char *map_enum(const enum_map_t *map, uint32_t value);
+
static int is_directory(const char *name);
#ifdef HAVE_FTS_H
static int list_directory(const char *name, struct archive *a);
@@ -132,7 +231,8 @@
static int test_file(zip_t *za, zip_uint64_t idx, const char *zipname, const char *filename, zip_uint64_t size, zip_uint32_t crc);
int ignore_case, test_files, paranoid, verbose, have_directory, check_consistency;
-int header_done;
+
+diff_output_t output;
int
@@ -228,19 +328,21 @@
qsort(a[i].entry, a[i].nentry, sizeof(a[i].entry[0]), entry_cmp);
}
- header_done = 0;
+ diff_output_init(&output, verbose, zn);
e[0] = a[0].entry;
e[1] = a[1].entry;
n[0] = a[0].nentry;
n[1] = a[1].nentry;
- res = compare_list(zn, (const void **)e, n, sizeof(e[i][0]), entry_cmp, have_directory ? entry_ignore : NULL, paranoid ? entry_paranoia_checks : NULL, entry_print);
+ res = compare_list(zn, (const void **)e, n, sizeof(e[i][0]), entry_cmp, have_directory ? entry_ignore : NULL, paranoid ? entry_paranoia_checks : NULL, entry_print, entry_start_file);
if (paranoid) {
if (comment_compare(a[0].comment, a[0].comment_length, a[1].comment, a[1].comment_length) != 0) {
- if (verbose) {
- printf("--- archive comment (%zu)\n", a[0].comment_length);
- printf("+++ archive comment (%zu)\n", a[1].comment_length);
+ if (a[0].comment_length > 0) {
+ diff_output_data(&output, '-', (const zip_uint8_t *)a[0].comment, a[0].comment_length, "archive comment");
+ }
+ if (a[1].comment_length > 0) {
+ diff_output_data(&output, '+', (const zip_uint8_t *)a[1].comment, a[1].comment_length, "archive comment");
}
res = 1;
}
@@ -482,37 +584,36 @@
}
-static int
-compare_list(char *const name[2], const void *l[2], const zip_uint64_t n[2], int size, int (*cmp)(const void *, const void *), int (*ignore)(const void *l, int last, const void *o), int (*check)(char *const name[2], const void *, const void *), void (*print)(const void *)) {
+static int compare_list(char *const name[2], const void *list[2], const zip_uint64_t list_length[2], int element_size, int (*cmp)(const void *a, const void *b), int (*ignore)(const void *list, int last, const void *other), int (*check)(char *const name[2], const void *a, const void *b), void (*print)(char side, const void *element), void (*start_file)(const void *element)) {
unsigned int i[2];
- int j, c;
+ int j;
int diff;
-#define INC(k) (i[k]++, l[k] = ((const char *)l[k]) + size)
+#define INC(k) (i[k]++, list[k] = ((const char *)list[k]) + element_size)
#define PRINT(k) \
do { \
- if (ignore && ignore(l[k], i[k] >= n[k] - 1, i[1-k] < n[1-k] ? l[1-k] : NULL)) { \
+ if (ignore && ignore(list[k], i[k] >= list_length[k] - 1, i[1-k] < list_length[1-k] ? list[1-k] : NULL)) { \
break; \
} \
- if (header_done == 0 && verbose) { \
- printf("--- %s\n+++ %s\n", name[0], name[1]); \
- header_done = 1; \
- } \
- if (verbose) { \
- printf("%c ", (k) ? '+' : '-'); \
- print(l[k]); \
- } \
+ print((k) ? '+' : '-', list[k]); \
diff = 1; \
} while (0)
i[0] = i[1] = 0;
diff = 0;
- while (i[0] < n[0] && i[1] < n[1]) {
- c = cmp(l[0], l[1]);
+ while (i[0] < list_length[0] && i[1] < list_length[1]) {
+ int c = cmp(list[0], list[1]);
if (c == 0) {
- if (check)
- diff |= check(name, l[0], l[1]);
+ if (check) {
+ if (start_file) {
+ start_file(list[0]);
+ }
+ diff |= check(name, list[0], list[1]);
+ if (start_file) {
+ diff_output_end_file(&output);
+ }
+ }
INC(0);
INC(1);
}
@@ -527,7 +628,7 @@
}
for (j = 0; j < 2; j++) {
- while (i[j] < n[j]) {
+ while (i[j] < list_length[j]) {
PRINT(j);
INC(j);
}
@@ -582,7 +683,7 @@
n[0] = e1->n_extra_fields;
n[1] = e2->n_extra_fields;
- return compare_list(name, (const void **)ef, n, sizeof(struct ef), ef_order, NULL, NULL, ef_print);
+ return compare_list(name, (const void **)ef, n, sizeof(struct ef), ef_order, NULL, NULL, ef_print, NULL);
}
@@ -604,15 +705,10 @@
static void
-ef_print(const void *p) {
+ef_print(char side, const void *p) {
const struct ef *ef = (struct ef *)p;
- int i;
- printf(" %s ", ef->name);
- printf("%04x %c <", ef->id, ef->flags == ZIP_FL_LOCAL ? 'l' : 'c');
- for (i = 0; i < ef->size; i++)
- printf("%s%02x", i ? " " : "", ef->data[i]);
- printf(">\n");
+ diff_output_data(&output, side, ef->data, ef->size, " %s extra field %s", ef->flags == ZIP_FL_LOCAL ? "local" : "central", map_enum(extra_fields, ef->id));
}
@@ -676,33 +772,19 @@
ret = 0;
- if (ef_compare(name, e1, e2) != 0)
- ret = 1;
-
if (e1->comp_method != e2->comp_method) {
- if (verbose) {
- if (header_done == 0) {
- printf("--- %s\n+++ %s\n", name[0], name[1]);
- header_done = 1;
- }
- printf("--- %s ", e1->name);
- printf("method %u\n", e1->comp_method);
- printf("+++ %s ", e1->name);
- printf("method %u\n", e2->comp_method);
- }
+ diff_output(&output, '-', " compression method %s", map_enum(comp_methods, e1->comp_method));
+ diff_output(&output, '+', " compression method %s", map_enum(comp_methods, e2->comp_method));
ret = 1;
}
+
+ if (ef_compare(name, e1, e2) != 0) {
+ ret = 1;
+ }
+
if (comment_compare(e1->comment, e1->comment_length, e2->comment, e2->comment_length) != 0) {
- if (verbose) {
- if (header_done == 0) {
- printf("--- %s\n+++ %s\n", name[0], name[1]);
- header_done = 1;
- }
- printf("--- %s ", e1->name);
- printf("comment %" PRIu32 "\n", e1->comment_length);
- printf("+++ %s ", e1->name);
- printf("comment %" PRIu32 "\n", e2->comment_length);
- }
+ diff_output_data(&output, '-', (const zip_uint8_t *)e1->comment, e1->comment_length, " comment");
+ diff_output_data(&output, '+', (const zip_uint8_t *)e2->comment, e2->comment_length, " comment");
ret = 1;
}
@@ -710,14 +792,17 @@
}
-static void
-entry_print(const void *p) {
- const struct entry *e;
+static void entry_print(char side, const void *p) {
+ const struct entry *e = (struct entry *)p;
- e = (struct entry *)p;
+ diff_output_file(&output, side, e->name, e->size, e->crc);
+}
- /* TODO PRId64 */
- printf("%10lu %08x %s\n", (unsigned long)e->size, e->crc, e->name);
+
+static void entry_start_file(const void *p) {
+ const struct entry *e = (struct entry *)p;
+
+ diff_output_start_file(&output, e->name, e->size, e->crc);
}
@@ -761,3 +846,21 @@
return 0;
}
+
+
+static const char *map_enum(const enum_map_t *map, uint32_t value) {
+ static char unknown[16];
+ size_t i = 0;
+
+ while (map[i].value < UINT32_MAX) {
+ if (map[i].value == value) {
+ return map[i].name;
+ }
+ i++;
+ }
+
+ snprintf(unknown, sizeof(unknown), "unknown (%u)", value);
+ unknown[sizeof(unknown) - 1] = '\0';
+
+ return unknown;
+}