Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 22 Jul 2008 13:04:08 GMT
From:      Anselm Strauss <strauss@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 145604 for review
Message-ID:  <200807221304.m6MD48Ge042071@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=145604

Change 145604 by strauss@strauss_marvelman on 2008/07/22 13:03:28

	- Added writing of end of central directory in ZIP writer
	- Added ZIP writer empty test from Tim
	- Fixed zip_encode() function (littel-endian encoding)

Affected files ...

.. //depot/projects/soc2008/strauss_libarchive/Makefile.am#8 edit
.. //depot/projects/soc2008/strauss_libarchive/libarchive/archive_write_set_format_zip.c#14 edit
.. //depot/projects/soc2008/strauss_libarchive/libarchive/test/test_write_format_zip_empty.c#1 add

Differences ...

==== //depot/projects/soc2008/strauss_libarchive/Makefile.am#8 (text+ko) ====

@@ -232,6 +232,7 @@
 	libarchive/test/test_write_format_tar.c			\
 	libarchive/test/test_write_format_tar_empty.c		\
 	libarchive/test/test_write_format_tar_ustar.c		\
+	libarchive/test/test_write_format_zip_empty.c		\
 	libarchive/test/test_write_open_memory.c
 
 libarchive_test_CPPFLAGS= -I$(top_builddir)/libarchive -I$(top_srcdir)/libarchive -I$(top_builddir)/libarchive/test

==== //depot/projects/soc2008/strauss_libarchive/libarchive/archive_write_set_format_zip.c#14 (text+ko) ====

@@ -12,6 +12,11 @@
  * Note that generally data in ZIP files is little-endian encoded,
  * with some exceptions.
  * 
+ * TODO: Since Libarchive is generally 64bit oriented, but this implementation
+ * does not yet support sizes exceeding 32bit, it is highly fragile for
+ * big archives. This should change when ZIP64 is finally implemented, otherwise
+ * some serious checking has to be done.
+ * 
  */
 
 #include "archive_platform.h"
@@ -31,6 +36,7 @@
 #define ZIP_SIGNATURE_LOCAL_FILE_HEADER 0x04034b50
 #define ZIP_SIGNATURE_DATA_DESCRIPTOR 0x08074b50
 #define ZIP_SIGNATURE_FILE_HEADER 0x02014b50
+#define ZIP_SIGNATURE_CENTRAL_DIRECTORY_END 0x06054b50
 
 #include "archive.h"
 #include "archive_entry.h"
@@ -42,7 +48,7 @@
 static int archive_write_zip_destroy(struct archive_write *);
 static int archive_write_zip_finish_entry(struct archive_write *);
 static int archive_write_zip_header(struct archive_write *, struct archive_entry *);
-static void zip_encode(int64_t, void *, size_t);
+static void zip_encode(uint64_t, void *, size_t);
 
 struct zip_local_file_header {
 	char signature[4];
@@ -94,6 +100,17 @@
 	struct zip_file_header_link *central_directory;
 };
 
+struct zip_central_directory_end {
+	char signature[4];
+	char disk[2];
+	char start_disk[2];
+	char entries_disk[2];
+	char entries[2];
+	char size[4];
+	char offset[4];
+	char comment_length[2];
+};
+
 int
 archive_write_set_format_zip(struct archive *_a)
 {
@@ -160,9 +177,7 @@
 	l->next = zip->central_directory;
 	zip->central_directory = l;
 	
-	/* Store the offset of this header for later use in central directory.
-	 * TODO: Offset actually are 8 bytes, for big archives this won't fit into
-	 * the 4 bytes field. Either use ZIP64, or return error. */
+	/* Store the offset of this header for later use in central directory. */ 
 	l->offset = a->archive.raw_position;
 	
 	/* 
@@ -230,8 +245,11 @@
 	struct zip *zip;
 	struct zip_file_header_link *l;
 	struct zip_file_header h;
-	int64_t size;
+	struct zip_central_directory_end end;
+	uint64_t size;
+	off_t offset;
 	const char *path;
+	int entries;
 	int ret;
 	
 	zip = (struct zip *) a->format_data;
@@ -252,6 +270,8 @@
 	zip_encode(ZIP_SIGNATURE_FILE_HEADER, &h.signature, sizeof(h.signature));
 	zip_encode(0x0200, &h.version_extract, sizeof(h.version_extract));
 	
+	entries = 0;
+	offset = a->archive.raw_position;
 	while (l != NULL) {
 		
 		/* Formatting individual header fields per entry. */
@@ -271,7 +291,20 @@
 		if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL);
 
 		l = l->next;
+		++entries;
 	}
+	
+	/* Formatting end of central directory. */
+	memset(&end, 0, sizeof(end));
+	zip_encode(ZIP_SIGNATURE_CENTRAL_DIRECTORY_END, &end.signature, sizeof(end.signature));
+	zip_encode(entries, &end.entries, sizeof(end.entries));
+	zip_encode(entries, &end.entries_disk, sizeof(end.entries_disk));
+	zip_encode(entries * sizeof(h), &end.size, sizeof(end.size));
+	zip_encode(offset, &end.offset, sizeof(end.offset));
+	
+	/* Writing end of central directory. */
+	ret = (a->compressor.write)(a, &end, sizeof(end));
+	if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL);
 
 	return (ARCHIVE_OK);
 }
@@ -295,12 +328,13 @@
 
 /* Encode data in little-endian for writing it to a ZIP file. */
 static void
-zip_encode(int64_t value, void *_p, size_t size)
+zip_encode(uint64_t value, void *_p, size_t size)
 {
 	unsigned char *p = (unsigned char *) _p;
 	size_t i;
 	for (i = 0; i <= size; ++i) {
-		*p = (value >>= i) & 0xff;
+		*p = value & 0xff;
+		value >>= 8;
 		p++;
 	}
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200807221304.m6MD48Ge042071>