When comparing directory listing, dont’ igore empty directories.
diff --git a/regress/zipcmp_zip_dir.test b/regress/zipcmp_zip_dir.test
index dbc7f50..e8ba46e 100644
--- a/regress/zipcmp_zip_dir.test
+++ b/regress/zipcmp_zip_dir.test
@@ -1,6 +1,14 @@
 # compare zip with directory
 program zipcmp
-mkdir 0777 dir-with-file
-args zipcmp_zip_dir.zip  dir-with-file
+mkdir 0777 a
+mkdir 0777 a/dir-with-file
+mkdir 0777 a/empty-dir-in-dir
+args zipcmp_zip_dir.zip  a
 file zipcmp_zip_dir.zip zipcmp_zip_dir.zip zipcmp_zip_dir.zip
-return 0
+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/
diff --git a/regress/zipcmp_zip_dir.zip b/regress/zipcmp_zip_dir.zip
index bf7a653..8f47f21 100644
--- a/regress/zipcmp_zip_dir.zip
+++ b/regress/zipcmp_zip_dir.zip
Binary files differ
diff --git a/src/zipcmp.c b/src/zipcmp.c
index 946e013..d63f1c3 100644
--- a/src/zipcmp.c
+++ b/src/zipcmp.c
@@ -113,13 +113,14 @@
 #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 (*checks)(char *const name[2], const void *, const void *), void (*print)(const void *));
+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_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 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 int is_directory(const char *name);
@@ -129,7 +130,7 @@
 static int list_zip(const char *name, struct archive *a);
 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;
+int ignore_case, test_files, paranoid, verbose, have_directory;
 int header_done;
 
 
@@ -142,6 +143,7 @@
     ignore_case = 0;
     test_files = 0;
     paranoid = 0;
+    have_directory = 0;
     verbose = 1;
 
     while ((c = getopt(argc, argv, OPTIONS)) != -1) {
@@ -209,6 +211,7 @@
 #else
             if (list_directory(zn[i], a + i) < 0)
                 exit(2);
+            have_directory = 1;
             paranoid = 0; /* paranoid checks make no sense for directories, since they compare zip metadata */
 #endif
         }
@@ -226,7 +229,7 @@
     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, 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);
 
     if (paranoid) {
         if (comment_compare(a[0].comment, a[0].comment_length, a[1].comment, a[1].comment_length) != 0) {
@@ -327,47 +330,62 @@
         zip_int64_t crc;
 
         switch (ent->fts_info) {
-        case FTS_D:
-        case FTS_DOT:
-        case FTS_DP:
-        case FTS_DEFAULT:
-        case FTS_SL:
-        case FTS_NSOK:
-            break;
+            case FTS_DOT:
+            case FTS_DP:
+            case FTS_DEFAULT:
+            case FTS_SL:
+            case FTS_NSOK:
+                break;
 
-        case FTS_DC:
-        case FTS_DNR:
-        case FTS_ERR:
-        case FTS_NS:
-        case FTS_SLNONE:
-            /* TODO: error */
-            fts_close(fts);
-            return -1;
-
-        case FTS_F:
-            if (a->nentry >= nalloc) {
-                nalloc += 16;
-                if (nalloc > SIZE_MAX / sizeof(a->entry[0])) {
-                    fprintf(stderr, "%s: malloc failure\n", progname);
-                    exit(1);
-                }
-                a->entry = realloc(a->entry, sizeof(a->entry[0]) * nalloc);
-                if (a->entry == NULL) {
-                    fprintf(stderr, "%s: malloc failure\n", progname);
-                    exit(1);
-                }
-            }
-
-            a->entry[a->nentry].name = strdup(ent->fts_path + prefix_length);
-            a->entry[a->nentry].size = (zip_uint64_t)ent->fts_statp->st_size;
-            if ((crc = compute_crc(ent->fts_accpath)) < 0) {
+            case FTS_DC:
+            case FTS_DNR:
+            case FTS_ERR:
+            case FTS_NS:
+            case FTS_SLNONE:
+                /* TODO: error */
                 fts_close(fts);
                 return -1;
-            }
 
-            a->entry[a->nentry].crc = (zip_uint32_t)crc;
-            a->nentry++;
-            break;
+            case FTS_D:
+            case FTS_F:
+                if (a->nentry >= nalloc) {
+                    nalloc += 16;
+                    if (nalloc > SIZE_MAX / sizeof(a->entry[0])) {
+                        fprintf(stderr, "%s: malloc failure\n", progname);
+                        exit(1);
+                    }
+                    a->entry = realloc(a->entry, sizeof(a->entry[0]) * nalloc);
+                    if (a->entry == NULL) {
+                        fprintf(stderr, "%s: malloc failure\n", progname);
+                        exit(1);
+                    }
+                }
+                
+                if (ent->fts_info == FTS_D) {
+                    char *dir_name;
+                    
+                    if (ent->fts_path[prefix_length] == '\0') {
+                        continue;
+                    }
+                    
+                    dir_name = malloc(strlen(ent->fts_path + prefix_length) + 2);
+                    sprintf(dir_name, "%s/", ent->fts_path + prefix_length);
+                    a->entry[a->nentry].name = dir_name;
+                    a->entry[a->nentry].size = 0;
+                    a->entry[a->nentry].crc = 0;
+                }
+                else {
+                    a->entry[a->nentry].name = strdup(ent->fts_path + prefix_length);
+                    a->entry[a->nentry].size = (zip_uint64_t)ent->fts_statp->st_size;
+                    if ((crc = compute_crc(ent->fts_accpath)) < 0) {
+                        fts_close(fts);
+                        return -1;
+                    }
+                
+                    a->entry[a->nentry].crc = (zip_uint32_t)crc;
+                }
+                a->nentry++;
+                break;
         }
     }
 
@@ -456,7 +474,7 @@
 
 
 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 (*check)(char *const name[2], const void *, const void *), void (*print)(const void *)) {
+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 *)) {
     unsigned int i[2];
     int j, c;
     int diff;
@@ -464,6 +482,9 @@
 #define INC(k) (i[k]++, l[k] = ((const char *)l[k]) + 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)) {   \
+            break;                                        \
+        }                                                 \
         if (header_done == 0 && verbose) {                \
             printf("--- %s\n+++ %s\n", name[0], name[1]); \
             header_done = 1;                              \
@@ -552,7 +573,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, ef_print);
+    return compare_list(name, (const void **)ef, n, sizeof(struct ef), ef_order, NULL, NULL, ef_print);
 }
 
 
@@ -610,6 +631,33 @@
 
 
 static int
+entry_ignore(const void *p, int last, const void *o) {
+    const struct entry *e = (const struct entry *)p;
+    const struct entry *other = (const struct entry *)o;
+    
+    size_t length = strlen(e[0].name);
+    
+    if (length == 0 || e[0].name[length - 1] != '/') {
+        /* not a directory */
+        return 0;
+    }
+    
+    if (other != NULL && strlen(other->name) > length && strncmp(other->name, e[0].name, length) == 0) {
+        /* not empty in other archive */
+        return 1;
+    }
+    
+    if (last || (strlen(e[1].name) < length || strncmp(e[0].name, e[1].name, length) != 0)) {
+        /* empty in this archive */
+        return 0;
+    }
+    
+    /* not empty in this archive */
+    return 1;
+}
+
+
+static int
 entry_paranoia_checks(char *const name[2], const void *p1, const void *p2) {
     const struct entry *e1, *e2;
     int ret;