Consistently remove internally handled extra fields.
diff --git a/TODO b/TODO
index e689a1d..f23688c 100644
--- a/TODO
+++ b/TODO
@@ -51,9 +51,6 @@
 
 Bugs
 ====
-! D zip64 extra field not removed from local extra fields (extra_count_ignore_zip64.test)
-    create function to filter internal efs, use in _zip_dirent_read and _zip_read_local_ef
-    define macro ZIP_EF_IS_INTERNAL, use in zip_file_extra_field_set and filter function
 ! D check for off_t overflow
 ! D fix OpenSUSE i686 regression failures
 ! D readd zip_get_num_files man page
@@ -78,6 +75,7 @@
 
 Test Case Issues
 ================
+! W extra_count_ignore_zip64.test: lc count is 3, not 4 (Info-ZIP UNIX merged?)
 * test calls against old API
 * run regression tests also from CMake framework
 * rename file to dir/ and vice versa (fails)
diff --git a/lib/zip_dirent.c b/lib/zip_dirent.c
index df91a5b..8cdd660 100644
--- a/lib/zip_dirent.c
+++ b/lib/zip_dirent.c
@@ -486,9 +486,9 @@
 	    if (zde->disk_number == ZIP_UINT16_MAX)
 		zde->disk_number = _zip_read4(&ef);
 	}
-
-	zde->extra_fields = _zip_ef_delete_by_id(zde->extra_fields, ZIP_EF_ZIP64, ZIP_EXTRA_FIELD_ALL, local ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL);
     }
+    
+    zde->extra_fields = _zip_ef_remove_internal(zde->extra_fields);
 
     if (bufp)
       *bufp = cur;
@@ -523,8 +523,6 @@
 	}
     }
     
-    de->extra_fields = _zip_ef_delete_by_id(de->extra_fields, id, ZIP_EXTRA_FIELD_ALL, ZIP_EF_BOTH);
-
     return str;
 }
 
diff --git a/lib/zip_extra_field.c b/lib/zip_extra_field.c
index d4bc77f..9b9e399 100644
--- a/lib/zip_extra_field.c
+++ b/lib/zip_extra_field.c
@@ -255,6 +255,35 @@
 
 
 
+struct zip_extra_field *
+_zip_ef_remove_internal(struct zip_extra_field *ef)
+{
+    struct zip_extra_field *ef_head;
+    struct zip_extra_field *prev, *next;
+    
+    ef_head = prev = ef;
+    
+    while (ef) {
+        if (ZIP_EF_IS_INTERNAL(ef->id)) {
+            next = ef->next;
+            if (ef_head == ef)
+                ef_head = next;
+            ef->next = NULL;
+            _zip_ef_free(ef);
+            if (prev)
+                prev->next = next;
+            ef = next;
+        }
+        else {
+            prev = ef;
+            ef = ef->next;
+        }
+    }
+    
+    return ef_head;
+}
+
+
 zip_uint16_t
 _zip_ef_size(struct zip_extra_field *ef, zip_flags_t flags)
 {
@@ -339,7 +368,7 @@
 	}
 	free(ef_raw);
 	
-        /* XXX: remove fields handled internally (Zip64, UTF-8) */
+        ef = _zip_ef_remove_internal(ef);
 	e->orig->extra_fields = _zip_ef_merge(e->orig->extra_fields, ef);
     }
 
diff --git a/lib/zip_extra_field_api.c b/lib/zip_extra_field_api.c
index 0458c70..d232073 100644
--- a/lib/zip_extra_field_api.c
+++ b/lib/zip_extra_field_api.c
@@ -220,7 +220,7 @@
 	return -1;
     }
     
-    if (ef_id == ZIP_EF_ZIP64 || ef_id == ZIP_EF_UTF_8_NAME || ef_id == ZIP_EF_UTF_8_COMMENT) {
+    if (ZIP_EF_IS_INTERNAL(ef_id)) {
 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
 	return -1;
     }
diff --git a/lib/zipint.h b/lib/zipint.h
index fae8177..2477a59 100644
--- a/lib/zipint.h
+++ b/lib/zipint.h
@@ -136,6 +136,7 @@
 #define ZIP_EF_UTF_8_NAME	0x7075
 #define ZIP_EF_ZIP64		0x0001
 
+#define ZIP_EF_IS_INTERNAL(id)	((id) == ZIP_EF_UTF_8_COMMENT || (id) == ZIP_EF_UTF_8_NAME || (id) == ZIP_EF_ZIP64)
 
 
 /* This section contains API that won't materialize like this.  It's
@@ -408,6 +409,7 @@
 struct zip_extra_field *_zip_ef_merge(struct zip_extra_field *, struct zip_extra_field *);
 struct zip_extra_field *_zip_ef_new(zip_uint16_t, zip_uint16_t, const zip_uint8_t *, zip_flags_t);
 struct zip_extra_field *_zip_ef_parse(const zip_uint8_t *, zip_uint16_t, zip_flags_t, struct zip_error *);
+struct zip_extra_field *_zip_ef_remove_internal(struct zip_extra_field *);
 zip_uint16_t _zip_ef_size(struct zip_extra_field *, zip_flags_t);
 void _zip_ef_write(struct zip_extra_field *, zip_flags_t, FILE *);