svn commit: r189389 - in head/lib/libarchive: . test

Tim Kientzle kientzle at FreeBSD.org
Wed Mar 4 18:19:43 PST 2009


Author: kientzle
Date: Thu Mar  5 02:19:42 2009
New Revision: 189389
URL: http://svn.freebsd.org/changeset/base/189389

Log:
  Merge r364, r378, r379, r393, and r539 from libarchive.googlecode.com:
  This is the last phase of the "big decompression refactor" that
  puts a lazy reblocking layer between each pair of read filters.
  I've also changed the terminology for this area---the two kinds
  of objects are now called "read filters" and "read filter bidders"---and
  moved ownership of these objects to the archive_read core.
  
  This greatly simplifies implementing new read filters, which
  can now use peek/consume I/O semantics both for bidding (arbitrary
  look-ahead!) and for reading streams (look-ahead simplifies handling
  concatenated streams, for instance).
  
  The first merge here is the overhaul proper; the remainder are small
  fixes to correct errors in the initial implementation.

Modified:
  head/lib/libarchive/archive_read.c
  head/lib/libarchive/archive_read_private.h
  head/lib/libarchive/archive_read_support_compression_bzip2.c
  head/lib/libarchive/archive_read_support_compression_compress.c
  head/lib/libarchive/archive_read_support_compression_gzip.c
  head/lib/libarchive/archive_read_support_compression_program.c
  head/lib/libarchive/test/test_read_position.c

Modified: head/lib/libarchive/archive_read.c
==============================================================================
--- head/lib/libarchive/archive_read.c	Thu Mar  5 01:59:49 2009	(r189388)
+++ head/lib/libarchive/archive_read.c	Thu Mar  5 02:19:42 2009	(r189389)
@@ -75,16 +75,6 @@ archive_read_new(void)
 	a->archive.state = ARCHIVE_STATE_NEW;
 	a->entry = archive_entry_new();
 
-	/* Initialize reblocking logic. */
-	a->buffer_size = 64 * 1024; /* 64k */
-	a->buffer = (char *)malloc(a->buffer_size);
-	a->next = a->buffer;
-	if (a->buffer == NULL) {
-		archive_entry_free(a->entry);
-		free(a);
-		return (NULL);
-	}
-
 	return (&a->archive);
 }
 
@@ -117,28 +107,33 @@ archive_read_open(struct archive *a, voi
 }
 
 static ssize_t
-client_read_proxy(struct archive_read_source *self, const void **buff)
+client_read_proxy(struct archive_read_filter *self, const void **buff)
 {
-	return (self->archive->client.reader)((struct archive *)self->archive,
+	ssize_t r;
+	r = (self->archive->client.reader)(&self->archive->archive,
 	    self->data, buff);
+	self->archive->archive.raw_position += r;
+	return (r);
 }
 
 static int64_t
-client_skip_proxy(struct archive_read_source *self, int64_t request)
+client_skip_proxy(struct archive_read_filter *self, int64_t request)
 {
-	return (self->archive->client.skipper)((struct archive *)self->archive,
+	int64_t r;
+	r = (self->archive->client.skipper)(&self->archive->archive,
 	    self->data, request);
+	self->archive->archive.raw_position += r;
+	return (r);
 }
 
 static int
-client_close_proxy(struct archive_read_source *self)
+client_close_proxy(struct archive_read_filter *self)
 {
 	int r = ARCHIVE_OK;
 
 	if (self->archive->client.closer != NULL)
 		r = (self->archive->client.closer)((struct archive *)self->archive,
 		    self->data);
-	free(self);
 	return (r);
 }
 
@@ -151,6 +146,7 @@ archive_read_open2(struct archive *_a, v
     archive_close_callback *client_closer)
 {
 	struct archive_read *a = (struct archive_read *)_a;
+	struct archive_read_filter *filter;
 	int e;
 
 	__archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
@@ -172,27 +168,21 @@ archive_read_open2(struct archive *_a, v
 	}
 
 	/* Save the client functions and mock up the initial source. */
-	a->client.opener = client_opener; /* Do we need to remember this? */
 	a->client.reader = client_reader;
 	a->client.skipper = client_skipper;
 	a->client.closer = client_closer;
-	a->client.data = client_data;
 
-	{
-		struct archive_read_source *source;
-
-		source = calloc(1, sizeof(*source));
-		if (source == NULL)
-			return (ARCHIVE_FATAL);
-		source->reader = NULL;
-		source->upstream = NULL;
-		source->archive = a;
-		source->data = client_data;
-		source->read = client_read_proxy;
-		source->skip = client_skip_proxy;
-		source->close = client_close_proxy;
-		a->source = source;
-	}
+	filter = calloc(1, sizeof(*filter));
+	if (filter == NULL)
+		return (ARCHIVE_FATAL);
+	filter->bidder = NULL;
+	filter->upstream = NULL;
+	filter->archive = a;
+	filter->data = client_data;
+	filter->read = client_read_proxy;
+	filter->skip = client_skip_proxy;
+	filter->close = client_close_proxy;
+	a->filter = filter;
 
 	/* In case there's no filter. */
 	a->archive.compression_code = ARCHIVE_COMPRESSION_NONE;
@@ -214,60 +204,49 @@ archive_read_open2(struct archive *_a, v
 static int
 build_stream(struct archive_read *a)
 {
-	int number_readers, i, bid, best_bid;
-	struct archive_reader *reader, *best_reader;
-	struct archive_read_source *source;
-	const void *block;
-	ssize_t bytes_read;
-
-	/* Read first block now for compress format detection. */
-	bytes_read = (a->source->read)(a->source, &block);
-	if (bytes_read < 0) {
-		/* If the first read fails, close before returning error. */
-		if (a->source->close != NULL) {
-			(a->source->close)(a->source);
-			a->source = NULL;
-		}
-		/* source->read should have already set error information. */
-		return (ARCHIVE_FATAL);
-	}
+	int number_bidders, i, bid, best_bid;
+	struct archive_read_filter_bidder *bidder, *best_bidder;
+	struct archive_read_filter *filter;
+	int r;
 
-	number_readers = sizeof(a->readers) / sizeof(a->readers[0]);
+	for (;;) {
+		number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);
 
-	best_bid = 0;
-	best_reader = NULL;
+		best_bid = 0;
+		best_bidder = NULL;
 
-	reader = a->readers;
-	for (i = 0, reader = a->readers; i < number_readers; i++, reader++) {
-		if (reader->bid != NULL) {
-			bid = (reader->bid)(reader, block, bytes_read);
-			if (bid > best_bid) {
-				best_bid = bid;
-				best_reader = reader;
+		bidder = a->bidders;
+		for (i = 0; i < number_bidders; i++, bidder++) {
+			if (bidder->bid != NULL) {
+				bid = (bidder->bid)(bidder, a->filter);
+				if (bid > best_bid) {
+					best_bid = bid;
+					best_bidder = bidder;
+				}
 			}
 		}
-	}
 
-	/*
-	 * If we have a winner, it becomes the next stage in the pipeline.
-	 */
-	if (best_reader != NULL) {
-		source = (best_reader->init)(a, best_reader, a->source,
-		    block, bytes_read);
-		if (source == NULL)
+		/* If no bidder, we're done. */
+		if (best_bidder == NULL) {
+			a->archive.compression_name = a->filter->name;
+			a->archive.compression_code = a->filter->code;
+			return (ARCHIVE_OK);
+		}
+
+		filter
+		    = (struct archive_read_filter *)calloc(1, sizeof(*filter));
+		if (filter == NULL)
 			return (ARCHIVE_FATAL);
-		/* Record the best decompressor for this stream. */
-		a->source = source;
-		/* Recurse to get next pipeline stage. */
-		return (build_stream(a));
+		filter->bidder = best_bidder;
+		filter->archive = a;
+		filter->upstream = a->filter;
+		r = (best_bidder->init)(filter);
+		if (r != ARCHIVE_OK) {
+			free(filter);
+			return (r);
+		}
+		a->filter = filter;
 	}
-
-	/* Save first block of data. */
-	a->client_buff = block;
-	a->client_total = bytes_read;
-	a->client_next = a->client_buff;
-	a->client_avail = a->client_total;
-	return (ARCHIVE_OK);
 }
 
 /*
@@ -594,20 +573,24 @@ archive_read_close(struct archive *_a)
 
 	/* TODO: Clean up the formatters. */
 
-	/* Clean up the stream pipeline. */
-	while (a->source != NULL) {
-		struct archive_read_source *t = a->source->upstream;
-		r1 = (a->source->close)(a->source);
-		if (r1 < r)
-			r = r1;
-		a->source = t;
+	/* Clean up the filter pipeline. */
+	while (a->filter != NULL) {
+		struct archive_read_filter *t = a->filter->upstream;
+		if (a->filter->close != NULL) {
+			r1 = (a->filter->close)(a->filter);
+			if (r1 < r)
+				r = r1;
+		}
+		free(a->filter->buffer);
+		free(a->filter);
+		a->filter = t;
 	}
 
-	/* Release the reader objects. */
-	n = sizeof(a->readers)/sizeof(a->readers[0]);
+	/* Release the bidder objects. */
+	n = sizeof(a->bidders)/sizeof(a->bidders[0]);
 	for (i = 0; i < n; i++) {
-		if (a->readers[i].free != NULL) {
-			r1 = (a->readers[i].free)(&a->readers[i]);
+		if (a->bidders[i].free != NULL) {
+			r1 = (a->bidders[i].free)(&a->bidders[i]);
 			if (r1 < r)
 				r = r1;
 		}
@@ -649,7 +632,6 @@ archive_read_finish(struct archive *_a)
 	if (a->entry)
 		archive_entry_free(a->entry);
 	a->archive.magic = 0;
-	free(a->buffer);
 	free(a);
 #if ARCHIVE_API_VERSION > 1
 	return (r);
@@ -699,20 +681,20 @@ __archive_read_register_format(struct ar
  * Used internally by decompression routines to register their bid and
  * initialization functions.
  */
-struct archive_reader *
-__archive_read_get_reader(struct archive_read *a)
+struct archive_read_filter_bidder *
+__archive_read_get_bidder(struct archive_read *a)
 {
 	int i, number_slots;
 
 	__archive_check_magic(&a->archive,
 	    ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
-	    "__archive_read_get_reader");
+	    "__archive_read_get_bidder");
 
-	number_slots = sizeof(a->readers) / sizeof(a->readers[0]);
+	number_slots = sizeof(a->bidders) / sizeof(a->bidders[0]);
 
 	for (i = 0; i < number_slots; i++) {
-		if (a->readers[i].bid == NULL)
-			return (a->readers + i);
+		if (a->bidders[i].bid == NULL)
+			return (a->bidders + i);
 	}
 
 	__archive_errx(1, "Not enough slots for compression registration");
@@ -725,7 +707,7 @@ __archive_read_get_reader(struct archive
  * flexible read-ahead and allows the I/O code to operate in a
  * zero-copy manner most of the time.
  *
- * In the ideal case, block providers give the I/O code blocks of data
+ * In the ideal case, filters generate blocks of data
  * and __archive_read_ahead() just returns pointers directly into
  * those blocks.  Then __archive_read_consume() just bumps those
  * pointers.  Only if your request would span blocks does the I/O
@@ -738,7 +720,7 @@ __archive_read_get_reader(struct archive
  *  * "I just want some data."  Ask for 1 byte and pay attention to
  *    the "number of bytes available" from __archive_read_ahead().
  *    You can consume more than you asked for; you just can't consume
- *    more than is available right now.  If you consume everything that's
+ *    more than is available.  If you consume everything that's
  *    immediately available, the next read_ahead() call will pull
  *    the next block.
  *  * "I want to output a large block of data."  As above, ask for 1 byte,
@@ -790,10 +772,17 @@ __archive_read_get_reader(struct archive
 const void *
 __archive_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
 {
+	return (__archive_read_filter_ahead(a->filter, min, avail));
+}
+
+const void *
+__archive_read_filter_ahead(struct archive_read_filter *filter,
+    size_t min, ssize_t *avail)
+{
 	ssize_t bytes_read;
 	size_t tocopy;
 
-	if (a->fatal) {
+	if (filter->fatal) {
 		if (avail)
 			*avail = ARCHIVE_FATAL;
 		return (NULL);
@@ -807,68 +796,68 @@ __archive_read_ahead(struct archive_read
 		/*
 		 * If we can satisfy from the copy buffer, we're done.
 		 */
-		if (a->avail >= min) {
+		if (filter->avail >= min) {
 			if (avail != NULL)
-				*avail = a->avail;
-			return (a->next);
+				*avail = filter->avail;
+			return (filter->next);
 		}
 
 		/*
 		 * We can satisfy directly from client buffer if everything
 		 * currently in the copy buffer is still in the client buffer.
 		 */
-		if (a->client_total >= a->client_avail + a->avail
-		    && a->client_avail + a->avail >= min) {
+		if (filter->client_total >= filter->client_avail + filter->avail
+		    && filter->client_avail + filter->avail >= min) {
 			/* "Roll back" to client buffer. */
-			a->client_avail += a->avail;
-			a->client_next -= a->avail;
+			filter->client_avail += filter->avail;
+			filter->client_next -= filter->avail;
 			/* Copy buffer is now empty. */
-			a->avail = 0;
-			a->next = a->buffer;
+			filter->avail = 0;
+			filter->next = filter->buffer;
 			/* Return data from client buffer. */
 			if (avail != NULL)
-				*avail = a->client_avail;
-			return (a->client_next);
+				*avail = filter->client_avail;
+			return (filter->client_next);
 		}
 
 		/* Move data forward in copy buffer if necessary. */
-		if (a->next > a->buffer &&
-		    a->next + min > a->buffer + a->buffer_size) {
-			if (a->avail > 0)
-				memmove(a->buffer, a->next, a->avail);
-			a->next = a->buffer;
+		if (filter->next > filter->buffer &&
+		    filter->next + min > filter->buffer + filter->buffer_size) {
+			if (filter->avail > 0)
+				memmove(filter->buffer, filter->next, filter->avail);
+			filter->next = filter->buffer;
 		}
 
 		/* If we've used up the client data, get more. */
-		if (a->client_avail <= 0) {
-			if (a->end_of_file) {
+		if (filter->client_avail <= 0) {
+			if (filter->end_of_file) {
 				if (avail != NULL)
 					*avail = 0;
 				return (NULL);
 			}
-			bytes_read = (a->source->read)(a->source,
-			    &a->client_buff);
+			bytes_read = (filter->read)(filter,
+			    &filter->client_buff);
 			if (bytes_read < 0) {		/* Read error. */
-				a->client_total = a->client_avail = 0;
-				a->client_next = a->client_buff = NULL;
-				a->fatal = 1;
+				filter->client_total = filter->client_avail = 0;
+				filter->client_next = filter->client_buff = NULL;
+				filter->fatal = 1;
 				if (avail != NULL)
 					*avail = ARCHIVE_FATAL;
 				return (NULL);
 			}
 			if (bytes_read == 0) {	/* Premature end-of-file. */
-				a->client_total = a->client_avail = 0;
-				a->client_next = a->client_buff = NULL;
-				a->end_of_file = 1;
+				filter->client_total = filter->client_avail = 0;
+				filter->client_next = filter->client_buff = NULL;
+				filter->end_of_file = 1;
 				/* Return whatever we do have. */
 				if (avail != NULL)
-					*avail = a->avail;
+					*avail = filter->avail;
 				return (NULL);
 			}
-			a->archive.raw_position += bytes_read;
-			a->client_total = bytes_read;
-			a->client_avail = a->client_total;
-			a->client_next = a->client_buff;
+			filter->position += bytes_read;
+			filter->client_total = bytes_read;
+			filter->client_avail = filter->client_total;
+			filter->client_next = filter->client_buff;
 		}
 		else
 		{
@@ -880,19 +869,22 @@ __archive_read_ahead(struct archive_read
 			 */
 
 			/* Ensure the buffer is big enough. */
-			if (min > a->buffer_size) {
+			if (min > filter->buffer_size) {
 				size_t s, t;
 				char *p;
 
 				/* Double the buffer; watch for overflow. */
-				s = t = a->buffer_size;
+				s = t = filter->buffer_size;
+				if (s == 0)
+					s = min;
 				while (s < min) {
 					t *= 2;
 					if (t <= s) { /* Integer overflow! */
-						archive_set_error(&a->archive,
-						    ENOMEM,
+						archive_set_error(
+							&filter->archive->archive,
+							ENOMEM,
 						    "Unable to allocate copy buffer");
-						a->fatal = 1;
+						filter->fatal = 1;
 						if (avail != NULL)
 							*avail = ARCHIVE_FATAL;
 						return (NULL);
@@ -902,39 +894,41 @@ __archive_read_ahead(struct archive_read
 				/* Now s >= min, so allocate a new buffer. */
 				p = (char *)malloc(s);
 				if (p == NULL) {
-					archive_set_error(&a->archive, ENOMEM,
+					archive_set_error(
+						&filter->archive->archive,
+						ENOMEM,
 					    "Unable to allocate copy buffer");
-					a->fatal = 1;
+					filter->fatal = 1;
 					if (avail != NULL)
 						*avail = ARCHIVE_FATAL;
 					return (NULL);
 				}
 				/* Move data into newly-enlarged buffer. */
-				if (a->avail > 0)
-					memmove(p, a->next, a->avail);
-				free(a->buffer);
-				a->next = a->buffer = p;
-				a->buffer_size = s;
+				if (filter->avail > 0)
+					memmove(p, filter->next, filter->avail);
+				free(filter->buffer);
+				filter->next = filter->buffer = p;
+				filter->buffer_size = s;
 			}
 
 			/* We can add client data to copy buffer. */
 			/* First estimate: copy to fill rest of buffer. */
-			tocopy = (a->buffer + a->buffer_size)
-			    - (a->next + a->avail);
+			tocopy = (filter->buffer + filter->buffer_size)
+			    - (filter->next + filter->avail);
 			/* Don't waste time buffering more than we need to. */
-			if (tocopy + a->avail > min)
-				tocopy = min - a->avail;
+			if (tocopy + filter->avail > min)
+				tocopy = min - filter->avail;
 			/* Don't copy more than is available. */
-			if (tocopy > a->client_avail)
-				tocopy = a->client_avail;
+			if (tocopy > filter->client_avail)
+				tocopy = filter->client_avail;
 
-			memcpy(a->next + a->avail, a->client_next,
+			memcpy(filter->next + filter->avail, filter->client_next,
 			    tocopy);
 			/* Remove this data from client buffer. */
-			a->client_next += tocopy;
-			a->client_avail -= tocopy;
+			filter->client_next += tocopy;
+			filter->client_avail -= tocopy;
 			/* add it to copy buffer. */
-			a->avail += tocopy;
+			filter->avail += tocopy;
 		}
 	}
 }
@@ -953,16 +947,25 @@ __archive_read_ahead(struct archive_read
 ssize_t
 __archive_read_consume(struct archive_read *a, size_t request)
 {
-	if (a->avail > 0) {
+	ssize_t r;
+	r = __archive_read_filter_consume(a->filter, request);
+	a->archive.file_position += r;
+	return (r);
+}
+
+ssize_t
+__archive_read_filter_consume(struct archive_read_filter * filter,
+    size_t request)
+{
+	if (filter->avail > 0) {
 		/* Read came from copy buffer. */
-		a->next += request;
-		a->avail -= request;
+		filter->next += request;
+		filter->avail -= request;
 	} else {
 		/* Read came from client buffer. */
-		a->client_next += request;
-		a->client_avail -= request;
+		filter->client_next += request;
+		filter->client_avail -= request;
 	}
-	a->archive.file_position += request;
 	return (request);
 }
 
@@ -976,23 +979,29 @@ __archive_read_consume(struct archive_re
 int64_t
 __archive_read_skip(struct archive_read *a, int64_t request)
 {
+	return (__archive_read_filter_skip(a->filter, request));
+}
+
+int64_t
+__archive_read_filter_skip(struct archive_read_filter *filter, int64_t request)
+{
 	off_t bytes_skipped, total_bytes_skipped = 0;
 	size_t min;
 
-	if (a->fatal)
+	if (filter->fatal)
 		return (-1);
 	/*
 	 * If there is data in the buffers already, use that first.
 	 */
-	if (a->avail > 0) {
-		min = minimum(request, (off_t)a->avail);
-		bytes_skipped = __archive_read_consume(a, min);
+	if (filter->avail > 0) {
+		min = minimum(request, (off_t)filter->avail);
+		bytes_skipped = __archive_read_consume(filter->archive, min);
 		request -= bytes_skipped;
 		total_bytes_skipped += bytes_skipped;
 	}
-	if (a->client_avail > 0) {
-		min = minimum(request, (off_t)a->client_avail);
-		bytes_skipped = __archive_read_consume(a, min);
+	if (filter->client_avail > 0) {
+		min = minimum(request, (off_t)filter->client_avail);
+		bytes_skipped = __archive_read_consume(filter->archive, min);
 		request -= bytes_skipped;
 		total_bytes_skipped += bytes_skipped;
 	}
@@ -1002,23 +1011,22 @@ __archive_read_skip(struct archive_read 
 	 * If a client_skipper was provided, try that first.
 	 */
 #if ARCHIVE_API_VERSION < 2
-	if ((a->source->skip != NULL) && (request < SSIZE_MAX)) {
+	if ((filter->skip != NULL) && (request < SSIZE_MAX)) {
 #else
-	if (a->source->skip != NULL) {
+	if (filter->skip != NULL) {
 #endif
-		bytes_skipped = (a->source->skip)(a->source, request);
+		bytes_skipped = (filter->skip)(filter, request);
 		if (bytes_skipped < 0) {	/* error */
-			a->client_total = a->client_avail = 0;
-			a->client_next = a->client_buff = NULL;
-			a->fatal = 1;
+			filter->client_total = filter->client_avail = 0;
+			filter->client_next = filter->client_buff = NULL;
+			filter->fatal = 1;
 			return (bytes_skipped);
 		}
+		filter->archive->archive.file_position += bytes_skipped;
 		total_bytes_skipped += bytes_skipped;
-		a->archive.file_position += bytes_skipped;
 		request -= bytes_skipped;
-		a->client_next = a->client_buff;
-		a->archive.raw_position += bytes_skipped;
-		a->client_avail = a->client_total = 0;
+		filter->client_next = filter->client_buff;
+		filter->client_avail = filter->client_total = 0;
 	}
 	/*
 	 * Note that client_skipper will usually not satisfy the
@@ -1029,18 +1037,20 @@ __archive_read_skip(struct archive_read 
 	while (request > 0) {
 		const void* dummy_buffer;
 		ssize_t bytes_read;
-		dummy_buffer = __archive_read_ahead(a, 1, &bytes_read);
+		dummy_buffer = __archive_read_ahead(filter->archive,
+		    1, &bytes_read);
 		if (bytes_read < 0)
 			return (bytes_read);
 		if (bytes_read == 0) {
 			/* We hit EOF before we satisfied the skip request. */
-			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			archive_set_error(&filter->archive->archive,
+			    ARCHIVE_ERRNO_MISC,
 			    "Truncated input file (need to skip %jd bytes)",
 			    (intmax_t)request);
 			return (ARCHIVE_FATAL);
 		}
 		min = (size_t)(minimum(bytes_read, request));
-		bytes_read = __archive_read_consume(a, min);
+		bytes_read = __archive_read_consume(filter->archive, min);
 		total_bytes_skipped += bytes_read;
 		request -= bytes_read;
 	}

Modified: head/lib/libarchive/archive_read_private.h
==============================================================================
--- head/lib/libarchive/archive_read_private.h	Thu Mar  5 01:59:49 2009	(r189388)
+++ head/lib/libarchive/archive_read_private.h	Thu Mar  5 02:19:42 2009	(r189389)
@@ -33,72 +33,80 @@
 #include "archive_private.h"
 
 struct archive_read;
-struct archive_reader;
-struct archive_read_source;
+struct archive_read_filter_bidder;
+struct archive_read_filter;
 
 /*
- * A "reader" knows how to provide blocks.  That can include something
- * that reads blocks from disk or socket or a transformation layer
- * that reads blocks from another source and transforms them.  This
- * includes decompression and decryption filters.
- *
- * How bidding works:
+ * How bidding works for filters:
  *   * The bid manager reads the first block from the current source.
  *   * It shows that block to each registered bidder.
- *   * The winning bidder is initialized (with the block and information
- *     about the source)
- *   * The winning bidder becomes the new source and the process repeats
- * This ends only when no reader provides a non-zero bid.
+ *   * The bid manager creates a new filter structure for the winning
+ *     bidder and gives the winning bidder a chance to initialize it.
+ *   * The new filter becomes the top filter in the archive_read structure
+ *     and we repeat the process.
+ * This ends only when no bidder provides a non-zero bid.
  */
-struct archive_reader {
-	/* Configuration data for the reader. */
+struct archive_read_filter_bidder {
+	/* Configuration data for the bidder. */
 	void *data;
-	/* Bidder is handed the initial block from its source. */
-	int (*bid)(struct archive_reader *, const void *buff, size_t);
-	/* Init() is given the archive, upstream source, and the initial
-	 * block above.  It returns a populated source structure. */
-	struct archive_read_source *(*init)(struct archive_read *,
-	    struct archive_reader *, struct archive_read_source *source,
-	    const void *, size_t);
-	/* Release the reader and any configuration data it allocated. */
-	int (*free)(struct archive_reader *);
+	/* Taste the upstream filter to see if we handle this. */
+	int (*bid)(struct archive_read_filter_bidder *,
+	    struct archive_read_filter *);
+	/* Initialize a newly-created filter. */
+	int (*init)(struct archive_read_filter *);
+	/* Release the bidder's configuration data. */
+	int (*free)(struct archive_read_filter_bidder *);
 };
 
 /*
- * A "source" is an instance of a reader.  This structure is
- * allocated and initialized by the init() method of a reader
- * above.
+ * This structure is allocated within the archive_read core
+ * and initialized by archive_read and the init() method of the
+ * corresponding bidder above.
  */
-struct archive_read_source {
-	/* Essentially all sources will need these values, so
+struct archive_read_filter {
+	/* Essentially all filters will need these values, so
 	 * just declare them here. */
-	struct archive_reader *reader; /* Reader that I'm an instance of. */
-	struct archive_read_source *upstream; /* Who I get blocks from. */
-	struct archive_read *archive; /* associated archive. */
+	struct archive_read_filter_bidder *bidder; /* My bidder. */
+	struct archive_read_filter *upstream; /* Who I read from. */
+	struct archive_read *archive; /* Associated archive. */
 	/* Return next block. */
-	ssize_t (*read)(struct archive_read_source *, const void **);
+	ssize_t (*read)(struct archive_read_filter *, const void **);
 	/* Skip forward this many bytes. */
-	int64_t (*skip)(struct archive_read_source *self, int64_t request);
-	/* Close (recursively) and free(self). */
-	int (*close)(struct archive_read_source *self);
+	int64_t (*skip)(struct archive_read_filter *self, int64_t request);
+	/* Close (just this filter) and free(self). */
+	int (*close)(struct archive_read_filter *self);
 	/* My private data. */
 	void *data;
+
+	const char	*name;
+	int		 code;
+
+	/* Used by reblocking logic. */
+	char		*buffer;
+	size_t		 buffer_size;
+	char		*next;		/* Current read location. */
+	size_t		 avail;		/* Bytes in my buffer. */
+	const void	*client_buff;	/* Client buffer information. */
+	size_t		 client_total;
+	const char	*client_next;
+	size_t		 client_avail;
+	int64_t		 position;
+	char		 end_of_file;
+	char		 fatal;
 };
 
 /*
- * The client source is almost the same as an internal source.
+ * The client looks a lot like a filter, so we just wrap it here.
  *
- * TODO: Make archive_read_source and archive_read_client identical so
+ * TODO: Make archive_read_filter and archive_read_client identical so
  * that users of the library can easily register their own
  * transformation filters.  This will probably break the API/ABI and
- * so should be deferred until libarchive 3.0.
+ * so should be deferred at least until libarchive 3.0.
  */
 struct archive_read_client {
-	archive_open_callback	*opener;
 	archive_read_callback	*reader;
 	archive_skip_callback	*skipper;
 	archive_close_callback	*closer;
-	void			*data;
 };
 
 struct archive_read {
@@ -122,28 +130,15 @@ struct archive_read {
 	/* Callbacks to open/read/write/close client archive stream. */
 	struct archive_read_client client;
 
-	/* Registered readers. */
-	struct archive_reader readers[8];
+	/* Registered filter bidders. */
+	struct archive_read_filter_bidder bidders[8];
 
-	/* Source */
-	struct archive_read_source *source;
+	/* Last filter in chain */
+	struct archive_read_filter *filter;
 
 	/* File offset of beginning of most recently-read header. */
 	off_t		  header_position;
 
-
-	/* Used by reblocking logic. */
-	char		*buffer;
-	size_t		 buffer_size;
-	char		*next;		/* Current read location. */
-	size_t		 avail;		/* Bytes in my buffer. */
-	const void	*client_buff;	/* Client buffer information. */
-	size_t		 client_total;
-	const char	*client_next;
-	size_t		 client_avail;
-	char		 end_of_file;
-	char		 fatal;
-
 	/*
 	 * Format detection is mostly the same as compression
 	 * detection, with one significant difference: The bidders
@@ -177,13 +172,14 @@ int	__archive_read_register_format(struc
 	    int (*read_data_skip)(struct archive_read *),
 	    int (*cleanup)(struct archive_read *));
 
-struct archive_reader
-	*__archive_read_get_reader(struct archive_read *a);
+struct archive_read_filter_bidder
+	*__archive_read_get_bidder(struct archive_read *a);
 
-const void
-	*__archive_read_ahead(struct archive_read *, size_t, ssize_t *);
-ssize_t
-	__archive_read_consume(struct archive_read *, size_t);
-int64_t
-	__archive_read_skip(struct archive_read *, int64_t);
+const void *__archive_read_ahead(struct archive_read *, size_t, ssize_t *);
+const void *__archive_read_filter_ahead(struct archive_read_filter *,
+    size_t, ssize_t *);
+ssize_t	__archive_read_consume(struct archive_read *, size_t);
+ssize_t	__archive_read_filter_consume(struct archive_read_filter *, size_t);
+int64_t	__archive_read_skip(struct archive_read *, int64_t);
+int64_t	__archive_read_filter_skip(struct archive_read_filter *, int64_t);
 #endif

Modified: head/lib/libarchive/archive_read_support_compression_bzip2.c
==============================================================================
--- head/lib/libarchive/archive_read_support_compression_bzip2.c	Thu Mar  5 01:59:49 2009	(r189388)
+++ head/lib/libarchive/archive_read_support_compression_bzip2.c	Thu Mar  5 02:19:42 2009	(r189389)
@@ -57,9 +57,9 @@ struct private_data {
 	char		 eof; /* True = found end of compressed data. */
 };
 
-/* Bzip2 source */
-static ssize_t	bzip2_source_read(struct archive_read_source *, const void **);
-static int	bzip2_source_close(struct archive_read_source *);
+/* Bzip2 filter */
+static ssize_t	bzip2_filter_read(struct archive_read_filter *, const void **);
+static int	bzip2_filter_close(struct archive_read_filter *);
 #endif
 
 /*
@@ -68,17 +68,15 @@ static int	bzip2_source_close(struct arc
  * error messages.)  So the bid framework here gets compiled even
  * if bzlib is unavailable.
  */
-static int	bzip2_reader_bid(struct archive_reader *, const void *, size_t);
-static struct archive_read_source *bzip2_reader_init(struct archive_read *,
-    struct archive_reader *, struct archive_read_source *,
-    const void *, size_t);
-static int	bzip2_reader_free(struct archive_reader *);
+static int	bzip2_reader_bid(struct archive_read_filter_bidder *, struct archive_read_filter *);
+static int	bzip2_reader_init(struct archive_read_filter *);
+static int	bzip2_reader_free(struct archive_read_filter_bidder *);
 
 int
 archive_read_support_compression_bzip2(struct archive *_a)
 {
 	struct archive_read *a = (struct archive_read *)_a;
-	struct archive_reader *reader = __archive_read_get_reader(a);
+	struct archive_read_filter_bidder *reader = __archive_read_get_bidder(a);
 
 	if (reader == NULL)
 		return (ARCHIVE_FATAL);
@@ -91,7 +89,7 @@ archive_read_support_compression_bzip2(s
 }
 
 static int
-bzip2_reader_free(struct archive_reader *self){
+bzip2_reader_free(struct archive_read_filter_bidder *self){
 	(void)self; /* UNUSED */
 	return (ARCHIVE_OK);
 }
@@ -104,61 +102,38 @@ bzip2_reader_free(struct archive_reader 
  * from verifying as much as we would like.
  */
 static int
-bzip2_reader_bid(struct archive_reader *self, const void *buff, size_t len)
+bzip2_reader_bid(struct archive_read_filter_bidder *self, struct archive_read_filter *filter)
 {
 	const unsigned char *buffer;
+	size_t avail;
 	int bits_checked;
 
 	(void)self; /* UNUSED */
 
-	if (len < 1)
+	/* Minimal bzip2 archive is 14 bytes. */
+	buffer = __archive_read_filter_ahead(filter, 14, &avail);
+	if (buffer == NULL)
 		return (0);
 
-	buffer = (const unsigned char *)buff;
+	/* First three bytes must be "BZh" */
 	bits_checked = 0;
-	if (buffer[0] != 'B')	/* Verify first ID byte. */
+	if (buffer[0] != 'B' || buffer[1] != 'Z' || buffer[2] != 'h')
 		return (0);
-	bits_checked += 8;
-	if (len < 2)
-		return (bits_checked);
-
-	if (buffer[1] != 'Z')	/* Verify second ID byte. */
-		return (0);
-	bits_checked += 8;
-	if (len < 3)
-		return (bits_checked);
-
-	if (buffer[2] != 'h')	/* Verify third ID byte. */
-		return (0);
-	bits_checked += 8;
-	if (len < 4)
-		return (bits_checked);
+	bits_checked += 24;
 
+	/* Next follows a compression flag which must be an ASCII digit. */
 	if (buffer[3] < '1' || buffer[3] > '9')
 		return (0);
 	bits_checked += 5;
-	if (len < 5)
-		return (bits_checked);
 
 	/* After BZh[1-9], there must be either a data block
 	 * which begins with 0x314159265359 or an end-of-data
 	 * marker of 0x177245385090. */
-
-	if (buffer[4] == 0x31) {
-		/* Verify the data block signature. */
-		size_t s = len;
-		if (s > 10) s = 10;
-		if (memcmp(buffer + 4, "\x31\x41\x59\x26\x53\x59", s - 4) != 0)
-			return (0);
-		bits_checked += 8 * (s - 4);
-	} else if (buffer[4] == 0x17) {
-		/* Verify the end-of-data marker. */
-		size_t s = len;
-		if (s > 10) s = 10;
-		if (memcmp(buffer + 4, "\x17\x72\x45\x38\x50\x90", s - 4) != 0)
-			return (0);
-		bits_checked += 8 * (s - 4);
-	} else
+	if (memcmp(buffer + 4, "\x31\x41\x59\x26\x53\x59", 6) == 0)
+		bits_checked += 48;
+	else if (memcmp(buffer + 4, "\x17\x72\x45\x38\x50\x90", 6) == 0)
+		bits_checked += 48;
+	else
 		return (0);
 
 	return (bits_checked);
@@ -171,19 +146,13 @@ bzip2_reader_bid(struct archive_reader *
  * decompression.  We can, however, still detect compressed archives
  * and emit a useful message.
  */
-static struct archive_read_source *
-bzip2_reader_init(struct archive_read *a, struct archive_reader *reader,
-    struct archive_read_source *upstream, const void *buff, size_t n)
+static int
+bzip2_reader_init(struct archive_read_filter *self)
 {
-	(void)a;	/* UNUSED */
-	(void)reader;	/* UNUSED */
-	(void)upstream; /* UNUSED */
-	(void)buff;	/* UNUSED */
-	(void)n;	/* UNUSED */
 
-	archive_set_error(&a->archive, -1,
+	archive_set_error(&self->archive->archive, -1,
 	    "This version of libarchive was compiled without bzip2 support");
-	return (NULL);
+	return (ARCHIVE_FATAL);
 }
 
 
@@ -192,67 +161,45 @@ bzip2_reader_init(struct archive_read *a
 /*
  * Setup the callbacks.
  */
-static struct archive_read_source *
-bzip2_reader_init(struct archive_read *a, struct archive_reader *reader,
-    struct archive_read_source *upstream, const void *buff, size_t n)
+static int
+bzip2_reader_init(struct archive_read_filter *self)
 {
 	static const size_t out_block_size = 64 * 1024;
 	void *out_block;
-	struct archive_read_source *self;
 	struct private_data *state;
 
-	(void)reader; /* UNUSED */
+	self->code = ARCHIVE_COMPRESSION_BZIP2;
+	self->name = "bzip2";
 
-	a->archive.compression_code = ARCHIVE_COMPRESSION_BZIP2;
-	a->archive.compression_name = "bzip2";
-
-	self = calloc(sizeof(*self), 1);
 	state = (struct private_data *)calloc(sizeof(*state), 1);
 	out_block = (unsigned char *)malloc(out_block_size);
 	if (self == NULL || state == NULL || out_block == NULL) {
-		archive_set_error(&a->archive, ENOMEM,
-		    "Can't allocate data for %s decompression",
-		    a->archive.compression_name);
+		archive_set_error(&self->archive->archive, ENOMEM,
+		    "Can't allocate data for bzip2 decompression");
 		free(out_block);
 		free(state);
-		free(self);
-		return (NULL);
+		return (ARCHIVE_FATAL);
 	}
 
-
-	self->archive = a;
 	self->data = state;
 	state->out_block_size = out_block_size;
 	state->out_block = out_block;
-	self->upstream = upstream;
-	self->read = bzip2_source_read;
+	self->read = bzip2_filter_read;
 	self->skip = NULL; /* not supported */
-	self->close = bzip2_source_close;
-
-	/*
-	 * A bug in bzlib.h: stream.next_in should be marked 'const'
-	 * but isn't (the library never alters data through the

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list