Improve error string structure.
diff --git a/developer-xcode/zip_err_str.c b/developer-xcode/zip_err_str.c
index 09440b8..c9b1504 100644
--- a/developer-xcode/zip_err_str.c
+++ b/developer-xcode/zip_err_str.c
@@ -5,89 +5,53 @@
 
 #include "zipint.h"
 
-const char * const _zip_err_str[] = {
-    "No error",
-    "Multi-disk zip archives not supported",
-    "Renaming temporary file failed",
-    "Closing zip archive failed",
-    "Seek error",
-    "Read error",
-    "Write error",
-    "CRC error",
-    "Containing zip archive was closed",
-    "No such file",
-    "File already exists",
-    "Can't open file",
-    "Failure to create temporary file",
-    "Zlib error",
-    "Malloc failure",
-    "Entry has been changed",
-    "Compression method not supported",
-    "Premature end of file",
-    "Invalid argument",
-    "Not a zip archive",
-    "Internal error",
-    "Zip archive inconsistent",
-    "Can't remove file",
-    "Entry has been deleted",
-    "Encryption method not supported",
-    "Read-only archive",
-    "No password provided",
-    "Wrong password provided",
-    "Operation not supported",
-    "Resource still in use",
-    "Tell error",
-    "Compressed data invalid",
-    "Operation cancelled",
-};
-
-const int _zip_nerr_str = sizeof(_zip_err_str)/sizeof(_zip_err_str[0]);
-
 #define L ZIP_ET_LIBZIP
 #define N ZIP_ET_NONE
 #define S ZIP_ET_SYS
 #define Z ZIP_ET_ZLIB
 
-#define E true
-#define G false
+#define E ZIP_DETAIL_ET_ENTRY
+#define G ZIP_DETAIL_ET_GLOBAL
 
-const int _zip_err_type[] = {
-    N,
-    N,
-    S,
-    S,
-    S,
-    S,
-    S,
-    N,
-    N,
-    N,
-    N,
-    S,
-    S,
-    Z,
-    N,
-    N,
-    N,
-    N,
-    N,
-    N,
-    N,
-    L,
-    S,
-    N,
-    N,
-    N,
-    N,
-    N,
-    N,
-    N,
-    S,
-    N,
-    N,
+const struct _zip_err_info _zip_err_str[] = {
+    { N, "No error" },
+    { N, "Multi-disk zip archives not supported" },
+    { S, "Renaming temporary file failed" },
+    { S, "Closing zip archive failed" },
+    { S, "Seek error" },
+    { S, "Read error" },
+    { S, "Write error" },
+    { N, "CRC error" },
+    { N, "Containing zip archive was closed" },
+    { N, "No such file" },
+    { N, "File already exists" },
+    { S, "Can't open file" },
+    { S, "Failure to create temporary file" },
+    { Z, "Zlib error" },
+    { N, "Malloc failure" },
+    { N, "Entry has been changed" },
+    { N, "Compression method not supported" },
+    { N, "Premature end of file" },
+    { N, "Invalid argument" },
+    { N, "Not a zip archive" },
+    { N, "Internal error" },
+    { L, "Zip archive inconsistent" },
+    { S, "Can't remove file" },
+    { N, "Entry has been deleted" },
+    { N, "Encryption method not supported" },
+    { N, "Read-only archive" },
+    { N, "No password provided" },
+    { N, "Wrong password provided" },
+    { N, "Operation not supported" },
+    { N, "Resource still in use" },
+    { S, "Tell error" },
+    { N, "Compressed data invalid" },
+    { N, "Operation cancelled" },
 };
 
-const struct _zip_err_detail _zip_err_details[] = {
+const int _zip_err_str_count = sizeof(_zip_err_str)/sizeof(_zip_err_str[0]);
+
+const struct _zip_err_info _zip_err_details[] = {
     { G, "no detail" },
     { G, "central directory overlaps EOCD, or there is space between them" },
     { G, "archive comment length incorrect" },
@@ -100,6 +64,14 @@
     { G, "EOCD64 magic incorrect" },
     { G, "EOCD64 and EOCD do not match" },
     { G, "invalid value in central directory" },
+    { E, "variable size fields overflow header" },
+    { E, "invalid UTF-8 in filename" },
+    { E, "invalid UTF-8 in comment" },
+    { E, "invalid Zip64 extra field" },
+    { E, "invalid WinZip AES extra field" },
+    { E, "garbage at end of extra fields" },
+    { E, "extra field length is invalid" },
+    { E, "file length in header doesn't match actual file length" },
 };
 
 const int _zip_err_details_count = sizeof(_zip_err_details)/sizeof(_zip_err_details[0]);
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 3d0aa70..4db84f8 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -206,34 +206,28 @@
 
 #include "zipint.h"
 
-const char * const _zip_err_str[] = {
-]=])
-set(zip_err_type)
-foreach(errln ${zip_h_err})
-  string(REGEX MATCH "#define ZIP_ER_([A-Z0-9_]+) ([0-9]+)[ \t]+/([-*0-9a-zA-Z, ']*)/" err_t_tt ${errln})
-  string(REGEX MATCH "([L|N|S|Z]+) ([-0-9a-zA-Z,, ']*)" err_t_tt "${CMAKE_MATCH_3}")
-  string(APPEND zip_err_type "    ${CMAKE_MATCH_1},\n")
-  string(STRIP "${CMAKE_MATCH_2}" err_t_tt)
-  string(APPEND zip_err_str "    \"${err_t_tt}\",\n")
-endforeach()
-string(APPEND zip_err_str [=[}\;
-
-const int _zip_nerr_str = sizeof(_zip_err_str)/sizeof(_zip_err_str[0])\;
-
 #define L ZIP_ET_LIBZIP
 #define N ZIP_ET_NONE
 #define S ZIP_ET_SYS
 #define Z ZIP_ET_ZLIB
 
-#define E true
-#define G false
+#define E ZIP_DETAIL_ET_ENTRY
+#define G ZIP_DETAIL_ET_GLOBAL
 
-const int _zip_err_type[] = {
+const struct _zip_err_info _zip_err_str[] = {
 ]=])
-string(APPEND zip_err_str "${zip_err_type}}\;\n")
-string(APPEND zip_err_str [=[
+set(zip_err_type)
+foreach(errln ${zip_h_err})
+  string(REGEX MATCH "#define ZIP_ER_([A-Z0-9_]+) ([0-9]+)[ \t]+/([-*0-9a-zA-Z, ']*)/" err_t_tt ${errln})
+  string(REGEX MATCH "([L|N|S|Z]+) ([-0-9a-zA-Z,, ']*)" err_t_tt "${CMAKE_MATCH_3}")
+  string(STRIP "${CMAKE_MATCH_2}" err_t_tt)
+  string(APPEND zip_err_str "    { ${CMAKE_MATCH_1}, \"${err_t_tt}\" },\n")
+endforeach()
+string(APPEND zip_err_str [=[}\;
 
-const struct _zip_err_detail _zip_err_details[] = {
+const int _zip_err_str_count = sizeof(_zip_err_str)/sizeof(_zip_err_str[0])\;
+
+const struct _zip_err_info _zip_err_details[] = {
 ]=])
 foreach(errln ${zipint_h_err})
   string(REGEX MATCH "#define ZIP_ER_DETAIL_([A-Z0-9_]+) ([0-9]+)[ \t]+/([-*0-9a-zA-Z, ']*)/" err_t_tt ${errln})
diff --git a/lib/zip_error.c b/lib/zip_error.c
index f639f00..adaa40b 100644
--- a/lib/zip_error.c
+++ b/lib/zip_error.c
@@ -81,10 +81,10 @@
 
 ZIP_EXTERN int
 zip_error_system_type(const zip_error_t *error) {
-    if (error->zip_err < 0 || error->zip_err >= _zip_nerr_str)
+    if (error->zip_err < 0 || error->zip_err >= _zip_err_str_count)
         return ZIP_ET_NONE;
 
-    return _zip_err_type[error->zip_err];
+    return _zip_err_str[error->zip_err].type;
 }
 
 
diff --git a/lib/zip_error_get_sys_type.c b/lib/zip_error_get_sys_type.c
index 3c9998c..86d03cf 100644
--- a/lib/zip_error_get_sys_type.c
+++ b/lib/zip_error_get_sys_type.c
@@ -37,8 +37,9 @@
 
 ZIP_EXTERN int
 zip_error_get_sys_type(int ze) {
-    if (ze < 0 || ze >= _zip_nerr_str)
+    if (ze < 0 || ze >= _zip_err_str_count) {
         return 0;
+    }
 
-    return _zip_err_type[ze];
+    return _zip_err_str[ze].type;
 }
diff --git a/lib/zip_error_strerror.c b/lib/zip_error_strerror.c
index 8b07131..7570aaf 100644
--- a/lib/zip_error_strerror.c
+++ b/lib/zip_error_strerror.c
@@ -46,16 +46,16 @@
 
     zip_error_fini(err);
 
-    if (err->zip_err < 0 || err->zip_err >= _zip_nerr_str) {
+    if (err->zip_err < 0 || err->zip_err >= _zip_err_str_count) {
         snprintf(buf, sizeof(buf), "Unknown error %d", err->zip_err);
         buf[sizeof(buf) - 1] = '\0'; /* make sure string is NUL-terminated */
         zip_error_string = NULL;
         system_error_string = buf;
     }
     else {
-        zip_error_string = _zip_err_str[err->zip_err];
+        zip_error_string = _zip_err_str[err->zip_err].description;
 
-        switch (_zip_err_type[err->zip_err]) {
+        switch (_zip_err_str[err->zip_err].type) {
             case ZIP_ET_SYS:
                 system_error_string = strerror(err->sys_err);
                 break;
@@ -76,7 +76,7 @@
                     buf[sizeof(buf) - 1] = '\0'; /* make sure string is NUL-terminated */
                     system_error_string = buf;
                 }
-                else if (_zip_err_details[error].has_index && index < MAX_DETAIL_INDEX) {
+                else if (_zip_err_details[error].type == ZIP_DETAIL_ET_ENTRY && index < MAX_DETAIL_INDEX) {
                     snprintf(buf, sizeof(buf), "entry %d: %s", index, _zip_err_details[error].description);
                     buf[sizeof(buf) - 1] = '\0'; /* make sure string is NUL-terminated */
                     system_error_string = buf;
@@ -97,7 +97,7 @@
     }
     else {
         if ((s = (char *)malloc(strlen(system_error_string) + (zip_error_string ? strlen(zip_error_string) + 2 : 0) + 1)) == NULL) {
-            return _zip_err_str[ZIP_ER_MEMORY];
+            return _zip_err_str[ZIP_ER_MEMORY].description;
         }
 
         sprintf(s, "%s%s%s", (zip_error_string ? zip_error_string : ""), (zip_error_string ? ": " : ""), system_error_string);
diff --git a/lib/zip_error_to_str.c b/lib/zip_error_to_str.c
index d315b19..70756c0 100644
--- a/lib/zip_error_to_str.c
+++ b/lib/zip_error_to_str.c
@@ -44,22 +44,23 @@
 zip_error_to_str(char *buf, zip_uint64_t len, int ze, int se) {
     const char *zs, *ss;
 
-    if (ze < 0 || ze >= _zip_nerr_str)
+    if (ze < 0 || ze >= _zip_err_str_count) {
         return snprintf(buf, len, "Unknown error %d", ze);
+    }
 
-    zs = _zip_err_str[ze];
+    zs = _zip_err_str[ze].description;
 
-    switch (_zip_err_type[ze]) {
-    case ZIP_ET_SYS:
-        ss = strerror(se);
-        break;
-
-    case ZIP_ET_ZLIB:
-        ss = zError(se);
-        break;
-
-    default:
-        ss = NULL;
+    switch (_zip_err_str[ze].type) {
+        case ZIP_ET_SYS:
+            ss = strerror(se);
+            break;
+            
+        case ZIP_ET_ZLIB:
+            ss = zError(se);
+            break;
+            
+        default:
+            ss = NULL;
     }
 
     return snprintf(buf, len, "%s%s%s", zs, (ss ? ": " : ""), (ss ? ss : ""));
diff --git a/lib/zipint.h b/lib/zipint.h
index df7dfa3..ee2a50d 100644
--- a/lib/zipint.h
+++ b/lib/zipint.h
@@ -189,12 +189,17 @@
 
 enum zip_les { ZIP_LES_NONE, ZIP_LES_UPPER, ZIP_LES_LOWER, ZIP_LES_INVAL };
 
-struct _zip_err_detail {
-    bool has_index;
+#define ZIP_DETAIL_ET_GLOBAL 0
+#define ZIP_DETAIL_ET_ENTRY  1
+
+struct _zip_err_info {
+    int type;
     const char *description;
 };
 
-extern const struct _zip_err_detail _zip_err_details[];
+extern const struct _zip_err_info _zip_err_str[];
+extern const int _zip_err_str_count;
+extern const struct _zip_err_info _zip_err_details[];
 extern const int _zip_err_details_count;
 
 /* macros for libzip-internal errors */
@@ -464,10 +469,6 @@
 };
 typedef struct _zip_pkware_keys zip_pkware_keys_t;
 
-extern const char *const _zip_err_str[];
-extern const int _zip_nerr_str;
-extern const int _zip_err_type[];
-
 #define ZIP_MAX(a, b) ((a) > (b) ? (a) : (b))
 #define ZIP_MIN(a, b) ((a) < (b) ? (a) : (b))