Make sure that names of all entries have the same encoding.

Add new public method to allow checkisc if an archive has entry names encoded in
UTF-8. If not then they will be encoded in IBM PC character encoding.

Bug: 16162465
Change-Id: I4468d76accca8a9b0b31cae8d43399ffc22cad42
diff --git a/include/ziparchive/zip_archive.h b/include/ziparchive/zip_archive.h
index 27a9796..afd2b7e 100644
--- a/include/ziparchive/zip_archive.h
+++ b/include/ziparchive/zip_archive.h
@@ -158,6 +158,11 @@
 void EndIteration(void* cookie);
 
 /*
+ * Whether entry names in an archive are encoded in UTF-8.
+ */
+bool HasUTF8Names(const ZipArchiveHandle handle);
+
+/*
  * Uncompress and write an entry to an open file identified by |fd|.
  * |entry->uncompressed_length| bytes will be written to the file at
  * its current offset, and the file will be truncated at the end of
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index a29eb79..9fe7cc7 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -192,8 +192,11 @@
 
 #undef DISALLOW_IMPLICIT_CONSTRUCTORS
 
-static const uint32_t kGPBDDFlagMask = 0x0008;         // mask value that signifies that the entry has a DD
+// mask value that signifies that the entry has a DD
+static const uint32_t kGPBDDFlagMask = 0x0008;
 static const uint32_t kMaxErrorLen = 1024;
+// mask value that signifies that the entry names are encoded in UTF-8
+static const uint32_t kGPBEFSFlagMask = 0x0800;
 
 // The maximum size of a central directory or a file
 // comment in bytes.
@@ -295,6 +298,7 @@
 
   /* number of entries in the Zip archive */
   uint16_t num_entries;
+  bool utf8_names_encoding;
 
   /*
    * We know how many entries are in the Zip archive, so we can have a
@@ -310,6 +314,7 @@
       directory_offset(0),
       directory_map(NULL),
       num_entries(0),
+      utf8_names_encoding(false),
       hash_table_size(0),
       hash_table(NULL) {}
 
@@ -655,6 +660,15 @@
           ptr - cd_ptr, cd_length, i);
       goto bail;
     }
+    if (i == 0) {
+      archive->utf8_names_encoding = cdr->gpb_flags & kGPBEFSFlagMask;
+    } else {
+      bool has_utf8_name_encoding = cdr->gpb_flags & kGPBEFSFlagMask;
+      if (archive->utf8_names_encoding != has_utf8_name_encoding) {
+        ALOGW("Zip: Entry names encoded with different encoding");
+        goto bail;
+      }
+    }
   }
   ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries);
 
@@ -976,6 +990,11 @@
   return kIterationEnd;
 }
 
+bool HasUTF8Names(const ZipArchiveHandle handle) {
+  const ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
+  return archive->utf8_names_encoding;
+}
+
 static int32_t InflateToFile(int fd, const ZipEntry* entry,
                              uint8_t* begin, uint32_t length,
                              uint64_t* crc_out) {