packages feed

libarchive-clib 3.8.8 → 3.8.9

raw patch · 84 files changed

+10148/−9337 lines, 84 files

Files

c/archive.h view
@@ -34,7 +34,7 @@  * assert that ARCHIVE_VERSION_NUMBER >= 2012108.  */ /* Note: Compiler will complain if this does not match archive_entry.h! */-#define	ARCHIVE_VERSION_NUMBER 3008008+#define	ARCHIVE_VERSION_NUMBER 3008009  #include <sys/stat.h> #include <stddef.h>  /* for wchar_t */@@ -177,7 +177,7 @@ /*  * Textual name/version of the library, useful for version displays.  */-#define	ARCHIVE_VERSION_ONLY_STRING "3.8.8"+#define	ARCHIVE_VERSION_ONLY_STRING "3.8.9" #define	ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING __LA_DECL const char *	archive_version_string(void); 
c/archive_acl.c view
@@ -1516,7 +1516,7 @@ 		const char *end; 	} field[6], name; -	const char *s, *st;+	const char *s, *st, *text_end; 	int numfields, fields, n, r, sol, ret; 	int type, types, tag, permset, id; 	size_t len;@@ -1539,6 +1539,7 @@  	ret = ARCHIVE_OK; 	types = 0;+	text_end = (text == NULL) ? text : text + length;  	while (text != NULL && length > 0 && *text != '\0') { 		/*@@ -1563,6 +1564,18 @@ 		if (field[0].start == NULL || field[0].end == NULL) { 			/* This should never happen */ 			return (ARCHIVE_FATAL);+		}++		if (field[0].start == text_end) {+			/*+			 * Empty entry: next_field() consumed the rest of the+			 * buffer as separators or whitespace, leaving+			 * field[0].start one past the end.  'text' is not+			 * guaranteed to be NUL terminated, so the byte after it+			 * must not be dereferenced.+			 */+			ret = ARCHIVE_WARN;+			continue; 		}  		if (*(field[0].start) == '#') {
c/archive_acl_private.h view
@@ -27,7 +27,9 @@ #define ARCHIVE_ACL_PRIVATE_H_INCLUDED  #ifndef __LIBARCHIVE_BUILD+#ifndef __LIBARCHIVE_TEST #error This header is only to be used internally to libarchive.+#endif #endif  #include "archive_string.h"
c/archive_check_magic.c view
@@ -85,6 +85,7 @@ 	case ARCHIVE_STATE_NEW:		return ("new"); 	case ARCHIVE_STATE_HEADER:	return ("header"); 	case ARCHIVE_STATE_DATA:	return ("data");+	case ARCHIVE_STATE_DATA_RECOVERY: return ("data_recovery"); 	case ARCHIVE_STATE_EOF:		return ("eof"); 	case ARCHIVE_STATE_CLOSED:	return ("closed"); 	case ARCHIVE_STATE_FATAL:	return ("fatal");
c/archive_entry.c view
@@ -1562,17 +1562,21 @@ archive_entry_copy_mac_metadata(struct archive_entry *entry,     const void *p, size_t s) {-  free(entry->mac_metadata);-  if (p == NULL || s == 0) {-    entry->mac_metadata = NULL;-    entry->mac_metadata_size = 0;-  } else {-    entry->mac_metadata_size = s;-    entry->mac_metadata = malloc(s);-    if (entry->mac_metadata == NULL)-      abort();-    memcpy(entry->mac_metadata, p, s);-  }+	void *metadata;++	if (p == NULL || s == 0) {+		free(entry->mac_metadata);+		entry->mac_metadata = NULL;+		entry->mac_metadata_size = 0;+	} else {+		metadata = malloc(s);+		if (metadata == NULL)+			abort();+		memcpy(metadata, p, s);+		free(entry->mac_metadata);+		entry->mac_metadata = metadata;+		entry->mac_metadata_size = s;+	} }  /* Digest handling */
c/archive_entry.h view
@@ -28,7 +28,7 @@ #define	ARCHIVE_ENTRY_H_INCLUDED  /* Note: Compiler will complain if this does not match archive.h! */-#define	ARCHIVE_VERSION_NUMBER 3008008+#define	ARCHIVE_VERSION_NUMBER 3008009  /*  * Note: archive_entry.h is for use outside of libarchive; the@@ -666,7 +666,7 @@ 	    la_int64_t /* offset */, la_int64_t /* length */);  /*- * To retrieve the xattr list, first "reset", then repeatedly ask for the+ * To retrieve the sparse list, first "reset", then repeatedly ask for the  * "next" entry.  */ 
c/archive_entry_link_resolver.c view
@@ -41,6 +41,7 @@  #include "archive.h" #include "archive_entry.h"+#include "archive_integer.h"  /*  * This is mostly a pretty straightforward hash table implementation.@@ -387,7 +388,7 @@ 	}  	/* If the links cache is getting too full, enlarge the hash table. */-	if (res->number_entries > res->number_buckets * 2)+	if (res->number_entries / 2 > res->number_buckets) 		grow_hash(res);  	hash = (size_t)(archive_entry_dev(entry) ^ archive_entry_ino64(entry));@@ -413,8 +414,7 @@ 	size_t i, bucket;  	/* Try to enlarge the bucket list. */-	new_size = res->number_buckets * 2;-	if (new_size < res->number_buckets)+	if (archive_ckd_mul_size(&new_size, res->number_buckets, 2)) 		return; 	new_buckets = calloc(new_size, sizeof(struct links_entry *)); 
c/archive_entry_xattr.c view
@@ -96,11 +96,11 @@ 	if ((xp->name = strdup(name)) == NULL) 		__archive_errx(1, "Out of memory"); -	if ((xp->value = malloc(size)) != NULL) {-		memcpy(xp->value, value, size);-		xp->size = size;-	} else-		xp->size = 0;+	if ((xp->value = malloc(size)) == NULL)+		__archive_errx(1, "Out of memory");++	memcpy(xp->value, value, size);+	xp->size = size;  	xp->next = entry->xattr_head; 	entry->xattr_head = xp;
c/archive_integer.h view
@@ -49,6 +49,9 @@ #ifdef HAVE_STDINT_H #include <stdint.h> #endif+#ifdef HAVE_TIME_H+#include <time.h>+#endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif@@ -243,5 +246,22 @@ 	return 0; #endif }++#if !defined(TIME_MAX)+#define TIME_MAX (((time_t)0 < (time_t)-1) ? (time_t)~0 :		\+	    sizeof(time_t) == sizeof(long long) ? (time_t)LLONG_MAX :	\+	    sizeof(time_t) == sizeof(long) ? (time_t)LONG_MAX :		\+	    sizeof(time_t) == sizeof(int) ? (time_t)INT_MAX :		\+	    sizeof(time_t) == sizeof(short) ? (time_t)SHRT_MAX :	\+	    1 /* I give up */)+#endif+#if !defined(TIME_MIN)+#define TIME_MIN (((time_t)0 < (time_t)-1) ? (time_t)0 :		\+	    sizeof(time_t) == sizeof(long long) ? (time_t)LLONG_MIN :	\+	    sizeof(time_t) == sizeof(long) ? (time_t)LONG_MIN :		\+	    sizeof(time_t) == sizeof(int) ? (time_t)INT_MIN :		\+	    sizeof(time_t) == sizeof(short) ? (time_t)SHRT_MIN :	\+	    -1 /* I give up */)+#endif  #endif
c/archive_options.c view
@@ -33,7 +33,7 @@  static char * parse_option(char **str,-    char **mod, char **opt, char **val);+    const char **mod, const char **opt, const char **val);  int _archive_set_option(struct archive *a,@@ -102,8 +102,8 @@     unsigned int magic, const char *fn, option_handler use_option) { 	int allok = 1, anyok = 0, ignore_mod_err = 0, r;-	char *data;-	char *s, *mod, *opt, *val;+	char *data, *s;+	const char *mod, *opt, *val;  	archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn); @@ -168,10 +168,10 @@ }  static char *-parse_option(char **s, char **m, char **o, char **v)+parse_option(char **s, const char **m, const char **o, const char **v) {-	char *end, *mod, *opt, *val;-	char *p;+	const char *mod, *val;+	char *end, *opt, *p;  	end = NULL; 	mod = NULL;
c/archive_pathmatch.c view
@@ -337,7 +337,7 @@ 			} 			if (*end == L']') { 				/* We found [...], try to match it. */-				if (!pm_list_w(p + 1, end, *s, flags))+				if (*s == L'\0' || !pm_list_w(p + 1, end, *s, flags)) 					return (0); 				p = end; /* Jump to trailing ']' char. */ 				break;
c/archive_private.h view
@@ -61,12 +61,38 @@ #define	ARCHIVE_READ_DISK_MAGIC (0xbadb0c5U) #define	ARCHIVE_MATCH_MAGIC	(0xcad11c9U) +/*+ * Having the state be a bitmask makes it easy to check+ * for combinations of allowed states.  These should+ * generally only be used in public API entry points,+ * primarily in archive_read.c, archive_write.c, etc.+ * Internal callbacks can rely on the core machinery+ * to only call them when appropriate.+ *+ * Generally checked via `__archive_check_magic()`.+ */++/* Newly created archive object, not yet opened */ #define	ARCHIVE_STATE_NEW	1U+/* Archive is ready to read a header. */ #define	ARCHIVE_STATE_HEADER	2U+/* A header has been read: client can ask for data+ * or they can ask for the next header and+ * we'll automatically skip the remaining data. */ #define	ARCHIVE_STATE_DATA	4U+/* Similar to STATE_DATA but after a FAILED header:+ * the client may not read data, but they may ask+ * for the next header and we'll recover. */+#define	ARCHIVE_STATE_DATA_RECOVERY	8U+/* End-of-archive has been reached.  Client can only+ * close or free the archive. */ #define	ARCHIVE_STATE_EOF	0x10U+/* Archive is closed; client is only allowed to free the archive. */ #define	ARCHIVE_STATE_CLOSED	0x20U+/* Archive is in a FATAL error state: a close request+ * is permitted but ignored. */ #define	ARCHIVE_STATE_FATAL	0x8000U+/* Any valid (non-fatal) state. */ #define	ARCHIVE_STATE_ANY	(0xFFFFU & ~ARCHIVE_STATE_FATAL)  struct archive_vtable {
c/archive_read.c view
@@ -103,7 +103,12 @@  	a->archive.state = ARCHIVE_STATE_NEW; 	a->entry = archive_entry_new2(&a->archive);+	if (a->entry == NULL) {+		free(a);+		return (NULL);+	} 	a->archive.vtable = &archive_read_vtable;+	a->entry_bytes_declared = -1;  	a->passphrases.last = &a->passphrases.first; @@ -135,12 +140,16 @@     archive_open_callback *client_opener, archive_read_callback *client_reader,     archive_close_callback *client_closer) {+	int r;+ 	/* Old archive_read_open() is just a thin shell around 	 * archive_read_open1. */ 	archive_read_set_open_callback(a, client_opener); 	archive_read_set_read_callback(a, client_reader); 	archive_read_set_close_callback(a, client_closer);-	archive_read_set_callback_data(a, client_data);+	r = archive_read_set_callback_data(a, client_data);+	if (r < 0)+		return (r); 	return archive_read_open1(a); } @@ -152,9 +161,13 @@     archive_skip_callback *client_skipper,     archive_close_callback *client_closer) {+	int r;+ 	/* Old archive_read_open2() is just a thin shell around 	 * archive_read_open1. */-	archive_read_set_callback_data(a, client_data);+	r = archive_read_set_callback_data(a, client_data);+	if (r < 0)+		return (r); 	archive_read_set_open_callback(a, client_opener); 	archive_read_set_read_callback(a, client_reader); 	archive_read_set_skip_callback(a, client_skipper);@@ -163,28 +176,28 @@ }  static ssize_t-client_read_proxy(struct archive_read_filter *self, const void **buff)+client_read_proxy(struct archive_read_filter *f, const void **buff) { 	ssize_t r;-	r = (self->archive->client.reader)(&self->archive->archive,-	    self->data, buff);+	r = (f->archive->client.reader)(&f->archive->archive,+	    f->data, buff); 	return (r); }  static int64_t-client_skip_proxy(struct archive_read_filter *self, int64_t request)+client_skip_proxy(struct archive_read_filter *f, int64_t request) { 	if (request < 0) 		__archive_errx(1, "Negative skip requested"); 	if (request == 0) 		return 0; -	if (self->archive->client.skipper != NULL) {+	if (f->archive->client.skipper != NULL) { 		int64_t total = 0; 		for (;;) { 			int64_t get, ask = request;-			get = (self->archive->client.skipper)-				(&self->archive->archive, self->data, ask);+			get = (f->archive->client.skipper)+				(&f->archive->archive, f->data, ask); 			total += get; 			if (get == 0 || get == request) 				return (total);@@ -192,7 +205,7 @@ 				return ARCHIVE_FATAL; 			request -= get; 		}-	} else if (self->archive->client.seeker != NULL+	} else if (f->archive->client.seeker != NULL 		&& request > 64 * 1024) { 		/* If the client provided a seeker but not a skipper, 		 * we can use the seeker to skip forward.@@ -205,9 +218,9 @@ 		 * to just reading and discarding.  That's why we 		 * only do this for skips of over 64k. 		 */-		int64_t before = self->position;-		int64_t after = (self->archive->client.seeker)-		    (&self->archive->archive, self->data, request, SEEK_CUR);+		int64_t before = f->position;+		int64_t after = (f->archive->client.seeker)+		    (&f->archive->archive, f->data, request, SEEK_CUR); 		if (after != before + request) 			return ARCHIVE_FATAL; 		return after - before;@@ -216,20 +229,20 @@ }  static int64_t-client_seek_proxy(struct archive_read_filter *self, int64_t offset, int whence)+client_seek_proxy(struct archive_read_filter *f, int64_t offset, int whence) { 	/* DO NOT use the skipper here!  If we transparently handled 	 * forward seek here by using the skipper, that will break 	 * other libarchive code that assumes a successful forward 	 * seek means it can also seek backwards. 	 */-	if (self->archive->client.seeker == NULL) {-		archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+	if (f->archive->client.seeker == NULL) {+		archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, 		    "Current client reader does not support seeking a device"); 		return (ARCHIVE_FAILED); 	}-	return (self->archive->client.seeker)(&self->archive->archive,-	    self->data, offset, whence);+	return (f->archive->client.seeker)(&f->archive->archive,+	    f->data, offset, whence); }  static int@@ -251,21 +264,21 @@ }  static int-client_close_proxy(struct archive_read_filter *self)+client_close_proxy(struct archive_read_filter *f) {-	return read_client_close_proxy(self->archive);+	return read_client_close_proxy(f->archive); }  static int-client_switch_proxy(struct archive_read_filter *self, unsigned int iindex)+client_switch_proxy(struct archive_read_filter *f, unsigned int iindex) { 	struct archive_read *a; 	int r1 = ARCHIVE_OK, r2 = ARCHIVE_OK; 	void *data2; -	while (self->upstream != NULL)-		self = self->upstream;-	a = self->archive;+	while (f->upstream != NULL)+		f = f->upstream;+	a = f->archive;  	/* Don't do anything if already in the specified data node */ 	if (a->client.cursor == iindex)@@ -276,19 +289,19 @@ 	if (a->client.switcher != NULL) 	{ 		r1 = r2 = (a->client.switcher)-			((struct archive *)a, self->data, data2);-		self->data = data2;+			((struct archive *)a, f->data, data2);+		f->data = data2; 	} 	else 	{ 		/* Attempt to call close and open instead */ 		if (a->client.closer != NULL) 			r1 = (a->client.closer)-				((struct archive *)a, self->data);-		self->data = data2;+				((struct archive *)a, f->data);+		f->data = data2; 		if (a->client.opener != NULL) 			r2 = (a->client.opener)-				((struct archive *)a, self->data);+				((struct archive *)a, f->data); 	} 	return (r1 < r2) ? r1 : r2; }@@ -469,7 +482,7 @@ archive_read_open1(struct archive *_a) { 	struct archive_read *a = (struct archive_read *)_a;-	struct archive_read_filter *filter, *tmp;+	struct archive_read_filter *f, *tmp; 	int slot, e = ARCHIVE_OK;  	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,@@ -493,23 +506,23 @@ 		} 	} -	filter = calloc(1, sizeof(*filter));-	if (filter == NULL)+	f = calloc(1, sizeof(*f));+	if (f == NULL) 		return (ARCHIVE_FATAL);-	filter->bidder = NULL;-	filter->upstream = NULL;-	filter->archive = a;-	filter->data = a->client.dataset[0].data;-	filter->vtable = &none_reader_vtable;-	filter->name = "none";-	filter->code = ARCHIVE_FILTER_NONE;-	filter->can_skip = 1;-	filter->can_seek = 1;+	f->bidder = NULL;+	f->upstream = NULL;+	f->archive = a;+	f->data = a->client.dataset[0].data;+	f->vtable = &none_reader_vtable;+	f->name = "none";+	f->code = ARCHIVE_FILTER_NONE;+	f->can_skip = 1;+	f->can_seek = 1;  	a->client.dataset[0].begin_position = 0; 	if (!a->filter || !a->bypass_filter_bidding) 	{-		a->filter = filter;+		a->filter = f; 		/* Build out the input pipeline. */ 		e = choose_filters(a); 		if (e < ARCHIVE_WARN) {@@ -523,7 +536,7 @@ 		tmp = a->filter; 		while (tmp->upstream) 			tmp = tmp->upstream;-		tmp->upstream = filter;+		tmp->upstream = f; 	}  	if (!a->format)@@ -558,7 +571,7 @@ { 	int number_bidders, i, bid, best_bid, number_filters; 	struct archive_read_filter_bidder *bidder, *best_bidder;-	struct archive_read_filter *filter;+	struct archive_read_filter *f; 	ssize_t avail; 	int r; @@ -590,13 +603,13 @@ 			return (ARCHIVE_OK); 		} -		filter = calloc(1, sizeof(*filter));-		if (filter == NULL)+		f = calloc(1, sizeof(*f));+		if (f == NULL) 			return (ARCHIVE_FATAL);-		filter->bidder = best_bidder;-		filter->archive = a;-		filter->upstream = a->filter;-		a->filter = filter;+		f->bidder = best_bidder;+		f->archive = a;+		f->upstream = a->filter;+		a->filter = f; 		r = (best_bidder->vtable->init)(a->filter); 		if (r != ARCHIVE_OK) { 			__archive_read_free_filters(a);@@ -626,7 +639,8 @@ 	int r1 = ARCHIVE_OK, r2;  	archive_check_magic(_a, ARCHIVE_READ_MAGIC,-	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,+	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA |+	    ARCHIVE_STATE_DATA_RECOVERY, 	    "archive_read_next_header");  	archive_entry_clear(entry);@@ -635,8 +649,12 @@ 	/* 	 * If client didn't consume entire data, skip any remainder 	 * (This is especially important for GNU incremental directories.)+	 * A header that failed to parse (DATA_RECOVERY) still needs the+	 * same treatment: whatever of its body the format reader left+	 * unconsumed must be skipped before we can read the next header. 	 */-	if (a->archive.state == ARCHIVE_STATE_DATA) {+	if (a->archive.state == ARCHIVE_STATE_DATA ||+	    a->archive.state == ARCHIVE_STATE_DATA_RECOVERY) { 		r1 = archive_read_data_skip(&a->archive); 		if (r1 == ARCHIVE_EOF) 			archive_set_error(&a->archive, EIO,@@ -674,8 +692,26 @@ 	case ARCHIVE_FATAL: 		a->archive.state = ARCHIVE_STATE_FATAL; 		break;+	case ARCHIVE_FAILED:+		/*+		 * This entry's header could not be parsed, so its metadata+		 * cannot be trusted.  ARCHIVE_STATE_DATA_RECOVERY still+		 * permits skipping past it (the format reader is+		 * responsible for ensuring that's actually possible), but+		 * blocks archive_read_data() and friends, which all check+		 * for ARCHIVE_STATE_DATA specifically and would otherwise+		 * return content for an entry we don't actually understand.+		 */+		a->archive.state = ARCHIVE_STATE_DATA_RECOVERY;+		break; 	} +	if (r2 == ARCHIVE_OK || r2 == ARCHIVE_WARN)+		a->entry_bytes_declared = archive_entry_size_is_set(entry)+		    ? archive_entry_size(entry) : -1;+	else+		a->entry_bytes_declared = -1;+ 	__archive_reset_read_data(&a->archive);  	a->data_start_node = a->client.cursor;@@ -764,7 +800,7 @@  /*  * Returns 1 if the archive contains at least one encrypted entry.- * If the archive format not support encryption at all+ * If the archive format does not support encryption at all,  * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned.  * If for any other reason (e.g. not enough data read so far)  * we cannot say whether there are encrypted entries, then@@ -934,7 +970,8 @@ 	size_t size; 	int64_t offset; -	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,+	archive_check_magic(_a, ARCHIVE_READ_MAGIC,+	    ARCHIVE_STATE_DATA | ARCHIVE_STATE_DATA_RECOVERY, 	    "archive_read_data_skip");  	if (a->format->read_data_skip != NULL)@@ -966,11 +1003,9 @@ 	    "archive_seek_data_block");  	if (a->format->seek_data == NULL) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,-		    "Internal error: "-		    "No format_seek_data_block function registered");-		a->archive.state = ARCHIVE_STATE_FATAL;-		return (ARCHIVE_FATAL);+		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+		    "Cannot seek data with this format");+		return (ARCHIVE_FAILED); 	}  	r = (a->format->seek_data)(a, offset, whence);@@ -1347,13 +1382,13 @@ }  const void *-__archive_read_filter_ahead(struct archive_read_filter *filter,+__archive_read_filter_ahead(struct archive_read_filter *f,     size_t min, ssize_t *avail) { 	ssize_t bytes_read; 	size_t tocopy; -	if (filter->fatal) {+	if (f->fatal) { 		if (avail) 			*avail = ARCHIVE_FATAL; 		return (NULL);@@ -1370,79 +1405,79 @@ 		 * note that min == 0 is a perfectly well-defined 		 * request. 		 */-		if (filter->avail >= min && filter->avail > 0) {+		if (f->avail >= min && f->avail > 0) { 			if (avail != NULL)-				*avail = filter->avail;-			return (filter->next);+				*avail = f->avail;+			return (f->next); 		}  		/* 		 * We can satisfy directly from client buffer if everything 		 * currently in the copy buffer is still in the client buffer. 		 */-		if (filter->client_total >= filter->client_avail + filter->avail-		    && filter->client_avail + filter->avail >= min) {+		if (f->client_total >= f->client_avail + f->avail+		    && f->client_avail + f->avail >= min) { 			/* "Roll back" to client buffer. */-			filter->client_avail += filter->avail;-			filter->client_next -= filter->avail;+			f->client_avail += f->avail;+			f->client_next -= f->avail; 			/* Copy buffer is now empty. */-			filter->avail = 0;-			filter->next = filter->buffer;+			f->avail = 0;+			f->next = f->buffer; 			/* Return data from client buffer. */ 			if (avail != NULL)-				*avail = filter->client_avail;-			return (filter->client_next);+				*avail = f->client_avail;+			return (f->client_next); 		}  		/* Move data forward in copy buffer if necessary. */-		if (filter->next > filter->buffer &&-		    min > filter->buffer_size - (filter->next - filter->buffer)) {-			if (filter->avail > 0)-				memmove(filter->buffer, filter->next,-				    filter->avail);-			filter->next = filter->buffer;+		if (f->next > f->buffer &&+		    min > f->buffer_size - (f->next - f->buffer)) {+			if (f->avail > 0)+				memmove(f->buffer, f->next,+				    f->avail);+			f->next = f->buffer; 		}  		/* If we've used up the client data, get more. */-		if (filter->client_avail <= 0) {-			if (filter->end_of_file) {+		if (f->client_avail <= 0) {+			if (f->end_of_file) { 				if (avail != NULL)-					*avail = filter->avail;+					*avail = f->avail; 				return (NULL); 			}-			bytes_read = (filter->vtable->read)(filter,-			    &filter->client_buff);+			bytes_read = (f->vtable->read)(f,+			    &f->client_buff); 			if (bytes_read < 0) {		/* Read error. */-				filter->client_total = filter->client_avail = 0;-				filter->client_next =-				    filter->client_buff = NULL;-				filter->fatal = 1;+				f->client_total = f->client_avail = 0;+				f->client_next =+				    f->client_buff = NULL;+				f->fatal = 1; 				if (avail != NULL) 					*avail = ARCHIVE_FATAL; 				return (NULL); 			} 			if (bytes_read == 0) { 				/* Check for another client object first */-				if (filter->archive->client.cursor !=-				      filter->archive->client.nodes - 1) {-					if (client_switch_proxy(filter,-					    filter->archive->client.cursor + 1)+				if (f->archive->client.cursor !=+				      f->archive->client.nodes - 1) {+					if (client_switch_proxy(f,+					    f->archive->client.cursor + 1) 					    == ARCHIVE_OK) 						continue; 				} 				/* Premature end-of-file. */-				filter->client_total = filter->client_avail = 0;-				filter->client_next =-				    filter->client_buff = NULL;-				filter->end_of_file = 1;+				f->client_total = f->client_avail = 0;+				f->client_next =+				    f->client_buff = NULL;+				f->end_of_file = 1; 				/* Return whatever we do have. */ 				if (avail != NULL)-					*avail = filter->avail;+					*avail = f->avail; 				return (NULL); 			}-			filter->client_total = bytes_read;-			filter->client_avail = filter->client_total;-			filter->client_next = filter->client_buff;+			f->client_total = bytes_read;+			f->client_avail = f->client_total;+			f->client_next = f->client_buff; 		} else { 			/* 			 * We can't satisfy the request from the copy@@ -1452,67 +1487,66 @@ 			 */  			/* Ensure the buffer is big enough. */-			if (min > filter->buffer_size) {-				size_t s, t;+			if (min > f->buffer_size) {+				size_t s; 				char *p;  				/* Double the buffer; watch for overflow. */-				s = t = filter->buffer_size;+				s = f->buffer_size; 				if (s == 0) 					s = min; 				while (s < min) {-					t *= 2;-					if (t <= s) { /* Integer overflow! */+					if (archive_ckd_mul_size(&s, s, 2)) {+						/* Integer overflow! */ 						archive_set_error(-						    &filter->archive->archive,+						    &f->archive->archive, 						    ENOMEM, 						    "Unable to allocate copy" 						    " buffer");-						filter->fatal = 1;+						f->fatal = 1; 						if (avail != NULL) 							*avail = ARCHIVE_FATAL; 						return (NULL); 					}-					s = t; 				} 				/* Now s >= min, so allocate a new buffer. */ 				p = malloc(s); 				if (p == NULL) { 					archive_set_error(-						&filter->archive->archive,+						&f->archive->archive, 						ENOMEM, 					    "Unable to allocate copy buffer");-					filter->fatal = 1;+					f->fatal = 1; 					if (avail != NULL) 						*avail = ARCHIVE_FATAL; 					return (NULL); 				} 				/* Move data into newly-enlarged buffer. */-				if (filter->avail > 0)-					memmove(p, filter->next, filter->avail);-				free(filter->buffer);-				filter->next = filter->buffer = p;-				filter->buffer_size = s;+				if (f->avail > 0)+					memmove(p, f->next, f->avail);+				free(f->buffer);+				f->next = f->buffer = p;+				f->buffer_size = s; 			}  			/* We can add client data to copy buffer. */ 			/* First estimate: copy to fill rest of buffer. */-			tocopy = (filter->buffer + filter->buffer_size)-			    - (filter->next + filter->avail);+			tocopy = (f->buffer + f->buffer_size)+			    - (f->next + f->avail); 			/* Don't waste time buffering more than we need to. */-			if (tocopy + filter->avail > min)-				tocopy = min - filter->avail;+			if (tocopy + f->avail > min)+				tocopy = min - f->avail; 			/* Don't copy more than is available. */-			if (tocopy > filter->client_avail)-				tocopy = filter->client_avail;+			if (tocopy > f->client_avail)+				tocopy = f->client_avail; -			memcpy(filter->next + filter->avail,-			    filter->client_next, tocopy);+			memcpy(f->next + f->avail,+			    f->client_next, tocopy); 			/* Remove this data from client buffer. */-			filter->client_next += tocopy;-			filter->client_avail -= tocopy;+			f->client_next += tocopy;+			f->client_avail -= tocopy; 			/* add it to copy buffer. */-			filter->avail += tocopy;+			f->avail += tocopy; 		} 	} }@@ -1527,7 +1561,7 @@ }  int64_t-__archive_read_filter_consume(struct archive_read_filter * filter,+__archive_read_filter_consume(struct archive_read_filter *f,     int64_t request) { 	int64_t skipped;@@ -1537,13 +1571,13 @@ 	if (request == 0) 		return 0; -	skipped = advance_file_pointer(filter, request);+	skipped = advance_file_pointer(f, request); 	if (skipped == request) 		return (skipped); 	/* We hit EOF before we satisfied the skip request. */ 	if (skipped < 0)  /* Map error code to 0 for error message below. */ 		skipped = 0;-	archive_set_error(&filter->archive->archive,+	archive_set_error(&f->archive->archive, 	    ARCHIVE_ERRNO_MISC, 	    "Truncated input file (needed %jd bytes, only %jd available)", 	    (intmax_t)request, (intmax_t)skipped);@@ -1557,45 +1591,45 @@  * Returns a negative value if there's an I/O error.  */ static int64_t-advance_file_pointer(struct archive_read_filter *filter, int64_t request)+advance_file_pointer(struct archive_read_filter *f, int64_t request) { 	int64_t bytes_skipped, total_bytes_skipped = 0; 	ssize_t bytes_read; 	size_t min; -	if (filter->fatal)+	if (f->fatal) 		return (-1);  	/* Use up the copy buffer first. */-	if (filter->avail > 0) {-		min = (size_t)minimum(request, (int64_t)filter->avail);-		filter->next += min;-		filter->avail -= min;+	if (f->avail > 0) {+		min = (size_t)minimum(request, (int64_t)f->avail);+		f->next += min;+		f->avail -= min; 		request -= min;-		filter->position += min;+		f->position += min; 		total_bytes_skipped += min; 	}  	/* Then use up the client buffer. */-	if (filter->client_avail > 0) {-		min = (size_t)minimum(request, (int64_t)filter->client_avail);-		filter->client_next += min;-		filter->client_avail -= min;+	if (f->client_avail > 0) {+		min = (size_t)minimum(request, (int64_t)f->client_avail);+		f->client_next += min;+		f->client_avail -= min; 		request -= min;-		filter->position += min;+		f->position += min; 		total_bytes_skipped += min; 	} 	if (request == 0) 		return (total_bytes_skipped);  	/* If there's an optimized skip function, use it. */-	if (filter->can_skip != 0) {-		bytes_skipped = client_skip_proxy(filter, request);+	if (f->can_skip != 0) {+		bytes_skipped = client_skip_proxy(f, request); 		if (bytes_skipped < 0) {	/* error */-			filter->fatal = 1;+			f->fatal = 1; 			return (bytes_skipped); 		}-		filter->position += bytes_skipped;+		f->position += bytes_skipped; 		total_bytes_skipped += bytes_skipped; 		request -= bytes_skipped; 		if (request == 0)@@ -1604,37 +1638,37 @@  	/* Use ordinary reads as necessary to complete the request. */ 	for (;;) {-		bytes_read = (filter->vtable->read)(filter, &filter->client_buff);+		bytes_read = (f->vtable->read)(f, &f->client_buff); 		if (bytes_read < 0) {-			filter->client_buff = NULL;-			filter->fatal = 1;+			f->client_buff = NULL;+			f->fatal = 1; 			return (bytes_read); 		}  		if (bytes_read == 0) {-			if (filter->archive->client.cursor !=-			      filter->archive->client.nodes - 1) {-				if (client_switch_proxy(filter,-				    filter->archive->client.cursor + 1)+			if (f->archive->client.cursor !=+			      f->archive->client.nodes - 1) {+				if (client_switch_proxy(f,+				    f->archive->client.cursor + 1) 				    == ARCHIVE_OK) 					continue; 			}-			filter->client_buff = NULL;-			filter->end_of_file = 1;+			f->client_buff = NULL;+			f->end_of_file = 1; 			return (total_bytes_skipped); 		}  		if (bytes_read >= request) {-			filter->client_next =-			    ((const char *)filter->client_buff) + request;-			filter->client_avail = (size_t)(bytes_read - request);-			filter->client_total = bytes_read;+			f->client_next =+			    ((const char *)f->client_buff) + request;+			f->client_avail = (size_t)(bytes_read - request);+			f->client_total = bytes_read; 			total_bytes_skipped += request;-			filter->position += request;+			f->position += request; 			return (total_bytes_skipped); 		} -		filter->position += bytes_read;+		f->position += bytes_read; 		total_bytes_skipped += bytes_read; 		request -= bytes_read; 	}@@ -1650,23 +1684,23 @@ }  int64_t-__archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,+__archive_read_filter_seek(struct archive_read_filter *f, int64_t offset,     int whence) { 	struct archive_read_client *client; 	int64_t r; 	unsigned int cursor; -	if (filter->closed || filter->fatal)+	if (f->closed || f->fatal) 		return (ARCHIVE_FATAL);-	if (filter->can_seek == 0)+	if (f->can_seek == 0) 		return (ARCHIVE_FAILED); -	client = &(filter->archive->client);+	client = &(f->archive->client); 	switch (whence) { 	case SEEK_CUR: 		/* Adjust the offset and use SEEK_SET instead */-		offset += filter->position;+		offset += f->position; 		__LA_FALLTHROUGH; 	case SEEK_SET: 		cursor = 0;@@ -1683,10 +1717,10 @@ 			client->dataset[++cursor].begin_position = r; 		} 		while (1) {-			r = client_switch_proxy(filter, cursor);+			r = client_switch_proxy(f, cursor); 			if (r != ARCHIVE_OK) 				return r;-			if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0)+			if ((r = client_seek_proxy(f, 0, SEEK_END)) < 0) 				return r; 			client->dataset[cursor].total_size = r; 			if (client->dataset[cursor].begin_position +@@ -1701,7 +1735,7 @@ 		if (offset < 0 		    || offset > client->dataset[cursor].total_size) 			return ARCHIVE_FATAL;-		if ((r = client_seek_proxy(filter, offset, SEEK_SET)) < 0)+		if ((r = client_seek_proxy(f, offset, SEEK_SET)) < 0) 			return r; 		break; @@ -1717,10 +1751,10 @@ 			client->dataset[++cursor].begin_position = r; 		} 		while (1) {-			r = client_switch_proxy(filter, cursor);+			r = client_switch_proxy(f, cursor); 			if (r != ARCHIVE_OK) 				return r;-			if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0)+			if ((r = client_seek_proxy(f, 0, SEEK_END)) < 0) 				return r; 			client->dataset[cursor].total_size = r; 			r = client->dataset[cursor].begin_position +@@ -1741,9 +1775,9 @@ 				client->dataset[cursor].total_size; 		} 		offset = (r + offset) - client->dataset[cursor].begin_position;-		if ((r = client_switch_proxy(filter, cursor)) != ARCHIVE_OK)+		if ((r = client_switch_proxy(f, cursor)) != ARCHIVE_OK) 			return r;-		r = client_seek_proxy(filter, offset, SEEK_SET);+		r = client_seek_proxy(f, offset, SEEK_SET); 		if (r < ARCHIVE_OK) 			return r; 		break;@@ -1771,10 +1805,10 @@ 		 * size is (r - offset).  Can we use that to simplify 		 * the TODO items above? 		 */-		filter->avail = filter->client_avail = 0;-		filter->next = filter->buffer;-		filter->position = r;-		filter->end_of_file = 0;+		f->avail = f->client_avail = 0;+		f->next = f->buffer;+		f->position = r;+		f->end_of_file = 0; 	} 	return r; }
c/archive_read_append_filter.c view
@@ -38,8 +38,8 @@ {   int r1, r2, number_bidders, i;   const char *str;-  struct archive_read_filter_bidder *bidder;-  struct archive_read_filter *filter;+  struct archive_read_filter_bidder *b;+  struct archive_read_filter *f;   struct archive_read *a = (struct archive_read *)_a;    r2 = (ARCHIVE_OK);@@ -118,30 +118,30 @@   {     number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); -    bidder = a->bidders;-    for (i = 1; i < number_bidders; i++, bidder++)+    b = a->bidders;+    for (i = 1; i < number_bidders; i++, b++)     {-      if (!bidder->name || !strcmp(bidder->name, str))+      if (!b->name || !strcmp(b->name, str))         break;     }-    if (!bidder->name || strcmp(bidder->name, str))+    if (!b->name || strcmp(b->name, str))     {       archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,           "Internal error: Unable to append filter");       return (ARCHIVE_FATAL);     } -    filter = calloc(1, sizeof(*filter));-    if (filter == NULL)+    f = calloc(1, sizeof(*f));+    if (f == NULL)     {       archive_set_error(&a->archive, ENOMEM, "Out of memory");       return (ARCHIVE_FATAL);     }-    filter->bidder = bidder;-    filter->archive = a;-    filter->upstream = a->filter;-    a->filter = filter;-    r2 = (bidder->vtable->init)(a->filter);+    f->bidder = b;+    f->archive = a;+    f->upstream = a->filter;+    a->filter = f;+    r2 = (b->vtable->init)(a->filter);     if (r2 != ARCHIVE_OK) {       __archive_read_free_filters(a);       return (ARCHIVE_FATAL);@@ -163,8 +163,8 @@   const char *cmd, const void *signature, size_t signature_len) {   int r, number_bidders, i;-  struct archive_read_filter_bidder *bidder;-  struct archive_read_filter *filter;+  struct archive_read_filter_bidder *b;+  struct archive_read_filter *f;   struct archive_read *a = (struct archive_read *)_a;    if (archive_read_support_filter_program_signature(_a, cmd, signature,@@ -173,36 +173,36 @@    number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); -  bidder = a->bidders;-  for (i = 0; i < number_bidders; i++, bidder++)+  b = a->bidders;+  for (i = 0; i < number_bidders; i++, b++)   {     /* Program bidder name set to filter name after initialization */-    if (bidder->data && !bidder->name)+    if (b->data && !b->name)       break;   }-  if (!bidder->data)+  if (!b->data)   {     archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,         "Internal error: Unable to append program filter");     return (ARCHIVE_FATAL);   } -  filter = calloc(1, sizeof(*filter));-  if (filter == NULL)+  f = calloc(1, sizeof(*f));+  if (f == NULL)   {     archive_set_error(&a->archive, ENOMEM, "Out of memory");     return (ARCHIVE_FATAL);   }-  filter->bidder = bidder;-  filter->archive = a;-  filter->upstream = a->filter;-  a->filter = filter;-  r = (bidder->vtable->init)(a->filter);+  f->bidder = b;+  f->archive = a;+  f->upstream = a->filter;+  a->filter = f;+  r = (b->vtable->init)(a->filter);   if (r != ARCHIVE_OK) {     __archive_read_free_filters(a);     return (ARCHIVE_FATAL);   }-  bidder->name = a->filter->name;+  b->name = a->filter->name;    a->bypass_filter_bidding = 1;   return r;
c/archive_read_data_into_fd.c view
@@ -37,6 +37,7 @@  #include "archive.h" #include "archive_private.h"+#include "archive_read_private.h"  /* Maximum amount of data to write at one time. */ #define	MAX_WRITE	(1024 * 1024)@@ -97,12 +98,15 @@ 	int64_t fd_offset; 	int64_t target_offset; 	int64_t actual_offset = 0;+	int64_t declared_size; 	int can_lseek; 	char *nulls = NULL;  	archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, 	    "archive_read_data_into_fd"); +	declared_size = ((struct archive_read *)a)->entry_bytes_declared;+ 	can_lseek = (fstat(fd, &st) == 0) && S_ISREG(st.st_mode); 	if (can_lseek) { 		fd_offset = lseek(fd, 0, SEEK_CUR);@@ -113,6 +117,24 @@ 	while ((r = archive_read_data_block(a, &buff, &size, &target_offset)) == 	    ARCHIVE_OK) { 		const char *p = buff;+		int overran = 0;++		if (declared_size >= 0) {+			/* We know the expected size, let's enforce that we don't overrun. */+			if (target_offset > declared_size) {+				/* We're already beyond the end? Don't write any more. */+				target_offset = declared_size;+				size = 0;+				overran = 1;+			} else if (size > (uint64_t)(declared_size - target_offset)) {+				/* Above is safe because target_offset <= declared_size */+				/* This block is bigger than the expected remainder */+				size = (size_t)(declared_size - target_offset);+				overran = 1;+			}+			/* Else size <= expected remainder of data and we're OK. */+		}+ 		if (target_offset > actual_offset) { 			r = pad_to(a, fd, can_lseek, &nulls, 			    target_offset, actual_offset);@@ -134,13 +156,37 @@ 			p += bytes_written; 			size -= bytes_written; 		}+		if (overran) {+			archive_set_error(a, ARCHIVE_ERRNO_MISC,+			    "Actual entry size exceeds the declared size "+			    "(%jd); truncated output at the declared size",+			    (intmax_t)declared_size);+			r = ARCHIVE_FAILED;+			goto cleanup;+		} 	}  	if (r == ARCHIVE_EOF && target_offset > actual_offset) {-		r2 = pad_to(a, fd, can_lseek, &nulls,-		    target_offset, actual_offset);-		if (r2 != ARCHIVE_OK)-			r = r2;+		int trailing_hole_overran =+		    declared_size >= 0 && target_offset > declared_size;+		if (trailing_hole_overran)+			target_offset = declared_size;+		if (target_offset > actual_offset) {+			r2 = pad_to(a, fd, can_lseek, &nulls,+			    target_offset, actual_offset);+			if (r2 != ARCHIVE_OK)+				r = r2;+			else+				actual_offset = target_offset;+		}+		if (trailing_hole_overran) {+			archive_set_error(a, ARCHIVE_ERRNO_MISC,+			    "Actual entry size exceeds the declared size "+			    "(%jd); truncated output at the declared size",+			    (intmax_t)declared_size);+			r = ARCHIVE_FAILED;+			goto cleanup;+		} 	}  cleanup:
c/archive_read_disk_posix.c view
@@ -453,6 +453,10 @@ 	a->archive.state = ARCHIVE_STATE_NEW; 	a->archive.vtable = &archive_read_disk_vtable; 	a->entry = archive_entry_new2(&a->archive);+	if (a->entry == NULL) {+		free(a);+		return (NULL);+	} 	a->lookup_uname = trivial_lookup_uname; 	a->lookup_gname = trivial_lookup_gname; 	a->flags = ARCHIVE_READDISK_MAC_COPYFILE;
c/archive_read_disk_set_standard_lookup.c view
@@ -45,6 +45,7 @@ #endif  #include "archive.h"+#include "archive_integer.h"  #if defined(_WIN32) && !defined(__CYGWIN__) int@@ -209,7 +210,8 @@ 		 * we just double it and try again.  Because the buffer 		 * is kept around in the cache object, we shouldn't 		 * have to do this very often. */-		nbuff_size = cache->buff_size * 2;+		if (archive_ckd_mul_size(&nbuff_size, cache->buff_size, 2))+			break; 		nbuff = realloc(cache->buff, nbuff_size); 		if (nbuff == NULL) 			break;@@ -276,7 +278,8 @@ 		/* ERANGE means our buffer was too small, but POSIX 		 * doesn't tell us how big the buffer should be, so 		 * we just double it and try again. */-		nbuff_size = cache->buff_size * 2;+		if (archive_ckd_mul_size(&nbuff_size, cache->buff_size, 2))+			break; 		nbuff = realloc(cache->buff, nbuff_size); 		if (nbuff == NULL) 			break;
c/archive_read_disk_windows.c view
@@ -37,10 +37,11 @@ #include <winioctl.h>  #include "archive.h"-#include "archive_string.h" #include "archive_entry.h"+#include "archive_integer.h" #include "archive_private.h" #include "archive_read_disk_private.h"+#include "archive_string.h" #include "archive_time_private.h"  #ifndef O_BINARY@@ -151,6 +152,8 @@ 	size_t			 dirname_length;  	int	 depth;+	/* Whether this tree began as a wildcard search */+	int	 rootwild;  	BY_HANDLE_FILE_INFORMATION	lst; 	BY_HANDLE_FILE_INFORMATION	st;@@ -555,6 +558,10 @@ 	a->archive.state = ARCHIVE_STATE_NEW; 	a->archive.vtable = &archive_read_disk_vtable; 	a->entry = archive_entry_new2(&a->archive);+	if (a->entry == NULL) {+		free(a);+		return (NULL);+	} 	a->lookup_uname = trivial_lookup_uname; 	a->lookup_gname = trivial_lookup_gname; 	a->flags = ARCHIVE_READDISK_MAC_COPYFILE;@@ -926,7 +933,27 @@ 		case 0: 			return (ARCHIVE_EOF); 		case TREE_POSTDESCENT:+			if (t->depth == 1 && t->rootwild && t->symlink_mode == 'H') {+				/*+				 * We have descended from a directory at depth 0 specified by a+				 * wildcard search in 'H'ybrid link mode. All items under this+				 * directory should be 'P'hysical.+				 */+				t->symlink_mode = 'P';+				a->follow_symlinks = 0;+			}+			break; 		case TREE_POSTASCENT:+			if (t->depth == 0 && t->rootwild && t->initial_symlink_mode == 'H') {+				/*+				 * We have returned to the root of a wildcard search, in 'H'ybrid+				 * mode, so restore the symlink mode we overwrote in+				 * TREE_POSTDESCENT.+				 */+				t->symlink_mode = t->initial_symlink_mode;+				/* Mimics setup done in setup_symlink_mode */+				a->follow_symlinks = 1;+			} 			break; 		case TREE_REGULAR: 			lst = tree_current_lstat(t);@@ -966,7 +993,14 @@ 	switch(t->symlink_mode) { 	case 'H': 		/* 'H': After the first item, rest like 'P'. */-		t->symlink_mode = 'P';+		if (!t->rootwild) {+			/*+			 * 'H': When we started with a wildcard, entries at the starting+			 * depth should be kept in `H` mode; switching into 'P' mode+			 * is handled in TREE_POSTDESCENT when we enter depth = 1.+			 */+			t->symlink_mode = 'P';+		} 		/* 'H': First item (from command line) like 'L'. */ 		/* FALLTHROUGH */ 	case 'L':@@ -1733,6 +1767,7 @@ 	t->full_path_dir_length = 0; 	t->dirname_length = 0; 	t->depth = 0;+	t->rootwild = 0; 	t->descend = 0; 	t->current = NULL; 	t->d = INVALID_HANDLE_VALUE;@@ -1786,6 +1821,7 @@ 			t->full_path.length = wcslen(t->full_path.s); 			t->full_path_dir_length = archive_strlen(&t->full_path); 		}+		t->rootwild = 1; 	} 	tree_push(t, base, t->full_path.s, 0, 0, 0, NULL); 	archive_wstring_free(&ws);@@ -2505,7 +2541,12 @@ 			    (DWORD)outranges_size, &retbytes, NULL); 			if (ret == 0 && GetLastError() == ERROR_MORE_DATA) { 				free(outranges);-				outranges_size *= 2;+				if (archive_ckd_mul_size(&outranges_size, outranges_size, 2)) {+					archive_set_error(&a->archive, ENOMEM,+					    "Couldn't allocate memory");+					exit_sts = ARCHIVE_FATAL;+					goto exit_setup_sparse;+				} 				outranges = (FILE_ALLOCATED_RANGE_BUFFER *) 				    malloc(outranges_size); 				if (outranges == NULL) {
c/archive_read_open_fd.c view
@@ -69,6 +69,7 @@ 	la_seek_stat_t st; 	struct read_fd_data *mine; 	void *b;+	int r;  	archive_clear_error(a); 	if (la_seek_fstat(fd, &st) != 0) {@@ -107,7 +108,9 @@ 	archive_read_set_skip_callback(a, file_skip); 	archive_read_set_seek_callback(a, file_seek); 	archive_read_set_close_callback(a, file_close);-	archive_read_set_callback_data(a, mine);+	r = archive_read_set_callback_data(a, mine);+	if (r < 0)+		return (r); 	return (archive_read_open1(a)); } 
c/archive_read_open_file.c view
@@ -70,6 +70,7 @@ 	struct read_FILE_data *mine; 	size_t block_size = 128 * 1024; 	void *b;+	int r;  	archive_clear_error(a); 	mine = calloc(1, sizeof(*mine));@@ -104,7 +105,9 @@ 	archive_read_set_skip_callback(a, FILE_skip); 	archive_read_set_seek_callback(a, FILE_seek); 	archive_read_set_close_callback(a, FILE_close);-	archive_read_set_callback_data(a, mine);+	r = archive_read_set_callback_data(a, mine);+	if (r < 0)+		return (r); 	return (archive_read_open1(a)); } 
c/archive_read_open_memory.c view
@@ -68,6 +68,7 @@     size_t size, size_t read_size) { 	struct read_memory_data *mine;+	int r;  	mine = calloc(1, sizeof(*mine)); 	if (mine == NULL) {@@ -82,7 +83,9 @@ 	archive_read_set_seek_callback(a, memory_read_seek); 	archive_read_set_skip_callback(a, memory_read_skip); 	archive_read_set_close_callback(a, memory_read_close);-	archive_read_set_callback_data(a, mine);+	r = archive_read_set_callback_data(a, mine);+	if (r < 0)+		return (r); 	return (archive_read_open1(a)); } 
c/archive_read_private.h view
@@ -76,10 +76,10 @@ struct archive_read_filter_vtable { 	/* Return next block. */ 	ssize_t (*read)(struct archive_read_filter *, const void **);-	/* Close (just this filter) and free(self). */-	int (*close)(struct archive_read_filter *self);+	/* Close (just this filter) and free(filter). */+	int (*close)(struct archive_read_filter *); 	/* Read any header metadata if available. */-	int (*read_header)(struct archive_read_filter *self, struct archive_entry *entry);+	int (*read_header)(struct archive_read_filter *, struct archive_entry *); };  /*@@ -179,6 +179,15 @@  	/* File offset of beginning of most recently-read header. */ 	int64_t		  header_position;++	/*+	 * Declared uncompressed size of the entry whose header was most+	 * recently read, or -1 if no size was declared.  Lets format-+	 * agnostic consumers like archive_read_data_into_fd() cap their+	 * output at the size an entry actually promised, regardless of+	 * whether the format reader enforces that itself.+	 */+	int64_t		  entry_bytes_declared;  	/* Nodes and offsets of compressed data block */ 	unsigned int data_start_node;
c/archive_read_support_filter_bzip2.c view
@@ -50,7 +50,7 @@ #include "archive_read_private.h"  #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)-struct private_data {+struct bzip2 { 	bz_stream	 stream; 	char		*out_block; 	size_t		 out_block_size;@@ -112,15 +112,15 @@  * from verifying as much as we would like.  */ static int-bzip2_reader_bid(struct archive_read_filter_bidder *self, struct archive_read_filter *filter)+bzip2_reader_bid(struct archive_read_filter_bidder *b, struct archive_read_filter *f) { 	const unsigned char *buffer; 	int bits_checked; -	(void)self; /* UNUSED */+	(void)b; /* UNUSED */  	/* Minimal bzip2 archive is 14 bytes. */-	buffer = __archive_read_filter_ahead(filter, 14, NULL);+	buffer = __archive_read_filter_ahead(f, 14, NULL); 	if (buffer == NULL) 		return (0); @@ -156,16 +156,16 @@  * in case that's available.  */ static int-bzip2_reader_init(struct archive_read_filter *self)+bzip2_reader_init(struct archive_read_filter *f) { 	int r; -	r = __archive_read_program(self, "bzip2 -d");+	r = __archive_read_program(f, "bzip2 -d"); 	/* Note: We set the format here even if __archive_read_program() 	 * above fails.  We do, after all, know what the format is 	 * even if we weren't able to read it. */-	self->code = ARCHIVE_FILTER_BZIP2;-	self->name = "bzip2";+	f->code = ARCHIVE_FILTER_BZIP2;+	f->name = "bzip2"; 	return (r); } @@ -182,29 +182,29 @@  * Setup the callbacks.  */ static int-bzip2_reader_init(struct archive_read_filter *self)+bzip2_reader_init(struct archive_read_filter *f) { 	static const size_t out_block_size = 64 * 1024; 	void *out_block;-	struct private_data *state;+	struct bzip2 *bzip2; -	self->code = ARCHIVE_FILTER_BZIP2;-	self->name = "bzip2";+	f->code = ARCHIVE_FILTER_BZIP2;+	f->name = "bzip2"; -	state = calloc(1, sizeof(*state));+	bzip2 = calloc(1, sizeof(*bzip2)); 	out_block = malloc(out_block_size);-	if (state == NULL || out_block == NULL) {-		archive_set_error(&self->archive->archive, ENOMEM,+	if (bzip2 == NULL || out_block == NULL) {+		archive_set_error(&f->archive->archive, ENOMEM, 		    "Can't allocate data for bzip2 decompression"); 		free(out_block);-		free(state);+		free(bzip2); 		return (ARCHIVE_FATAL); 	} -	self->data = state;-	state->out_block_size = out_block_size;-	state->out_block = out_block;-	self->vtable = &bzip2_reader_vtable;+	f->data = bzip2;+	bzip2->out_block_size = out_block_size;+	bzip2->out_block = out_block;+	f->vtable = &bzip2_reader_vtable;  	return (ARCHIVE_OK); }@@ -213,44 +213,42 @@  * Return the next block of decompressed data.  */ static ssize_t-bzip2_filter_read(struct archive_read_filter *self, const void **p)+bzip2_filter_read(struct archive_read_filter *f, const void **p) {-	struct private_data *state;+	struct bzip2 *bzip2 = f->data; 	size_t decompressed; 	const char *read_buf; 	ssize_t ret; -	state = (struct private_data *)self->data;--	if (state->eof) {+	if (bzip2->eof) { 		*p = NULL; 		return (0); 	}  	/* Empty our output buffer. */-	state->stream.next_out = state->out_block;-	state->stream.avail_out = (uint32_t)state->out_block_size;+	bzip2->stream.next_out = bzip2->out_block;+	bzip2->stream.avail_out = (uint32_t)bzip2->out_block_size;  	/* Try to fill the output buffer. */ 	for (;;) { 		ssize_t max_in; -		if (!state->valid) {-			if (bzip2_reader_bid(self->bidder, self->upstream) == 0) {-				state->eof = 1;-				*p = state->out_block;-				decompressed = state->stream.next_out-				    - state->out_block;+		if (!bzip2->valid) {+			if (bzip2_reader_bid(f->bidder, f->upstream) == 0) {+				bzip2->eof = 1;+				*p = bzip2->out_block;+				decompressed = bzip2->stream.next_out+				    - bzip2->out_block; 				return (decompressed); 			} 			/* Initialize compression library. */-			ret = BZ2_bzDecompressInit(&(state->stream),+			ret = BZ2_bzDecompressInit(&(bzip2->stream), 					   0 /* library verbosity */, 					   0 /* don't use low-mem algorithm */);  			/* If init fails, try low-memory algorithm instead. */ 			if (ret == BZ_MEM_ERROR)-				ret = BZ2_bzDecompressInit(&(state->stream),+				ret = BZ2_bzDecompressInit(&(bzip2->stream), 					   0 /* library verbosity */, 					   1 /* do use low-mem algo */); @@ -269,63 +267,63 @@ 					detail = "mis-compiled library"; 					break; 				}-				archive_set_error(&self->archive->archive, err,+				archive_set_error(&f->archive->archive, err, 				    "Internal error initializing decompressor%s%s", 				    detail == NULL ? "" : ": ", 				    detail); 				return (ARCHIVE_FATAL); 			}-			state->valid = 1;+			bzip2->valid = 1; 		}  		/* stream.next_in is really const, but bzlib 		 * doesn't declare it so. <sigh> */ 		read_buf =-		    __archive_read_filter_ahead(self->upstream, 1, &ret);+		    __archive_read_filter_ahead(f->upstream, 1, &ret); 		if (read_buf == NULL) {-			archive_set_error(&self->archive->archive,+			archive_set_error(&f->archive->archive, 			    ARCHIVE_ERRNO_MISC, 			    "truncated bzip2 input"); 			return (ARCHIVE_FATAL); 		}-		state->stream.next_in = (char *)(uintptr_t)read_buf;+		bzip2->stream.next_in = (char *)(uintptr_t)read_buf; 		if (UINT_MAX >= SSIZE_MAX) 			max_in = SSIZE_MAX; 		else 			max_in = UINT_MAX; 		if (ret > max_in) 			ret = max_in;-		state->stream.avail_in = (uint32_t)ret;+		bzip2->stream.avail_in = (uint32_t)ret;  		/* Decompress as much as we can in one pass. */-		ret = BZ2_bzDecompress(&(state->stream));-		__archive_read_filter_consume(self->upstream,-		    state->stream.next_in - read_buf);+		ret = BZ2_bzDecompress(&(bzip2->stream));+		__archive_read_filter_consume(f->upstream,+		    bzip2->stream.next_in - read_buf);  		switch (ret) { 		case BZ_STREAM_END: /* Found end of stream. */-			switch (BZ2_bzDecompressEnd(&(state->stream))) {+			switch (BZ2_bzDecompressEnd(&(bzip2->stream))) { 			case BZ_OK: 				break; 			default:-				archive_set_error(&(self->archive->archive),+				archive_set_error(&(f->archive->archive), 					  ARCHIVE_ERRNO_MISC, 					  "Failed to clean up decompressor"); 				return (ARCHIVE_FATAL); 			}-			state->valid = 0;+			bzip2->valid = 0; 			/* FALLTHROUGH */ 		case BZ_OK: /* Decompressor made some progress. */ 			/* If we filled our buffer, update stats and return. */-			if (state->stream.avail_out == 0) {-				*p = state->out_block;-				decompressed = state->stream.next_out-				    - state->out_block;+			if (bzip2->stream.avail_out == 0) {+				*p = bzip2->out_block;+				decompressed = bzip2->stream.next_out+				    - bzip2->out_block; 				return (decompressed); 			} 			break; 		default: /* Return an error. */-			archive_set_error(&self->archive->archive,+			archive_set_error(&f->archive->archive, 			    ARCHIVE_ERRNO_MISC, "bzip decompression failed"); 			return (ARCHIVE_FATAL); 		}@@ -336,28 +334,26 @@  * Clean up the decompressor.  */ static int-bzip2_filter_close(struct archive_read_filter *self)+bzip2_filter_close(struct archive_read_filter *f) {-	struct private_data *state;+	struct bzip2 *bzip2 = f->data; 	int ret = ARCHIVE_OK; -	state = (struct private_data *)self->data;--	if (state->valid) {-		switch (BZ2_bzDecompressEnd(&state->stream)) {+	if (bzip2->valid) {+		switch (BZ2_bzDecompressEnd(&bzip2->stream)) { 		case BZ_OK: 			break; 		default:-			archive_set_error(&self->archive->archive,+			archive_set_error(&f->archive->archive, 					  ARCHIVE_ERRNO_MISC, 					  "Failed to clean up decompressor"); 			ret = ARCHIVE_FATAL; 		}-		state->valid = 0;+		bzip2->valid = 0; 	} -	free(state->out_block);-	free(state);+	free(bzip2->out_block);+	free(bzip2); 	return (ret); } 
c/archive_read_support_filter_compress.c view
@@ -90,7 +90,7 @@  * names and structure here don't exactly match those used by compress.  */ -struct private_data {+struct compress { 	/* Input variables. */ 	const unsigned char	*next_in; 	size_t			 avail_in;@@ -169,16 +169,16 @@  * This logic returns zero if any part of the signature fails.  */ static int-compress_bidder_bid(struct archive_read_filter_bidder *self,-    struct archive_read_filter *filter)+compress_bidder_bid(struct archive_read_filter_bidder *b,+    struct archive_read_filter *f) { 	const unsigned char *buffer; 	int bits_checked; -	(void)self; /* UNUSED */+	(void)b; /* UNUSED */  	/* Shortest valid compress file is 3 bytes. */-	buffer = __archive_read_filter_ahead(filter, 3, NULL);+	buffer = __archive_read_filter_ahead(f, 3, NULL);  	if (buffer == NULL) 		return (0);@@ -207,69 +207,69 @@  * Setup the callbacks.  */ static int-compress_bidder_init(struct archive_read_filter *self)+compress_bidder_init(struct archive_read_filter *f) {-	struct private_data *state;+	struct compress *compress; 	static const size_t out_block_size = 64 * 1024; 	void *out_block; -	self->code = ARCHIVE_FILTER_COMPRESS;-	self->name = "compress (.Z)";+	f->code = ARCHIVE_FILTER_COMPRESS;+	f->name = "compress (.Z)"; -	state = calloc(1, sizeof(*state));+	compress = calloc(1, sizeof(*compress)); 	out_block = malloc(out_block_size);-	if (state == NULL || out_block == NULL) {+	if (compress == NULL || out_block == NULL) { 		free(out_block);-		free(state);-		archive_set_error(&self->archive->archive, ENOMEM,+		free(compress);+		archive_set_error(&f->archive->archive, ENOMEM, 		    "Can't allocate data for %s decompression",-		    self->name);+		    f->name); 		return (ARCHIVE_FATAL); 	} -	self->data = state;-	state->out_block_size = out_block_size;-	state->out_block = out_block;-	self->vtable = &compress_reader_vtable;+	f->data = compress;+	compress->out_block_size = out_block_size;+	compress->out_block = out_block;+	f->vtable = &compress_reader_vtable;  	return (ARCHIVE_OK); }  static int-compress_filter_init(struct archive_read_filter *self)+compress_filter_init(struct archive_read_filter *f) {-	struct private_data *state = (struct private_data *)self->data;+	struct compress *compress = f->data; 	int code; -	state->initialized = 1;+	compress->initialized = 1; -	(void)getbits(self, 8); /* Skip first signature byte. */-	(void)getbits(self, 8); /* Skip second signature byte. */+	(void)getbits(f, 8); /* Skip first signature byte. */+	(void)getbits(f, 8); /* Skip second signature byte. */  	/* Get compression parameters. */-	code = getbits(self, 8);+	code = getbits(f, 8); 	if (code < 0 || (code & 0x1f) > 16) {-		archive_set_error(&self->archive->archive, -1,+		archive_set_error(&f->archive->archive, -1, 		    "Invalid compressed data"); 		return (ARCHIVE_FATAL); 	}-	state->maxcode_bits = code & 0x1f;-	state->maxcode = (1 << state->maxcode_bits);-	state->use_reset_code = code & 0x80;+	compress->maxcode_bits = code & 0x1f;+	compress->maxcode = (1 << compress->maxcode_bits);+	compress->use_reset_code = code & 0x80;  	/* Initialize decompressor. */-	state->free_ent = 256;-	state->stackp = state->stack;-	if (state->use_reset_code)-		state->free_ent++;-	state->bits = 9;-	state->section_end_code = (1<<state->bits) - 1;-	state->oldcode = -1;+	compress->free_ent = 256;+	compress->stackp = compress->stack;+	if (compress->use_reset_code)+		compress->free_ent++;+	compress->bits = 9;+	compress->section_end_code = (1<<compress->bits) - 1;+	compress->oldcode = -1; 	for (code = 255; code >= 0; code--) {-		state->prefix[code] = 0;-		state->suffix[code] = code;+		compress->prefix[code] = 0;+		compress->suffix[code] = code; 	}-	next_code(self);+	next_code(f);  	return (ARCHIVE_OK); }@@ -279,32 +279,31 @@  * as necessary.  */ static ssize_t-compress_filter_read(struct archive_read_filter *self, const void **pblock)+compress_filter_read(struct archive_read_filter *f, const void **pblock) {-	struct private_data *state;+	struct compress *compress = f->data; 	unsigned char *p, *start, *end; 	int ret; -	state = (struct private_data *)self->data;-	if (!state->initialized) {-		ret = compress_filter_init(self);+	if (!compress->initialized) {+		ret = compress_filter_init(f); 		if (ret != ARCHIVE_OK) 			return (ret); 	}-	if (state->end_of_stream) {+	if (compress->end_of_stream) { 		*pblock = NULL; 		return (0); 	}-	p = start = (unsigned char *)state->out_block;-	end = start + state->out_block_size;+	p = start = (unsigned char *)compress->out_block;+	end = start + compress->out_block_size; -	while (p < end && !state->end_of_stream) {-		if (state->stackp > state->stack) {-			*p++ = *--state->stackp;+	while (p < end && !compress->end_of_stream) {+		if (compress->stackp > compress->stack) {+			*p++ = *--compress->stackp; 		} else {-			ret = next_code(self);+			ret = next_code(f); 			if (ret == -1)-				state->end_of_stream = ret;+				compress->end_of_stream = ret; 			else if (ret != ARCHIVE_OK) 				return (ret); 		}@@ -318,12 +317,12 @@  * Close and release the filter.  */ static int-compress_filter_close(struct archive_read_filter *self)+compress_filter_close(struct archive_read_filter *f) {-	struct private_data *state = (struct private_data *)self->data;+	struct compress *compress = f->data; -	free(state->out_block);-	free(state);+	free(compress->out_block);+	free(compress); 	return (ARCHIVE_OK); } @@ -333,18 +332,18 @@  * format error, ARCHIVE_EOF if we hit end of data, ARCHIVE_OK otherwise.  */ static int-next_code(struct archive_read_filter *self)+next_code(struct archive_read_filter *f) {-	struct private_data *state = (struct private_data *)self->data;+	struct compress *compress = f->data; 	int code, newcode;  again:-	code = newcode = getbits(self, state->bits);+	code = newcode = getbits(f, compress->bits); 	if (code < 0) 		return (code);  	/* If it's a reset code, reset the dictionary. */-	if ((code == 256) && state->use_reset_code) {+	if ((code == 256) && compress->use_reset_code) { 		/* 		 * The original 'compress' implementation blocked its 		 * I/O in a manner that resulted in junk bytes being@@ -352,63 +351,63 @@ 		 * this junk.  (Yes, the number of *bytes* to skip is 		 * a function of the current *bit* length.) 		 */-		int skip_bytes =  state->bits --		    (state->bytes_in_section % state->bits);-		skip_bytes %= state->bits;-		state->bits_avail = 0; /* Discard rest of this byte. */+		int skip_bytes =  compress->bits -+		    (compress->bytes_in_section % compress->bits);+		skip_bytes %= compress->bits;+		compress->bits_avail = 0; /* Discard rest of this byte. */ 		while (skip_bytes-- > 0) {-			code = getbits(self, 8);+			code = getbits(f, 8); 			if (code < 0) 				return (code); 		} 		/* Now, actually do the reset. */-		state->bytes_in_section = 0;-		state->bits = 9;-		state->section_end_code = (1 << state->bits) - 1;-		state->free_ent = 257;-		state->oldcode = -1;+		compress->bytes_in_section = 0;+		compress->bits = 9;+		compress->section_end_code = (1 << compress->bits) - 1;+		compress->free_ent = 257;+		compress->oldcode = -1; 		goto again; 	} -	if (code > state->free_ent-	    || (code == state->free_ent && state->oldcode < 0)) {+	if (code > compress->free_ent+	    || (code == compress->free_ent && compress->oldcode < 0)) { 		/* An invalid code is a fatal error. */-		archive_set_error(&(self->archive->archive), -1,+		archive_set_error(&(f->archive->archive), -1, 		    "Invalid compressed data"); 		return (ARCHIVE_FATAL); 	}  	/* Special case for KwKwK string. */-	if (code >= state->free_ent) {-		*state->stackp++ = state->finbyte;-		code = state->oldcode;+	if (code >= compress->free_ent) {+		*compress->stackp++ = compress->finbyte;+		code = compress->oldcode; 	}  	/* Generate output characters in reverse order. */ 	while (code >= 256) {-		*state->stackp++ = state->suffix[code];-		code = state->prefix[code];+		*compress->stackp++ = compress->suffix[code];+		code = compress->prefix[code]; 	}-	*state->stackp++ = state->finbyte = code;+	*compress->stackp++ = compress->finbyte = code;  	/* Generate the new entry. */-	code = state->free_ent;-	if (code < state->maxcode && state->oldcode >= 0) {-		state->prefix[code] = state->oldcode;-		state->suffix[code] = state->finbyte;-		++state->free_ent;+	code = compress->free_ent;+	if (code < compress->maxcode && compress->oldcode >= 0) {+		compress->prefix[code] = compress->oldcode;+		compress->suffix[code] = compress->finbyte;+		++compress->free_ent; 	}-	if (state->free_ent > state->section_end_code) {-		state->bits++;-		state->bytes_in_section = 0;-		if (state->bits == state->maxcode_bits)-			state->section_end_code = state->maxcode;+	if (compress->free_ent > compress->section_end_code) {+		compress->bits++;+		compress->bytes_in_section = 0;+		if (compress->bits == compress->maxcode_bits)+			compress->section_end_code = compress->maxcode; 		else-			state->section_end_code = (1 << state->bits) - 1;+			compress->section_end_code = (1 << compress->bits) - 1; 	}  	/* Remember previous code. */-	state->oldcode = newcode;+	compress->oldcode = newcode; 	return (ARCHIVE_OK); } @@ -418,9 +417,9 @@  * -1 indicates end of available data.  */ static int-getbits(struct archive_read_filter *self, int n)+getbits(struct archive_read_filter *f, int n) {-	struct private_data *state = (struct private_data *)self->data;+	struct compress *compress = f->data; 	int code; 	ssize_t ret; 	static const int mask[] = {@@ -428,31 +427,31 @@ 		0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff 	}; -	while (state->bits_avail < n) {-		if (state->avail_in <= 0) {-			if (state->consume_unnotified) {-				__archive_read_filter_consume(self->upstream,-					state->consume_unnotified);-				state->consume_unnotified = 0;+	while (compress->bits_avail < n) {+		if (compress->avail_in <= 0) {+			if (compress->consume_unnotified) {+				__archive_read_filter_consume(f->upstream,+					compress->consume_unnotified);+				compress->consume_unnotified = 0; 			}-			state->next_in-			    = __archive_read_filter_ahead(self->upstream,+			compress->next_in+			    = __archive_read_filter_ahead(f->upstream, 				1, &ret); 			if (ret == 0) 				return (-1);-			if (state->next_in == NULL)+			if (compress->next_in == NULL) 				return (ARCHIVE_FATAL);-			state->consume_unnotified = state->avail_in = ret;+			compress->consume_unnotified = compress->avail_in = ret; 		}-		state->bit_buffer |= *state->next_in++ << state->bits_avail;-		state->avail_in--;-		state->bits_avail += 8;-		state->bytes_in_section++;+		compress->bit_buffer |= *compress->next_in++ << compress->bits_avail;+		compress->avail_in--;+		compress->bits_avail += 8;+		compress->bytes_in_section++; 	} -	code = state->bit_buffer;-	state->bit_buffer >>= n;-	state->bits_avail -= n;+	code = compress->bit_buffer;+	compress->bit_buffer >>= n;+	compress->bits_avail -= n;  	return (code & mask[n]); }
c/archive_read_support_filter_grzip.c view
@@ -76,14 +76,14 @@  * Bidder just verifies the header and returns the number of verified bits.  */ static int-grzip_bidder_bid(struct archive_read_filter_bidder *self,-    struct archive_read_filter *filter)+grzip_bidder_bid(struct archive_read_filter_bidder *b,+    struct archive_read_filter *f) { 	const unsigned char *p; -	(void)self; /* UNUSED */+	(void)b; /* UNUSED */ -	p = __archive_read_filter_ahead(filter, sizeof(grzip_magic), NULL);+	p = __archive_read_filter_ahead(f, sizeof(grzip_magic), NULL); 	if (p == NULL) 		return (0); @@ -94,15 +94,15 @@ }  static int-grzip_bidder_init(struct archive_read_filter *self)+grzip_bidder_init(struct archive_read_filter *f) { 	int r; -	r = __archive_read_program(self, "grzip -d");+	r = __archive_read_program(f, "grzip -d"); 	/* Note: We set the format here even if __archive_read_program() 	 * above fails.  We do, after all, know what the format is 	 * even if we weren't able to read it. */-	self->code = ARCHIVE_FILTER_GRZIP;-	self->name = "grzip";+	f->code = ARCHIVE_FILTER_GRZIP;+	f->name = "grzip"; 	return (r); }
c/archive_read_support_filter_gzip.c view
@@ -51,7 +51,7 @@ #include "archive_read_private.h"  #ifdef HAVE_ZLIB_H-struct private_data {+struct gzip { 	z_stream	 stream; 	char		 in_stream; 	unsigned char	*out_block;@@ -120,9 +120,9 @@ #define MAX_FILENAME_LENGTH (1024 * 1024L) #define MAX_COMMENT_LENGTH (1024 * 1024L) static ssize_t-peek_at_header(struct archive_read_filter *filter, int *pbits,+peek_at_header(struct archive_read_filter *f, int *pbits, #ifdef HAVE_ZLIB_H-	       struct private_data *state+	       struct gzip *gzip #else 	       void *state #endif@@ -139,7 +139,7 @@ 	/* Start by looking at the first ten bytes of the header, which 	 * is all fixed layout. */ 	len = 10;-	p = __archive_read_filter_ahead(filter, len, &avail);+	p = __archive_read_filter_ahead(f, len, &avail); 	if (p == NULL) 		return (0); 	/* We only support deflation- third byte must be 0x08. */@@ -152,8 +152,8 @@ 	header_flags = p[3]; 	/* Bytes 4-7 are mod time in little endian. */ #ifdef HAVE_ZLIB_H-	if (state)-		state->mtime = archive_le32dec(p + 4);+	if (gzip)+		gzip->mtime = archive_le32dec(p + 4); #endif 	/* Byte 8 is deflate flags. */ 	/* XXXX TODO: return deflate flags back to consume_header for use@@ -162,7 +162,7 @@  	/* Optional extra data:  2 byte length plus variable body. */ 	if (header_flags & 4) {-		p = __archive_read_filter_ahead(filter, len + 2, &avail);+		p = __archive_read_filter_ahead(f, len + 2, &avail); 		if (p == NULL) 			return (0); 		len += archive_le16dec(p + len);@@ -180,7 +180,7 @@ 				if (avail > MAX_FILENAME_LENGTH) { 					return (0); 				}-				p = __archive_read_filter_ahead(filter,+				p = __archive_read_filter_ahead(f, 				    len, &avail); 			} 			if (p == NULL)@@ -188,10 +188,10 @@ 		} while (p[len - 1] != 0);  #ifdef HAVE_ZLIB_H-		if (state) {+		if (gzip) { 			/* Reset the name in case of repeat header reads. */-			free(state->name);-			state->name = strdup((const char *)&p[file_start]);+			free(gzip->name);+			gzip->name = strdup((const char *)&p[file_start]); 		} #endif 	}@@ -204,7 +204,7 @@ 				if (avail > MAX_COMMENT_LENGTH) { 					return (0); 				}-				p = __archive_read_filter_ahead(filter,+				p = __archive_read_filter_ahead(f, 				    len, &avail); 			} 			if (p == NULL)@@ -214,7 +214,7 @@  	/* Optional header CRC */ 	if ((header_flags & 2)) {-		p = __archive_read_filter_ahead(filter, len + 2, &avail);+		p = __archive_read_filter_ahead(f, len + 2, &avail); 		if (p == NULL) 			return (0); #if 0@@ -236,14 +236,14 @@  * Bidder just verifies the header and returns the number of verified bits.  */ static int-gzip_bidder_bid(struct archive_read_filter_bidder *self,-    struct archive_read_filter *filter)+gzip_bidder_bid(struct archive_read_filter_bidder *b,+    struct archive_read_filter *f) { 	int bits_checked; -	(void)self; /* UNUSED */+	(void)b; /* UNUSED */ -	if (peek_at_header(filter, &bits_checked, NULL))+	if (peek_at_header(f, &bits_checked, NULL)) 		return (bits_checked); 	return (0); }@@ -256,35 +256,33 @@  * in case that's available.  */ static int-gzip_bidder_init(struct archive_read_filter *self)+gzip_bidder_init(struct archive_read_filter *f) { 	int r; -	r = __archive_read_program(self, "gzip -d");+	r = __archive_read_program(f, "gzip -d"); 	/* Note: We set the format here even if __archive_read_program() 	 * above fails.  We do, after all, know what the format is 	 * even if we weren't able to read it. */-	self->code = ARCHIVE_FILTER_GZIP;-	self->name = "gzip";+	f->code = ARCHIVE_FILTER_GZIP;+	f->name = "gzip"; 	return (r); }  #else  static int-gzip_read_header(struct archive_read_filter *self, struct archive_entry *entry)+gzip_read_header(struct archive_read_filter *f, struct archive_entry *entry) {-	struct private_data *state;--	state = (struct private_data *)self->data;+	struct gzip *gzip = f->data;  	/* An mtime of 0 is considered invalid/missing. */-	if (state->mtime != 0)-		archive_entry_set_mtime(entry, state->mtime, 0);+	if (gzip->mtime != 0)+		archive_entry_set_mtime(entry, gzip->mtime, 0);  	/* If the name is available, extract it. */-	if (state->name)-		archive_entry_set_pathname(entry, state->name);+	if (gzip->name)+		archive_entry_set_pathname(entry, gzip->name);  	return (ARCHIVE_OK); }@@ -302,59 +300,57 @@  * Initialize the filter object.  */ static int-gzip_bidder_init(struct archive_read_filter *self)+gzip_bidder_init(struct archive_read_filter *f) {-	struct private_data *state;+	struct gzip *gzip; 	static const size_t out_block_size = 64 * 1024; 	void *out_block; -	self->code = ARCHIVE_FILTER_GZIP;-	self->name = "gzip";+	f->code = ARCHIVE_FILTER_GZIP;+	f->name = "gzip"; -	state = calloc(1, sizeof(*state));+	gzip = calloc(1, sizeof(*gzip)); 	out_block = malloc(out_block_size);-	if (state == NULL || out_block == NULL) {+	if (gzip == NULL || out_block == NULL) { 		free(out_block);-		free(state);-		archive_set_error(&self->archive->archive, ENOMEM,+		free(gzip);+		archive_set_error(&f->archive->archive, ENOMEM, 		    "Can't allocate data for gzip decompression"); 		return (ARCHIVE_FATAL); 	} -	self->data = state;-	state->out_block_size = out_block_size;-	state->out_block = out_block;-	self->vtable = &gzip_reader_vtable;+	f->data = gzip;+	gzip->out_block_size = out_block_size;+	gzip->out_block = out_block;+	f->vtable = &gzip_reader_vtable; -	state->in_stream = 0; /* We're not actually within a stream yet. */+	gzip->in_stream = 0; /* We're not actually within a stream yet. */  	return (ARCHIVE_OK); }  static int-consume_header(struct archive_read_filter *self)+consume_header(struct archive_read_filter *f) {-	struct private_data *state;+	struct gzip *gzip = f->data; 	ssize_t avail, max_in; 	size_t len; 	int ret; -	state = (struct private_data *)self->data;- 	/* If this is a real header, consume it. */-	len = peek_at_header(self->upstream, NULL, state);+	len = peek_at_header(f->upstream, NULL, gzip); 	if (len == 0) 		return (ARCHIVE_EOF);-	__archive_read_filter_consume(self->upstream, len);+	__archive_read_filter_consume(f->upstream, len);  	/* Initialize CRC accumulator. */-	state->crc = crc32(0L, NULL, 0);+	gzip->crc = crc32(0L, NULL, 0);  	/* Initialize compression library. */-	state->stream.next_in = (unsigned char *)(uintptr_t)-	    __archive_read_filter_ahead(self->upstream, 1, &avail);+	gzip->stream.next_in = (unsigned char *)(uintptr_t)+	    __archive_read_filter_ahead(f->upstream, 1, &avail); 	if (avail < 0) {-		archive_set_error(&self->archive->archive,+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_MISC, 		    "Failed to read gzip input"); 		return (ARCHIVE_FATAL);@@ -365,34 +361,34 @@ 		max_in = UINT_MAX; 	if (avail > max_in) 		avail = max_in;-	state->stream.avail_in = (uInt)avail;-	ret = inflateInit2(&(state->stream),+	gzip->stream.avail_in = (uInt)avail;+	ret = inflateInit2(&(gzip->stream), 	    -15 /* Don't check for zlib header */);  	/* Decipher the error code. */ 	switch (ret) { 	case Z_OK:-		state->in_stream = 1;+		gzip->in_stream = 1; 		return (ARCHIVE_OK); 	case Z_STREAM_ERROR:-		archive_set_error(&self->archive->archive,+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_MISC, 		    "Internal error initializing compression library: " 		    "invalid setup parameter"); 		break; 	case Z_MEM_ERROR:-		archive_set_error(&self->archive->archive, ENOMEM,+		archive_set_error(&f->archive->archive, ENOMEM, 		    "Internal error initializing compression library: " 		    "out of memory"); 		break; 	case Z_VERSION_ERROR:-		archive_set_error(&self->archive->archive,+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_MISC, 		    "Internal error initializing compression library: " 		    "invalid library version"); 		break; 	default:-		archive_set_error(&self->archive->archive,+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_MISC, 		    "Internal error initializing compression library: " 		    " Zlib error %d", ret);@@ -402,59 +398,55 @@ }  static int-consume_trailer(struct archive_read_filter *self)+consume_trailer(struct archive_read_filter *f) {-	struct private_data *state;+	struct gzip *gzip = f->data; 	const unsigned char *p; -	state = (struct private_data *)self->data;--	state->in_stream = 0;-	switch (inflateEnd(&(state->stream))) {+	gzip->in_stream = 0;+	switch (inflateEnd(&(gzip->stream))) { 	case Z_OK: 		break; 	default:-		archive_set_error(&self->archive->archive,+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_MISC, 		    "Failed to clean up gzip decompressor"); 		return (ARCHIVE_FATAL); 	}  	/* GZip trailer is a fixed 8 byte structure. */-	p = __archive_read_filter_ahead(self->upstream, 8, NULL);+	p = __archive_read_filter_ahead(f->upstream, 8, NULL); 	if (p == NULL) 		return (ARCHIVE_FATAL);  	/* XXX TODO: Verify the length and CRC. */  	/* We've verified the trailer, so consume it now. */-	__archive_read_filter_consume(self->upstream, 8);+	__archive_read_filter_consume(f->upstream, 8);  	return (ARCHIVE_OK); }  static ssize_t-gzip_filter_read(struct archive_read_filter *self, const void **p)+gzip_filter_read(struct archive_read_filter *f, const void **p) {-	struct private_data *state;+	struct gzip *gzip = f->data; 	size_t decompressed; 	ssize_t avail_in, max_in; 	int ret; -	state = (struct private_data *)self->data;- 	/* Empty our output buffer. */-	state->stream.next_out = state->out_block;-	state->stream.avail_out = (uInt)state->out_block_size;+	gzip->stream.next_out = gzip->out_block;+	gzip->stream.avail_out = (uInt)gzip->out_block_size;  	/* Try to fill the output buffer. */-	while (state->stream.avail_out > 0 && !state->eof) {+	while (gzip->stream.avail_out > 0 && !gzip->eof) { 		/* If we're not in a stream, read a header 		 * and initialize the decompression library. */-		if (!state->in_stream) {-			ret = consume_header(self);+		if (!gzip->in_stream) {+			ret = consume_header(f); 			if (ret == ARCHIVE_EOF) {-				state->eof = 1;+				gzip->eof = 1; 				break; 			} 			if (ret < ARCHIVE_OK)@@ -464,10 +456,10 @@ 		/* Peek at the next available data. */ 		/* ZLib treats stream.next_in as const but doesn't declare 		 * it so, hence this ugly cast. */-		state->stream.next_in = (unsigned char *)(uintptr_t)-		    __archive_read_filter_ahead(self->upstream, 1, &avail_in);-		if (state->stream.next_in == NULL) {-			archive_set_error(&self->archive->archive,+		gzip->stream.next_in = (unsigned char *)(uintptr_t)+		    __archive_read_filter_ahead(f->upstream, 1, &avail_in);+		if (gzip->stream.next_in == NULL) {+			archive_set_error(&f->archive->archive, 			    ARCHIVE_ERRNO_MISC, 			    "truncated gzip input"); 			return (ARCHIVE_FATAL);@@ -478,27 +470,27 @@ 			max_in = UINT_MAX; 		if (avail_in > max_in) 			avail_in = max_in;-		state->stream.avail_in = (uInt)avail_in;+		gzip->stream.avail_in = (uInt)avail_in;  		/* Decompress and consume some of that data. */-		ret = inflate(&(state->stream), 0);+		ret = inflate(&(gzip->stream), 0); 		switch (ret) { 		case Z_OK: /* Decompressor made some progress. */-			__archive_read_filter_consume(self->upstream,-			    avail_in - state->stream.avail_in);+			__archive_read_filter_consume(f->upstream,+			    avail_in - gzip->stream.avail_in); 			break; 		case Z_STREAM_END: /* Found end of stream. */-			__archive_read_filter_consume(self->upstream,-			    avail_in - state->stream.avail_in);+			__archive_read_filter_consume(f->upstream,+			    avail_in - gzip->stream.avail_in); 			/* Consume the stream trailer; release the 			 * decompression library. */-			ret = consume_trailer(self);+			ret = consume_trailer(f); 			if (ret < ARCHIVE_OK) 				return (ret); 			break; 		default: 			/* Return an error. */-			archive_set_error(&self->archive->archive,+			archive_set_error(&f->archive->archive, 			    ARCHIVE_ERRNO_MISC, 			    "gzip decompression failed"); 			return (ARCHIVE_FATAL);@@ -506,11 +498,11 @@ 	}  	/* We've read as much as we can. */-	decompressed = state->stream.next_out - state->out_block;+	decompressed = gzip->stream.next_out - gzip->out_block; 	if (decompressed == 0) 		*p = NULL; 	else-		*p = state->out_block;+		*p = gzip->out_block; 	return (decompressed); } @@ -518,29 +510,28 @@  * Clean up the decompressor.  */ static int-gzip_filter_close(struct archive_read_filter *self)+gzip_filter_close(struct archive_read_filter *f) {-	struct private_data *state;+	struct gzip *gzip = f->data; 	int ret; -	state = (struct private_data *)self->data; 	ret = ARCHIVE_OK; -	if (state->in_stream) {-		switch (inflateEnd(&(state->stream))) {+	if (gzip->in_stream) {+		switch (inflateEnd(&(gzip->stream))) { 		case Z_OK: 			break; 		default:-			archive_set_error(&(self->archive->archive),+			archive_set_error(&(f->archive->archive), 			    ARCHIVE_ERRNO_MISC, 			    "Failed to clean up gzip compressor"); 			ret = ARCHIVE_FATAL; 		} 	} -	free(state->name);-	free(state->out_block);-	free(state);+	free(gzip->name);+	free(gzip->out_block);+	free(gzip); 	return (ret); } 
c/archive_read_support_filter_lrzip.c view
@@ -75,18 +75,18 @@  * Bidder just verifies the header and returns the number of verified bits.  */ static int-lrzip_bidder_bid(struct archive_read_filter_bidder *self,-    struct archive_read_filter *filter)+lrzip_bidder_bid(struct archive_read_filter_bidder *b,+    struct archive_read_filter *f) { 	const unsigned char *p; 	ssize_t len; 	int i; -	(void)self; /* UNUSED */+	(void)b; /* UNUSED */ 	/* Start by looking at the first six bytes of the header, which 	 * is all fixed layout. */ 	len = 6;-	p = __archive_read_filter_ahead(filter, len, NULL);+	p = __archive_read_filter_ahead(f, len, NULL); 	if (p == NULL) 		return (0); @@ -105,15 +105,15 @@ }  static int-lrzip_bidder_init(struct archive_read_filter *self)+lrzip_bidder_init(struct archive_read_filter *f) { 	int r; -	r = __archive_read_program(self, "lrzip -d -q");+	r = __archive_read_program(f, "lrzip -d -q"); 	/* Note: We set the format here even if __archive_read_program() 	 * above fails.  We do, after all, know what the format is 	 * even if we weren't able to read it. */-	self->code = ARCHIVE_FILTER_LRZIP;-	self->name = "lrzip";+	f->code = ARCHIVE_FILTER_LRZIP;+	f->name = "lrzip"; 	return (r); }
c/archive_read_support_filter_lz4.c view
@@ -57,7 +57,7 @@ #define LZ4_SKIPPABLE_MASK 0xFFFFFFF0  #if defined(HAVE_LIBLZ4)-struct private_data {+struct lz4 { 	enum {  SELECT_STREAM, 		READ_DEFAULT_STREAM, 		READ_DEFAULT_BLOCK,@@ -139,8 +139,8 @@  * from verifying as much as we would like.  */ static int-lz4_reader_bid(struct archive_read_filter_bidder *self,-    struct archive_read_filter *filter)+lz4_reader_bid(struct archive_read_filter_bidder *b,+    struct archive_read_filter *f) { 	const unsigned char *buffer; 	ssize_t avail;@@ -159,7 +159,7 @@ 	const size_t max_lookahead = 64 * 1024; 	uint32_t magic_number; -	(void)self; /* UNUSED */+	(void)b; /* UNUSED */  	/* 	 * Zstd and LZ4 skippable frame magic numbers are identical. To@@ -168,7 +168,7 @@ 	 */  	/* Minimal lz4 archive is 11 bytes. */-	buffer = __archive_read_filter_ahead(filter, min_lz4_archive_size,+	buffer = __archive_read_filter_ahead(f, min_lz4_archive_size, 	    &avail); 	if (buffer == NULL) 		return (0);@@ -184,7 +184,7 @@  		/* Ensure that we can read another 4 bytes. */ 		if (offset_in_buffer + 4 > (size_t)avail) {-			buffer = __archive_read_filter_ahead(filter,+			buffer = __archive_read_filter_ahead(f, 			    offset_in_buffer + 4, &avail); 			if (buffer == NULL) 				return (0);@@ -212,7 +212,7 @@ 			if (min > max_lookahead) 				return (0);  -			buffer = __archive_read_filter_ahead(filter,+			buffer = __archive_read_filter_ahead(f, 			    min, &avail); 			if (buffer == NULL) 				return (0); @@ -271,16 +271,16 @@  * in case that's available.  */ static int-lz4_reader_init(struct archive_read_filter *self)+lz4_reader_init(struct archive_read_filter *f) { 	int r; -	r = __archive_read_program(self, "lz4 -d -q");+	r = __archive_read_program(f, "lz4 -d -q"); 	/* Note: We set the format here even if __archive_read_program() 	 * above fails.  We do, after all, know what the format is 	 * even if we weren't able to read it. */-	self->code = ARCHIVE_FILTER_LZ4;-	self->name = "lz4";+	f->code = ARCHIVE_FILTER_LZ4;+	f->name = "lz4"; 	return (r); } @@ -297,73 +297,73 @@  * Setup the callbacks.  */ static int-lz4_reader_init(struct archive_read_filter *self)+lz4_reader_init(struct archive_read_filter *f) {-	struct private_data *state;+	struct lz4 *lz4; -	self->code = ARCHIVE_FILTER_LZ4;-	self->name = "lz4";+	f->code = ARCHIVE_FILTER_LZ4;+	f->name = "lz4"; -	state = calloc(1, sizeof(*state));-	if (state == NULL) {-		archive_set_error(&self->archive->archive, ENOMEM,+	lz4 = calloc(1, sizeof(*lz4));+	if (lz4 == NULL) {+		archive_set_error(&f->archive->archive, ENOMEM, 		    "Can't allocate data for lz4 decompression"); 		return (ARCHIVE_FATAL); 	} -	self->data = state;-	state->stage = SELECT_STREAM;-	self->vtable = &lz4_reader_vtable;+	f->data = lz4;+	lz4->stage = SELECT_STREAM;+	f->vtable = &lz4_reader_vtable;  	return (ARCHIVE_OK); }  static int-lz4_allocate_out_block(struct archive_read_filter *self)+lz4_allocate_out_block(struct archive_read_filter *f) {-	struct private_data *state = (struct private_data *)self->data;-	size_t out_block_size = state->flags.block_maximum_size;+	struct lz4 *lz4 = f->data;+	size_t out_block_size = lz4->flags.block_maximum_size; 	void *out_block; -	if (!state->flags.block_independence)+	if (!lz4->flags.block_independence) 		out_block_size += 64 * 1024;-	if (state->out_block_size < out_block_size) {-		free(state->out_block);-		state->out_block = NULL;+	if (lz4->out_block_size < out_block_size) {+		free(lz4->out_block);+		lz4->out_block = NULL; 		out_block = malloc(out_block_size); 		if (out_block == NULL) {-			state->out_block_size = 0;-			archive_set_error(&self->archive->archive, ENOMEM,+			lz4->out_block_size = 0;+			archive_set_error(&f->archive->archive, ENOMEM, 			    "Can't allocate data for lz4 decompression"); 			return (ARCHIVE_FATAL); 		}-		state->out_block_size = out_block_size;-		state->out_block = out_block;+		lz4->out_block_size = out_block_size;+		lz4->out_block = out_block; 	}-	if (!state->flags.block_independence)-		memset(state->out_block, 0, 64 * 1024);+	if (!lz4->flags.block_independence)+		memset(lz4->out_block, 0, 64 * 1024); 	return (ARCHIVE_OK); }  static int-lz4_allocate_out_block_for_legacy(struct archive_read_filter *self)+lz4_allocate_out_block_for_legacy(struct archive_read_filter *f) {-	struct private_data *state = (struct private_data *)self->data;+	struct lz4 *lz4 = f->data; 	size_t out_block_size = LEGACY_BLOCK_SIZE; 	void *out_block; -	if (state->out_block_size < out_block_size) {-		free(state->out_block);-		state->out_block = NULL;+	if (lz4->out_block_size < out_block_size) {+		free(lz4->out_block);+		lz4->out_block = NULL; 		out_block = malloc(out_block_size); 		if (out_block == NULL) {-			state->out_block_size = 0;-			archive_set_error(&self->archive->archive, ENOMEM,+			lz4->out_block_size = 0;+			archive_set_error(&f->archive->archive, ENOMEM, 			    "Can't allocate data for lz4 decompression"); 			return (ARCHIVE_FATAL); 		}-		state->out_block_size = out_block_size;-		state->out_block = out_block;+		lz4->out_block_size = out_block_size;+		lz4->out_block = out_block; 	} 	return (ARCHIVE_OK); }@@ -372,96 +372,96 @@  * Return the next block of decompressed data.  */ static ssize_t-lz4_filter_read(struct archive_read_filter *self, const void **p)+lz4_filter_read(struct archive_read_filter *f, const void **p) {-	struct private_data *state = (struct private_data *)self->data;+	struct lz4 *lz4 = f->data; 	ssize_t ret; -	if (state->eof) {+	if (lz4->eof) { 		*p = NULL; 		return (0); 	} -	__archive_read_filter_consume(self->upstream, state->unconsumed);-	state->unconsumed = 0;+	__archive_read_filter_consume(f->upstream, lz4->unconsumed);+	lz4->unconsumed = 0; -	switch (state->stage) {+	switch (lz4->stage) { 	case SELECT_STREAM: 		break; 	case READ_DEFAULT_STREAM: 	case READ_LEGACY_STREAM: 		/* Reading an lz4 stream already failed. */-		archive_set_error(&self->archive->archive,+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_MISC, "Invalid sequence"); 		return (ARCHIVE_FATAL); 	case READ_DEFAULT_BLOCK:-		ret = lz4_filter_read_default_stream(self, p);-		if (ret != 0 || state->stage != SELECT_STREAM)+		ret = lz4_filter_read_default_stream(f, p);+		if (ret != 0 || lz4->stage != SELECT_STREAM) 			return ret; 		break; 	case READ_LEGACY_BLOCK:-		ret = lz4_filter_read_legacy_stream(self, p);-		if (ret != 0 || state->stage != SELECT_STREAM)+		ret = lz4_filter_read_legacy_stream(f, p);+		if (ret != 0 || lz4->stage != SELECT_STREAM) 			return ret; 		break; 	default:-		archive_set_error(&self->archive->archive,+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_MISC, "Program error"); 		return (ARCHIVE_FATAL); 	} -	while (state->stage == SELECT_STREAM) {+	while (lz4->stage == SELECT_STREAM) { 		const char *read_buf;  		/* Read a magic number. */-		read_buf = __archive_read_filter_ahead(self->upstream, 4,+		read_buf = __archive_read_filter_ahead(f->upstream, 4, 				NULL); 		if (read_buf == NULL) {-			state->eof = 1;+			lz4->eof = 1; 			*p = NULL; 			return (0); 		} 		uint32_t number = archive_le32dec(read_buf);-		__archive_read_filter_consume(self->upstream, 4);+		__archive_read_filter_consume(f->upstream, 4); 		if (number == LZ4_MAGICNUMBER)-			return lz4_filter_read_default_stream(self, p);+			return lz4_filter_read_default_stream(f, p); 		else if (number == LZ4_LEGACY)-			return lz4_filter_read_legacy_stream(self, p);+			return lz4_filter_read_legacy_stream(f, p); 		else if ((number & LZ4_SKIPPABLE_MASK) == LZ4_SKIPPABLE_START) { 			read_buf = __archive_read_filter_ahead(-				self->upstream, 4, NULL);+				f->upstream, 4, NULL); 			if (read_buf == NULL) { 				archive_set_error(-				    &self->archive->archive,+				    &f->archive->archive, 		    		    ARCHIVE_ERRNO_MISC, 				    "Malformed lz4 data"); 				return (ARCHIVE_FATAL); 			} 			int64_t skip_bytes = archive_le32dec(read_buf);-			if (__archive_read_filter_consume(self->upstream,+			if (__archive_read_filter_consume(f->upstream, 			    4 + skip_bytes) < 0) { 				archive_set_error(-				    &self->archive->archive,+				    &f->archive->archive, 				    ARCHIVE_ERRNO_MISC, 				    "Malformed lz4 data"); 				return (ARCHIVE_FATAL); 			} 		} else { 			/* Ignore following unrecognized data. */-			state->eof = 1;+			lz4->eof = 1; 			*p = NULL; 			return (0); 		} 	}-	state->eof = 1;+	lz4->eof = 1; 	*p = NULL; 	return (0); }  static int-lz4_filter_read_descriptor(struct archive_read_filter *self)+lz4_filter_read_descriptor(struct archive_read_filter *f) {-	struct private_data *state = (struct private_data *)self->data;+	struct lz4 *lz4 = f->data; 	const char *read_buf; 	ssize_t bytes_remaining; 	ssize_t descriptor_bytes;@@ -469,10 +469,10 @@ 	unsigned int chsum, chsum_verifier;  	/* Make sure we have 2 bytes for flags. */-	read_buf = __archive_read_filter_ahead(self->upstream, 2,+	read_buf = __archive_read_filter_ahead(f->upstream, 2, 	    &bytes_remaining); 	if (read_buf == NULL) {-		archive_set_error(&self->archive->archive,+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_MISC, 		    "truncated lz4 input"); 		return (ARCHIVE_FATAL);@@ -488,11 +488,11 @@ 	/* A reserved bit must be zero. */ 	if (flag & 0x02) 		goto malformed_error;-	state->flags.block_independence = (flag & 0x20) != 0;-	state->flags.block_checksum = (flag & 0x10)?4:0;-	state->flags.stream_size = (flag & 0x08) != 0;-	state->flags.stream_checksum = (flag & 0x04) != 0;-	state->flags.preset_dictionary = (flag & 0x01) != 0;+	lz4->flags.block_independence = (flag & 0x20) != 0;+	lz4->flags.block_checksum = (flag & 0x10)?4:0;+	lz4->flags.stream_size = (flag & 0x08) != 0;+	lz4->flags.stream_checksum = (flag & 0x04) != 0;+	lz4->flags.preset_dictionary = (flag & 0x01) != 0;  	/* BD */ 	bd = (unsigned char)read_buf[1];@@ -502,16 +502,16 @@ 	/* Get a maximum block size. */ 	switch (read_buf[1] >> 4) { 	case 4: /* 64 KB */-		state->flags.block_maximum_size = 64 * 1024;+		lz4->flags.block_maximum_size = 64 * 1024; 		break; 	case 5: /* 256 KB */-		state->flags.block_maximum_size = 256 * 1024;+		lz4->flags.block_maximum_size = 256 * 1024; 		break; 	case 6: /* 1 MB */-		state->flags.block_maximum_size = 1024 * 1024;+		lz4->flags.block_maximum_size = 1024 * 1024; 		break; 	case 7: /* 4 MB */-		state->flags.block_maximum_size = 4 * 1024 * 1024;+		lz4->flags.block_maximum_size = 4 * 1024 * 1024; 		break; 	default: 		goto malformed_error;@@ -519,15 +519,15 @@  	/* Read the whole descriptor in a stream block. */ 	descriptor_bytes = 3;-	if (state->flags.stream_size)+	if (lz4->flags.stream_size) 		descriptor_bytes += 8;-	if (state->flags.preset_dictionary)+	if (lz4->flags.preset_dictionary) 		descriptor_bytes += 4; 	if (bytes_remaining < descriptor_bytes) {-		read_buf = __archive_read_filter_ahead(self->upstream,+		read_buf = __archive_read_filter_ahead(f->upstream, 		    descriptor_bytes, &bytes_remaining); 		if (read_buf == NULL) {-			archive_set_error(&self->archive->archive,+			archive_set_error(&f->archive->archive, 			    ARCHIVE_ERRNO_MISC, 			    "truncated lz4 input"); 			return (ARCHIVE_FATAL);@@ -542,30 +542,30 @@ 		goto malformed_error; #endif -	__archive_read_filter_consume(self->upstream, descriptor_bytes);+	__archive_read_filter_consume(f->upstream, descriptor_bytes);  	/* Make sure we have a large enough buffer for uncompressed data. */-	if (lz4_allocate_out_block(self) != ARCHIVE_OK)+	if (lz4_allocate_out_block(f) != ARCHIVE_OK) 		return (ARCHIVE_FATAL);-	if (state->flags.stream_checksum) {-		state->xxh32_state = __archive_xxhash.XXH32_init(0);-		if (state->xxh32_state == NULL)+	if (lz4->flags.stream_checksum) {+		lz4->xxh32_state = __archive_xxhash.XXH32_init(0);+		if (lz4->xxh32_state == NULL) 			return (ARCHIVE_FATAL); 	} -	state->decoded_size = 0;+	lz4->decoded_size = 0; 	/* Success */ 	return (ARCHIVE_OK); malformed_error:-	archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+	archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, 	    "malformed lz4 data"); 	return (ARCHIVE_FATAL); }  static ssize_t-lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)+lz4_filter_read_data_block(struct archive_read_filter *f, const void **p) {-	struct private_data *state = (struct private_data *)self->data;+	struct lz4 *lz4 = f->data; 	ssize_t compressed_size; 	const char *read_buf; 	int checksum_size;@@ -575,19 +575,19 @@ 	*p = NULL;  	/* Make sure we have 4 bytes for a block size. */-	read_buf = __archive_read_filter_ahead(self->upstream, 4, NULL);+	read_buf = __archive_read_filter_ahead(f->upstream, 4, NULL); 	if (read_buf == NULL) 		goto truncated_error; 	compressed_size = archive_le32dec(read_buf);-	if ((compressed_size & 0x7fffffff) > state->flags.block_maximum_size)+	if ((compressed_size & 0x7fffffff) > lz4->flags.block_maximum_size) 		goto malformed_error; 	/* A compressed size == 0 means the end of stream blocks. */ 	if (compressed_size == 0) {-		__archive_read_filter_consume(self->upstream, 4);+		__archive_read_filter_consume(f->upstream, 4); 		return 0; 	} -	checksum_size = state->flags.block_checksum;+	checksum_size = lz4->flags.block_checksum; 	/* Check if the block is uncompressed. */ 	if (compressed_size & 0x80000000U) { 		compressed_size &= 0x7fffffff;@@ -600,7 +600,7 @@ 	  for its decompression speed, so we read a whole block and allocate 	  a huge buffer used for decoded data. 	*/-	read_buf = __archive_read_filter_ahead(self->upstream,+	read_buf = __archive_read_filter_ahead(f->upstream, 	    4 + compressed_size + checksum_size, NULL); 	if (read_buf == NULL) 		goto truncated_error;@@ -621,24 +621,24 @@ 	/* If the block is uncompressed, there is nothing to do. */ 	if (uncompressed_size) { 		/* Prepare a prefix 64k block for next block. */-		if (!state->flags.block_independence) {+		if (!lz4->flags.block_independence) { 			prefix64k = 64 * 1024; 			if (uncompressed_size < (ssize_t)prefix64k) {-				memcpy(state->out_block+				memcpy(lz4->out_block 					+ prefix64k - uncompressed_size, 				    read_buf + 4, 				    uncompressed_size);-				memset(state->out_block, 0,+				memset(lz4->out_block, 0, 				    prefix64k - uncompressed_size); 			} else {-				memcpy(state->out_block,+				memcpy(lz4->out_block, 				    read_buf + 4 					+ uncompressed_size - prefix64k, 				    prefix64k); 			}-			state->decoded_size = 0;+			lz4->decoded_size = 0; 		}-		state->unconsumed = 4 + uncompressed_size + checksum_size;+		lz4->unconsumed = 4 + uncompressed_size + checksum_size; 		*p = read_buf + 4; 		return uncompressed_size; 	}@@ -646,168 +646,168 @@ 	/* 	   Decompress a block data. 	 */-	if (state->flags.block_independence) {+	if (lz4->flags.block_independence) { 		prefix64k = 0; 		uncompressed_size = LZ4_decompress_safe(read_buf + 4,-		    state->out_block, (int)compressed_size,-		    state->flags.block_maximum_size);+		    lz4->out_block, (int)compressed_size,+		    lz4->flags.block_maximum_size); 	} else { 		prefix64k = 64 * 1024;-		if (state->decoded_size) {-			if (state->decoded_size < prefix64k) {-				memmove(state->out_block-					+ prefix64k - state->decoded_size,-				    state->out_block + prefix64k,-				    state->decoded_size);-				memset(state->out_block, 0,-				    prefix64k - state->decoded_size);+		if (lz4->decoded_size) {+			if (lz4->decoded_size < prefix64k) {+				memmove(lz4->out_block+					+ prefix64k - lz4->decoded_size,+				    lz4->out_block + prefix64k,+				    lz4->decoded_size);+				memset(lz4->out_block, 0,+				    prefix64k - lz4->decoded_size); 			} else {-				memmove(state->out_block,-				    state->out_block + state->decoded_size,+				memmove(lz4->out_block,+				    lz4->out_block + lz4->decoded_size, 				    prefix64k); 			} 		} #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7 		uncompressed_size = LZ4_decompress_safe_usingDict( 		    read_buf + 4,-		    state->out_block + prefix64k, (int)compressed_size,-		    state->flags.block_maximum_size,-		    state->out_block,+		    lz4->out_block + prefix64k, (int)compressed_size,+		    lz4->flags.block_maximum_size,+		    lz4->out_block, 		    (int)prefix64k); #else 		uncompressed_size = LZ4_decompress_safe_withPrefix64k( 		    read_buf + 4,-		    state->out_block + prefix64k, (int)compressed_size,-		    state->flags.block_maximum_size);+		    lz4->out_block + prefix64k, (int)compressed_size,+		    lz4->flags.block_maximum_size); #endif 	}  	/* Check if an error occurred in the decompression process. */ 	if (uncompressed_size < 0) {-		archive_set_error(&(self->archive->archive),+		archive_set_error(&(f->archive->archive), 		    ARCHIVE_ERRNO_MISC, "lz4 decompression failed"); 		return (ARCHIVE_FATAL); 	} -	state->unconsumed = 4 + compressed_size + checksum_size;-	*p = state->out_block + prefix64k;-	state->decoded_size = uncompressed_size;+	lz4->unconsumed = 4 + compressed_size + checksum_size;+	*p = lz4->out_block + prefix64k;+	lz4->decoded_size = uncompressed_size; 	return uncompressed_size;  malformed_error:-	archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+	archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, 	    "malformed lz4 data"); 	return (ARCHIVE_FATAL); truncated_error:-	archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+	archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, 	    "truncated lz4 input"); 	return (ARCHIVE_FATAL); }  static ssize_t-lz4_filter_read_default_stream(struct archive_read_filter *self, const void **p)+lz4_filter_read_default_stream(struct archive_read_filter *f, const void **p) {-	struct private_data *state = (struct private_data *)self->data;+	struct lz4 *lz4 = f->data; 	const char *read_buf; 	ssize_t ret; -	if (state->stage == SELECT_STREAM) {-		state->stage = READ_DEFAULT_STREAM;+	if (lz4->stage == SELECT_STREAM) {+		lz4->stage = READ_DEFAULT_STREAM; 		/* First, read a descriptor. */-		if((ret = lz4_filter_read_descriptor(self)) != ARCHIVE_OK)+		if((ret = lz4_filter_read_descriptor(f)) != ARCHIVE_OK) 			return (ret);-		state->stage = READ_DEFAULT_BLOCK;+		lz4->stage = READ_DEFAULT_BLOCK; 	} 	/* Decompress a block. */-	ret = lz4_filter_read_data_block(self, p);+	ret = lz4_filter_read_data_block(f, p);  	/* If the end of block is detected, change the filter status 	   to read next stream. */ 	if (ret == 0 && *p == NULL)-		state->stage = SELECT_STREAM;+		lz4->stage = SELECT_STREAM;  	/* Optional processing, checking a stream sum. */-	if (state->flags.stream_checksum) {-		if (state->stage == SELECT_STREAM) {+	if (lz4->flags.stream_checksum) {+		if (lz4->stage == SELECT_STREAM) { 			unsigned int checksum; 			unsigned int checksum_stream;-			read_buf = __archive_read_filter_ahead(self->upstream,+			read_buf = __archive_read_filter_ahead(f->upstream, 			    4, NULL); 			if (read_buf == NULL) {-				archive_set_error(&self->archive->archive,+				archive_set_error(&f->archive->archive, 				    ARCHIVE_ERRNO_MISC, "truncated lz4 input"); 				return (ARCHIVE_FATAL); 			} 			checksum = archive_le32dec(read_buf);-			__archive_read_filter_consume(self->upstream, 4);+			__archive_read_filter_consume(f->upstream, 4); 			checksum_stream = __archive_xxhash.XXH32_digest(-			    state->xxh32_state);-			state->xxh32_state = NULL;+			    lz4->xxh32_state);+			lz4->xxh32_state = NULL; 			if (checksum != checksum_stream) { #ifndef DONT_FAIL_ON_CRC_ERROR-				archive_set_error(&self->archive->archive,+				archive_set_error(&f->archive->archive, 				    ARCHIVE_ERRNO_MISC, 				    "lz4 stream checksum error"); 				return (ARCHIVE_FATAL); #endif 			} 		} else if (ret > 0)-			__archive_xxhash.XXH32_update(state->xxh32_state,+			__archive_xxhash.XXH32_update(lz4->xxh32_state, 			    *p, (int)ret); 	} 	return (ret); }  static ssize_t-lz4_filter_read_legacy_stream(struct archive_read_filter *self, const void **p)+lz4_filter_read_legacy_stream(struct archive_read_filter *f, const void **p) {-	struct private_data *state = (struct private_data *)self->data;+	struct lz4 *lz4 = f->data; 	uint32_t compressed; 	const char *read_buf; 	ssize_t ret;  	*p = NULL;-	ret = lz4_allocate_out_block_for_legacy(self);+	ret = lz4_allocate_out_block_for_legacy(f); 	if (ret != ARCHIVE_OK) 		return ret;  	/* Make sure we have 4 bytes for a block size. */-	read_buf = __archive_read_filter_ahead(self->upstream, 4, NULL);+	read_buf = __archive_read_filter_ahead(f->upstream, 4, NULL); 	if (read_buf == NULL) {-		if (state->stage == SELECT_STREAM) {-			state->stage = READ_LEGACY_STREAM;-			archive_set_error(&self->archive->archive,+		if (lz4->stage == SELECT_STREAM) {+			lz4->stage = READ_LEGACY_STREAM;+			archive_set_error(&f->archive->archive, 			    ARCHIVE_ERRNO_MISC, 			    "truncated lz4 input"); 			return (ARCHIVE_FATAL); 		}-		state->stage = SELECT_STREAM;+		lz4->stage = SELECT_STREAM; 		return 0; 	}-	state->stage = READ_LEGACY_BLOCK;+	lz4->stage = READ_LEGACY_BLOCK; 	compressed = archive_le32dec(read_buf); 	if (compressed > LZ4_COMPRESSBOUND(LEGACY_BLOCK_SIZE)) {-		state->stage = SELECT_STREAM;+		lz4->stage = SELECT_STREAM; 		return 0; 	}  	/* Make sure we have a whole block. */-	read_buf = __archive_read_filter_ahead(self->upstream,+	read_buf = __archive_read_filter_ahead(f->upstream, 	    4 + compressed, NULL); 	if (read_buf == NULL) {-		archive_set_error(&(self->archive->archive),+		archive_set_error(&(f->archive->archive), 		    ARCHIVE_ERRNO_MISC, "truncated lz4 input"); 		return (ARCHIVE_FATAL); 	}-	ret = LZ4_decompress_safe(read_buf + 4, state->out_block,-	    compressed, (int)state->out_block_size);+	ret = LZ4_decompress_safe(read_buf + 4, lz4->out_block,+	    compressed, (int)lz4->out_block_size); 	if (ret < 0) {-		archive_set_error(&(self->archive->archive),+		archive_set_error(&(f->archive->archive), 		    ARCHIVE_ERRNO_MISC, "lz4 decompression failed"); 		return (ARCHIVE_FATAL); 	}-	*p = state->out_block;-	state->unconsumed = 4 + compressed;+	*p = lz4->out_block;+	lz4->unconsumed = 4 + compressed; 	return ret; } @@ -815,15 +815,14 @@  * Clean up the decompressor.  */ static int-lz4_filter_close(struct archive_read_filter *self)+lz4_filter_close(struct archive_read_filter *f) {-	struct private_data *state;+	struct lz4 *lz4 = f->data; 	int ret = ARCHIVE_OK; -	state = (struct private_data *)self->data;-	free(state->xxh32_state);-	free(state->out_block);-	free(state);+	free(lz4->xxh32_state);+	free(lz4->out_block);+	free(lz4); 	return (ret); } 
c/archive_read_support_filter_lzop.c view
@@ -68,7 +68,7 @@ #define LZOP_HEADER_MAGIC_LEN 9  #if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)-struct read_lzop {+struct lzop { 	unsigned char	*out_block; 	size_t		 out_block_size; 	int		 flags;@@ -127,14 +127,14 @@  * Bidder just verifies the header and returns the number of verified bits.  */ static int-lzop_bidder_bid(struct archive_read_filter_bidder *self,-    struct archive_read_filter *filter)+lzop_bidder_bid(struct archive_read_filter_bidder *b,+    struct archive_read_filter *f) { 	const unsigned char *p; -	(void)self; /* UNUSED */+	(void)b; /* UNUSED */ -	p = __archive_read_filter_ahead(filter, LZOP_HEADER_MAGIC_LEN, NULL);+	p = __archive_read_filter_ahead(f, LZOP_HEADER_MAGIC_LEN, NULL); 	if (p == NULL) 		return (0); @@ -151,16 +151,16 @@  * in case that's available.  */ static int-lzop_bidder_init(struct archive_read_filter *self)+lzop_bidder_init(struct archive_read_filter *f) { 	int r; -	r = __archive_read_program(self, "lzop -d");+	r = __archive_read_program(f, "lzop -d"); 	/* Note: We set the format here even if __archive_read_program() 	 * above fails.  We do, after all, know what the format is 	 * even if we weren't able to read it. */-	self->code = ARCHIVE_FILTER_LZOP;-	self->name = "lzop";+	f->code = ARCHIVE_FILTER_LZOP;+	f->name = "lzop"; 	return (r); } #else@@ -175,47 +175,47 @@  * Initialize the filter object.  */ static int-lzop_bidder_init(struct archive_read_filter *self)+lzop_bidder_init(struct archive_read_filter *f) {-	struct read_lzop *state;+	struct lzop *lzop; -	self->code = ARCHIVE_FILTER_LZOP;-	self->name = "lzop";+	f->code = ARCHIVE_FILTER_LZOP;+	f->name = "lzop"; -	state = calloc(1, sizeof(*state));-	if (state == NULL) {-		archive_set_error(&self->archive->archive, ENOMEM,+	lzop = calloc(1, sizeof(*lzop));+	if (lzop == NULL) {+		archive_set_error(&f->archive->archive, ENOMEM, 		    "Can't allocate data for lzop decompression"); 		return (ARCHIVE_FATAL); 	} -	self->data = state;-	self->vtable = &lzop_reader_vtable;+	f->data = lzop;+	f->vtable = &lzop_reader_vtable;  	return (ARCHIVE_OK); }  static int-consume_header(struct archive_read_filter *self)+consume_header(struct archive_read_filter *f) {-	struct read_lzop *state = (struct read_lzop *)self->data;+	struct lzop *lzop = f->data; 	const unsigned char *p, *_p; 	unsigned checksum, flags, len, method, version;  	/* 	 * Check LZOP magic code. 	 */-	p = __archive_read_filter_ahead(self->upstream,+	p = __archive_read_filter_ahead(f->upstream, 		LZOP_HEADER_MAGIC_LEN, NULL); 	if (p == NULL) 		return (ARCHIVE_EOF);  	if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN)) 		return (ARCHIVE_EOF);-	__archive_read_filter_consume(self->upstream,+	__archive_read_filter_consume(f->upstream, 	    LZOP_HEADER_MAGIC_LEN); -	p = __archive_read_filter_ahead(self->upstream, 29, NULL);+	p = __archive_read_filter_ahead(f->upstream, 29, NULL); 	if (p == NULL) 		goto truncated; 	_p = p;@@ -225,7 +225,7 @@ 	if (version >= 0x940) { 		unsigned reqversion = archive_be16dec(p); p += 2; 		if (reqversion < 0x900) {-			archive_set_error(&self->archive->archive,+			archive_set_error(&f->archive->archive, 			    ARCHIVE_ERRNO_MISC, "Invalid required version"); 			return (ARCHIVE_FAILED); 		}@@ -233,7 +233,7 @@  	method = *p++; 	if (method < 1 || method > 3) {-		archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+		archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, 		    "Unsupported method"); 		return (ARCHIVE_FAILED); 	}@@ -252,7 +252,7 @@ 			;/* NOP */ #endif 		else if (level > 9) {-			archive_set_error(&self->archive->archive,+			archive_set_error(&f->archive->archive, 			    ARCHIVE_ERRNO_MISC, "Invalid level"); 			return (ARCHIVE_FAILED); 		}@@ -270,7 +270,7 @@ 	len = *p++; /* Read filename length */ 	len += p - _p; 	/* Make sure we have all bytes we need to calculate checksum. */-	p = __archive_read_filter_ahead(self->upstream, len + 4, NULL);+	p = __archive_read_filter_ahead(f->upstream, len + 4, NULL); 	if (p == NULL) 		goto truncated; 	if (flags & CRC32_HEADER)@@ -281,146 +281,146 @@ 	if (archive_be32dec(p + len) != checksum) 		goto corrupted; #endif-	__archive_read_filter_consume(self->upstream, len + 4);+	__archive_read_filter_consume(f->upstream, len + 4); 	if (flags & EXTRA_FIELD) { 		/* Skip extra field */-		p = __archive_read_filter_ahead(self->upstream, 4, NULL);+		p = __archive_read_filter_ahead(f->upstream, 4, NULL); 		if (p == NULL) 			goto truncated; 		len = archive_be32dec(p);-		__archive_read_filter_consume(self->upstream,+		__archive_read_filter_consume(f->upstream, 		    (int64_t)len + 4 + 4); 	}-	state->flags = flags;-	state->in_stream = 1;+	lzop->flags = flags;+	lzop->in_stream = 1; 	return (ARCHIVE_OK); truncated:-	archive_set_error(&self->archive->archive,+	archive_set_error(&f->archive->archive, 	    ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data"); 	return (ARCHIVE_FAILED); corrupted:-	archive_set_error(&self->archive->archive,+	archive_set_error(&f->archive->archive, 	    ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header"); 	return (ARCHIVE_FAILED); }  static int-consume_block_info(struct archive_read_filter *self)+consume_block_info(struct archive_read_filter *f) {-	struct read_lzop *state = (struct read_lzop *)self->data;+	struct lzop *lzop = f->data; 	const unsigned char *p;-	unsigned flags = state->flags;+	unsigned flags = lzop->flags; -	p = __archive_read_filter_ahead(self->upstream, 4, NULL);+	p = __archive_read_filter_ahead(f->upstream, 4, NULL); 	if (p == NULL) 		goto truncated;-	state->uncompressed_size = archive_be32dec(p);-	__archive_read_filter_consume(self->upstream, 4);-	if (state->uncompressed_size == 0)+	lzop->uncompressed_size = archive_be32dec(p);+	__archive_read_filter_consume(f->upstream, 4);+	if (lzop->uncompressed_size == 0) 		return (ARCHIVE_EOF);-	if (state->uncompressed_size > MAX_BLOCK_SIZE)+	if (lzop->uncompressed_size > MAX_BLOCK_SIZE) 		goto corrupted; -	p = __archive_read_filter_ahead(self->upstream, 4, NULL);+	p = __archive_read_filter_ahead(f->upstream, 4, NULL); 	if (p == NULL) 		goto truncated;-	state->compressed_size = archive_be32dec(p);-	__archive_read_filter_consume(self->upstream, 4);-	if (state->compressed_size > state->uncompressed_size)+	lzop->compressed_size = archive_be32dec(p);+	__archive_read_filter_consume(f->upstream, 4);+	if (lzop->compressed_size > lzop->uncompressed_size) 		goto corrupted;  	if (flags & (CRC32_UNCOMPRESSED | ADLER32_UNCOMPRESSED)) {-		p = __archive_read_filter_ahead(self->upstream, 4, NULL);+		p = __archive_read_filter_ahead(f->upstream, 4, NULL); 		if (p == NULL) 			goto truncated;-		state->compressed_cksum = state->uncompressed_cksum =+		lzop->compressed_cksum = lzop->uncompressed_cksum = 		    archive_be32dec(p);-		__archive_read_filter_consume(self->upstream, 4);+		__archive_read_filter_consume(f->upstream, 4); 	} 	if ((flags & (CRC32_COMPRESSED | ADLER32_COMPRESSED)) &&-	    state->compressed_size < state->uncompressed_size) {-		p = __archive_read_filter_ahead(self->upstream, 4, NULL);+	    lzop->compressed_size < lzop->uncompressed_size) {+		p = __archive_read_filter_ahead(f->upstream, 4, NULL); 		if (p == NULL) 			goto truncated;-		state->compressed_cksum = archive_be32dec(p);-		__archive_read_filter_consume(self->upstream, 4);+		lzop->compressed_cksum = archive_be32dec(p);+		__archive_read_filter_consume(f->upstream, 4); 	} 	return (ARCHIVE_OK); truncated:-	archive_set_error(&self->archive->archive,+	archive_set_error(&f->archive->archive, 	    ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data"); 	return (ARCHIVE_FAILED); corrupted:-	archive_set_error(&self->archive->archive,+	archive_set_error(&f->archive->archive, 	    ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header"); 	return (ARCHIVE_FAILED); }  static ssize_t-lzop_filter_read(struct archive_read_filter *self, const void **p)+lzop_filter_read(struct archive_read_filter *f, const void **p) {-	struct read_lzop *state = (struct read_lzop *)self->data;+	struct lzop *lzop = f->data; 	const void *b; 	lzo_uint out_size; 	uint32_t cksum; 	int ret, r; -	if (state->unconsumed_bytes) {-		__archive_read_filter_consume(self->upstream,-		    state->unconsumed_bytes);-		state->unconsumed_bytes = 0;+	if (lzop->unconsumed_bytes) {+		__archive_read_filter_consume(f->upstream,+		    lzop->unconsumed_bytes);+		lzop->unconsumed_bytes = 0; 	}-	if (state->eof)+	if (lzop->eof) 		return (0);  	for (;;) {-		if (!state->in_stream) {-			ret = consume_header(self);+		if (!lzop->in_stream) {+			ret = consume_header(f); 			if (ret < ARCHIVE_OK) 				return (ret); 			if (ret == ARCHIVE_EOF) {-				state->eof = 1;+				lzop->eof = 1; 				return (0); 			} 		}-		ret = consume_block_info(self);+		ret = consume_block_info(f); 		if (ret < ARCHIVE_OK) 			return (ret); 		if (ret == ARCHIVE_EOF)-			state->in_stream = 0;+			lzop->in_stream = 0; 		else 			break; 	} -	if (state->out_block == NULL ||-	    state->out_block_size < state->uncompressed_size) {+	if (lzop->out_block == NULL ||+	    lzop->out_block_size < lzop->uncompressed_size) { 		void *new_block; -		new_block = realloc(state->out_block, state->uncompressed_size);+		new_block = realloc(lzop->out_block, lzop->uncompressed_size); 		if (new_block == NULL) {-			archive_set_error(&self->archive->archive, ENOMEM,+			archive_set_error(&f->archive->archive, ENOMEM, 			    "Can't allocate data for lzop decompression"); 			return (ARCHIVE_FATAL); 		}-		state->out_block = new_block;-		state->out_block_size = state->uncompressed_size;+		lzop->out_block = new_block;+		lzop->out_block_size = lzop->uncompressed_size; 	} -	b = __archive_read_filter_ahead(self->upstream,-		state->compressed_size, NULL);+	b = __archive_read_filter_ahead(f->upstream,+		lzop->compressed_size, NULL); 	if (b == NULL) {-		archive_set_error(&self->archive->archive,+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data"); 		return (ARCHIVE_FATAL); 	}-	if (state->flags & CRC32_COMPRESSED)-		cksum = crc32(crc32(0, NULL, 0), b, state->compressed_size);-	else if (state->flags & ADLER32_COMPRESSED)-		cksum = adler32(adler32(0, NULL, 0), b, state->compressed_size);+	if (lzop->flags & CRC32_COMPRESSED)+		cksum = crc32(crc32(0, NULL, 0), b, lzop->compressed_size);+	else if (lzop->flags & ADLER32_COMPRESSED)+		cksum = adler32(adler32(0, NULL, 0), b, lzop->compressed_size); 	else-		cksum = state->compressed_cksum;-	if (cksum != state->compressed_cksum) {-		archive_set_error(&self->archive->archive,+		cksum = lzop->compressed_cksum;+	if (cksum != lzop->compressed_cksum) {+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_MISC, "Corrupted data"); 		return (ARCHIVE_FATAL); 	}@@ -429,51 +429,51 @@ 	 * If both uncompressed size and compressed size are the same, 	 * we do not decompress this block. 	 */-	if (state->uncompressed_size == state->compressed_size) {+	if (lzop->uncompressed_size == lzop->compressed_size) { 		*p = b;-		state->unconsumed_bytes = state->compressed_size;-		return ((ssize_t)state->uncompressed_size);+		lzop->unconsumed_bytes = lzop->compressed_size;+		return ((ssize_t)lzop->uncompressed_size); 	}  	/* 	 * Drive lzo uncompression. 	 */-	out_size = (lzo_uint)state->uncompressed_size;-	r = lzo1x_decompress_safe(b, (lzo_uint)state->compressed_size,-		state->out_block, &out_size, NULL);+	out_size = (lzo_uint)lzop->uncompressed_size;+	r = lzo1x_decompress_safe(b, (lzo_uint)lzop->compressed_size,+		lzop->out_block, &out_size, NULL); 	switch (r) { 	case LZO_E_OK:-		if (out_size == state->uncompressed_size)+		if (out_size == lzop->uncompressed_size) 			break;-		archive_set_error(&self->archive->archive,+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_MISC, "Corrupted data"); 		return (ARCHIVE_FATAL); 	case LZO_E_OUT_OF_MEMORY:-		archive_set_error(&self->archive->archive, ENOMEM,+		archive_set_error(&f->archive->archive, ENOMEM, 		    "lzop decompression failed: out of memory"); 		return (ARCHIVE_FATAL); 	default:-		archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+		archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, 		    "lzop decompression failed: %d", r); 		return (ARCHIVE_FATAL); 	} -	if (state->flags & CRC32_UNCOMPRESSED)-		cksum = crc32(crc32(0, NULL, 0), state->out_block,-		    state->uncompressed_size);-	else if (state->flags & ADLER32_UNCOMPRESSED)-		cksum = adler32(adler32(0, NULL, 0), state->out_block,-		    state->uncompressed_size);+	if (lzop->flags & CRC32_UNCOMPRESSED)+		cksum = crc32(crc32(0, NULL, 0), lzop->out_block,+		    lzop->uncompressed_size);+	else if (lzop->flags & ADLER32_UNCOMPRESSED)+		cksum = adler32(adler32(0, NULL, 0), lzop->out_block,+		    lzop->uncompressed_size); 	else-		cksum = state->uncompressed_cksum;-	if (cksum != state->uncompressed_cksum) {-		archive_set_error(&self->archive->archive,+		cksum = lzop->uncompressed_cksum;+	if (cksum != lzop->uncompressed_cksum) {+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_MISC, "Corrupted data"); 		return (ARCHIVE_FATAL); 	} -	__archive_read_filter_consume(self->upstream, state->compressed_size);-	*p = state->out_block;+	__archive_read_filter_consume(f->upstream, lzop->compressed_size);+	*p = lzop->out_block; 	return ((ssize_t)out_size); } @@ -481,12 +481,12 @@  * Clean up the decompressor.  */ static int-lzop_filter_close(struct archive_read_filter *self)+lzop_filter_close(struct archive_read_filter *f) {-	struct read_lzop *state = (struct read_lzop *)self->data;+	struct lzop *lzop = f->data; -	free(state->out_block);-	free(state);+	free(lzop->out_block);+	free(lzop); 	return (ARCHIVE_OK); } 
c/archive_read_support_filter_program.c view
@@ -87,7 +87,7 @@  * bid twice in the same pipeline.  */ struct program_bidder {-	char *description;+	struct archive_string description; 	char *cmd; 	void *signature; 	size_t signature_len;@@ -102,7 +102,7 @@ /*  * The actual filter needs to track input and output data.  */-struct program_filter {+struct program { 	struct archive_string description; #if defined(_WIN32) && !defined(__CYGWIN__) 	HANDLE		 child;@@ -145,6 +145,8 @@ 	state->cmd = strdup(cmd); 	if (state->cmd == NULL) 		goto memerr;+	archive_strcpy(&state->description, "Program: ");+	archive_strcat(&state->description, cmd);  	if (signature != NULL && signature_len > 0) { 		state->signature_len = signature_len;@@ -168,9 +170,9 @@ }  static void-program_bidder_free(struct archive_read_filter_bidder *self)+program_bidder_free(struct archive_read_filter_bidder *b) {-	struct program_bidder *state = (struct program_bidder *)self->data;+	struct program_bidder *state = (struct program_bidder *)b->data;  	free_state(state); }@@ -180,6 +182,7 @@ {  	if (state) {+		archive_string_free(&state->description); 		free(state->cmd); 		free(state->signature); 		free(state);@@ -193,15 +196,15 @@  * we're called, then never bid again.  */ static int-program_bidder_bid(struct archive_read_filter_bidder *self,-    struct archive_read_filter *upstream)+program_bidder_bid(struct archive_read_filter_bidder *b,+    struct archive_read_filter *f) {-	struct program_bidder *state = self->data;+	struct program_bidder *state = b->data; 	const char *p;  	/* If we have a signature, use that to match. */ 	if (state->signature_len > 0) {-		p = __archive_read_filter_ahead(upstream,+		p = __archive_read_filter_ahead(f, 		    state->signature_len, NULL); 		if (p == NULL) 			return (0);@@ -226,36 +229,36 @@  * (including error message if the child came to a bad end).  */ static int-child_stop(struct archive_read_filter *self, struct program_filter *state)+child_stop(struct archive_read_filter *f, struct program *program) { 	/* Close our side of the I/O with the child. */-	if (state->child_stdin != -1) {-		close(state->child_stdin);-		state->child_stdin = -1;+	if (program->child_stdin != -1) {+		close(program->child_stdin);+		program->child_stdin = -1; 	}-	if (state->child_stdout != -1) {-		close(state->child_stdout);-		state->child_stdout = -1;+	if (program->child_stdout != -1) {+		close(program->child_stdout);+		program->child_stdout = -1; 	} -	if (state->child != 0) {+	if (program->child != 0) { 		/* Reap the child. */ 		do {-			state->waitpid_return-			    = waitpid(state->child, &state->exit_status, 0);-		} while (state->waitpid_return == -1 && errno == EINTR);-		state->child = 0;+			program->waitpid_return+			    = waitpid(program->child, &program->exit_status, 0);+		} while (program->waitpid_return == -1 && errno == EINTR);+		program->child = 0; 	} -	if (state->waitpid_return < 0) {+	if (program->waitpid_return < 0) { 		/* waitpid() failed?  This is ugly. */-		archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+		archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, 		    "Error closing child process"); 		return (ARCHIVE_WARN); 	}  #if !defined(_WIN32) || defined(__CYGWIN__)-	if (WIFSIGNALED(state->exit_status)) {+	if (WIFSIGNALED(program->exit_status)) { #ifdef SIGPIPE 		/* If the child died because we stopped reading before 		 * it was done, that's okay.  Some archive formats@@ -263,24 +266,24 @@ 		/* The alternative to this would be to add a step 		 * before close(child_stdout) above to read from the 		 * child until the child has no more to write. */-		if (WTERMSIG(state->exit_status) == SIGPIPE)+		if (WTERMSIG(program->exit_status) == SIGPIPE) 			return (ARCHIVE_OK); #endif-		archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+		archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, 		    "Child process exited with signal %d",-		    WTERMSIG(state->exit_status));+		    WTERMSIG(program->exit_status)); 		return (ARCHIVE_WARN); 	} #endif /* !_WIN32 || __CYGWIN__ */ -	if (WIFEXITED(state->exit_status)) {-		if (WEXITSTATUS(state->exit_status) == 0)+	if (WIFEXITED(program->exit_status)) {+		if (WEXITSTATUS(program->exit_status) == 0) 			return (ARCHIVE_OK); -		archive_set_error(&self->archive->archive,+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_MISC, 		    "Child process exited with status %d",-		    WEXITSTATUS(state->exit_status));+		    WEXITSTATUS(program->exit_status)); 		return (ARCHIVE_WARN); 	} @@ -291,13 +294,13 @@  * Use select() to decide whether the child is ready for read or write.  */ static ssize_t-child_read(struct archive_read_filter *self, char *buf, size_t buf_len)+child_read(struct archive_read_filter *f, char *buf, size_t buf_len) {-	struct program_filter *state = self->data;+	struct program *program = f->data; 	ssize_t ret, requested, avail; 	const char *p; #if defined(_WIN32) && !defined(__CYGWIN__)-	HANDLE handle = (HANDLE)_get_osfhandle(state->child_stdout);+	HANDLE handle = (HANDLE)_get_osfhandle(program->child_stdout); #endif  	requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len;@@ -325,7 +328,7 @@ 				break; 			} #endif-			ret = read(state->child_stdout, buf, requested);+			ret = read(program->child_stdout, buf, requested); 		} while (ret == -1 && errno == EINTR);  		if (ret > 0)@@ -333,44 +336,44 @@ 		if (ret == 0 || (ret == -1 && errno == EPIPE)) 			/* Child has closed its output; reap the child 			 * and return the status. */-			return (child_stop(self, state));+			return (child_stop(f, program)); 		if (ret == -1 && errno != EAGAIN) 			return (-1); -		if (state->child_stdin == -1) {+		if (program->child_stdin == -1) { 			/* Block until child has some I/O ready. */-			__archive_check_child(state->child_stdin,-			    state->child_stdout);+			__archive_check_child(program->child_stdin,+			    program->child_stdout); 			continue; 		}  		/* Get some more data from upstream. */-		p = __archive_read_filter_ahead(self->upstream, 1, &avail);+		p = __archive_read_filter_ahead(f->upstream, 1, &avail); 		if (p == NULL) {-			close(state->child_stdin);-			state->child_stdin = -1;-			fcntl(state->child_stdout, F_SETFL, 0);+			close(program->child_stdin);+			program->child_stdin = -1;+			fcntl(program->child_stdout, F_SETFL, 0); 			if (avail < 0) 				return (avail); 			continue; 		}  		do {-			ret = write(state->child_stdin, p, avail);+			ret = write(program->child_stdin, p, avail); 		} while (ret == -1 && errno == EINTR);  		if (ret > 0) { 			/* Consume whatever we managed to write. */-			__archive_read_filter_consume(self->upstream, ret);+			__archive_read_filter_consume(f->upstream, ret); 		} else if (ret == -1 && errno == EAGAIN) { 			/* Block until child has some I/O ready. */-			__archive_check_child(state->child_stdin,-			    state->child_stdout);+			__archive_check_child(program->child_stdin,+			    program->child_stdout); 		} else { 			/* Write failed. */-			close(state->child_stdin);-			state->child_stdin = -1;-			fcntl(state->child_stdout, F_SETFL, 0);+			close(program->child_stdin);+			program->child_stdin = -1;+			fcntl(program->child_stdout, F_SETFL, 0); 			/* If it was a bad error, we're done; otherwise 			 * it was EPIPE or EOF, and we can still read 			 * from the child. */@@ -387,9 +390,9 @@ };  int-__archive_read_program(struct archive_read_filter *self, const char *cmd)+__archive_read_program(struct archive_read_filter *f, const char *cmd) {-	struct program_filter	*state;+	struct program *program; 	static const size_t out_buf_len = 65536; 	char *out_buf; 	const char *prefix = "Program: ";@@ -397,70 +400,71 @@ 	size_t l;  	l = strlen(prefix) + strlen(cmd) + 1;-	state = calloc(1, sizeof(*state));+	program = calloc(1, sizeof(*program)); 	out_buf = malloc(out_buf_len);-	if (state == NULL || out_buf == NULL ||-	    archive_string_ensure(&state->description, l) == NULL) {-		archive_set_error(&self->archive->archive, ENOMEM,+	if (program == NULL || out_buf == NULL ||+	    archive_string_ensure(&program->description, l) == NULL) {+		archive_set_error(&f->archive->archive, ENOMEM, 		    "Can't allocate input data");-		if (state != NULL) {-			archive_string_free(&state->description);-			free(state);+		if (program != NULL) {+			archive_string_free(&program->description);+			free(program); 		} 		free(out_buf); 		return (ARCHIVE_FATAL); 	}-	archive_strcpy(&state->description, prefix);-	archive_strcat(&state->description, cmd);+	archive_strcpy(&program->description, prefix);+	archive_strcat(&program->description, cmd); -	self->code = ARCHIVE_FILTER_PROGRAM;-	self->name = state->description.s;+	f->code = ARCHIVE_FILTER_PROGRAM;+	f->name = program->description.s; -	state->out_buf = out_buf;-	state->out_buf_len = out_buf_len;+	program->out_buf = out_buf;+	program->out_buf_len = out_buf_len; -	ret = __archive_create_child(cmd, &state->child_stdin,-	    &state->child_stdout, &state->child);+	ret = __archive_create_child(cmd, &program->child_stdin,+	    &program->child_stdout, &program->child); 	if (ret != ARCHIVE_OK) {-		free(state->out_buf);-		archive_string_free(&state->description);-		free(state);-		archive_set_error(&self->archive->archive, EINVAL,+		free(program->out_buf);+		archive_string_free(&program->description);+		free(program);+		archive_set_error(&f->archive->archive, EINVAL, 		    "Can't initialize filter; unable to run program \"%s\"", 		    cmd); 		return (ARCHIVE_FATAL); 	} -	self->data = state;-	self->vtable = &program_reader_vtable;+	f->data = program;+	f->vtable = &program_reader_vtable;  	/* XXX Check that we can read at least one byte? */ 	return (ARCHIVE_OK); }  static int-program_bidder_init(struct archive_read_filter *self)+program_bidder_init(struct archive_read_filter *f) { 	struct program_bidder   *bidder_state;+	int r; -	bidder_state = (struct program_bidder *)self->bidder->data;-	return (__archive_read_program(self, bidder_state->cmd));+	bidder_state = (struct program_bidder *)f->bidder->data;+	r = __archive_read_program(f, bidder_state->cmd);+	f->name = bidder_state->description.s;+	return (r); }  static ssize_t-program_filter_read(struct archive_read_filter *self, const void **buff)+program_filter_read(struct archive_read_filter *f, const void **buff) {-	struct program_filter *state;+	struct program *program = f->data; 	ssize_t bytes; 	size_t total; 	char *p; -	state = (struct program_filter *)self->data;- 	total = 0;-	p = state->out_buf;-	while (state->child_stdout != -1 && total < state->out_buf_len) {-		bytes = child_read(self, p, state->out_buf_len - total);+	p = program->out_buf;+	while (program->child_stdout != -1 && total < program->out_buf_len) {+		bytes = child_read(f, p, program->out_buf_len - total); 		if (bytes < 0) 			/* No recovery is possible if we can no longer 			 * read from the child. */@@ -472,23 +476,22 @@ 		p += bytes; 	} -	*buff = state->out_buf;+	*buff = program->out_buf; 	return (total); }  static int-program_filter_close(struct archive_read_filter *self)+program_filter_close(struct archive_read_filter *f) {-	struct program_filter	*state;+	struct program *program = f->data; 	int e; -	state = (struct program_filter *)self->data;-	e = child_stop(self, state);+	e = child_stop(f, program);  	/* Release our private data. */-	free(state->out_buf);-	archive_string_free(&state->description);-	free(state);+	free(program->out_buf);+	archive_string_free(&program->description);+	free(program);  	return (e); }
c/archive_read_support_filter_rpm.c view
@@ -76,38 +76,38 @@ }  static int-rpm_bidder_bid(struct archive_read_filter_bidder *self,-    struct archive_read_filter *filter)+rpm_bidder_bid(struct archive_read_filter_bidder *b,+    struct archive_read_filter *f) {-	const unsigned char *b;+	const unsigned char *p; 	int bits_checked; -	(void)self; /* UNUSED */+	(void)b; /* UNUSED */ -	b = __archive_read_filter_ahead(filter, 8, NULL);-	if (b == NULL)+	p = __archive_read_filter_ahead(f, 8, NULL);+	if (p == NULL) 		return (0);  	bits_checked = 0; 	/* 	 * Verify Header Magic Bytes : 0XED 0XAB 0XEE 0XDB 	 */-	if (memcmp(b, "\xED\xAB\xEE\xDB", 4) != 0)+	if (memcmp(p, "\xED\xAB\xEE\xDB", 4) != 0) 		return (0); 	bits_checked += 32; 	/* 	 * Check major version. 	 */-	if (b[4] != 3 && b[4] != 4)+	if (p[4] != 3 && p[4] != 4) 		return (0); 	bits_checked += 8; 	/* 	 * Check package type; binary or source. 	 */-	if (b[6] != 0)+	if (p[6] != 0) 		return (0); 	bits_checked += 8;-	if (b[7] != 0 && b[7] != 1)+	if (p[7] != 0 && p[7] != 1) 		return (0); 	bits_checked += 8; @@ -121,40 +121,40 @@ };  static int-rpm_bidder_init(struct archive_read_filter *self)+rpm_bidder_init(struct archive_read_filter *f) { 	struct rpm   *rpm; -	self->code = ARCHIVE_FILTER_RPM;-	self->name = "rpm";+	f->code = ARCHIVE_FILTER_RPM;+	f->name = "rpm";  	rpm = calloc(1, sizeof(*rpm)); 	if (rpm == NULL) {-		archive_set_error(&self->archive->archive, ENOMEM,+		archive_set_error(&f->archive->archive, ENOMEM, 		    "Can't allocate data for rpm"); 		return (ARCHIVE_FATAL); 	} -	self->data = rpm;+	f->data = rpm; 	rpm->data_reached = 0;-	self->vtable = &rpm_reader_vtable;+	f->vtable = &rpm_reader_vtable;  	return (ARCHIVE_OK); }  static ssize_t-skip_padding(struct archive_read_filter *self)+skip_padding(struct archive_read_filter *f) { 	const unsigned char *h; 	ssize_t avail, count, r;  	do {-		h = __archive_read_filter_ahead(self->upstream, 1, &avail);+		h = __archive_read_filter_ahead(f->upstream, 1, &avail); 		if (h == NULL) 			return (ARCHIVE_FATAL); 		for (count = 0; count < avail && *h++ == '\0'; count++) 			;-		r = __archive_read_filter_consume(self->upstream, count);+		r = __archive_read_filter_consume(f->upstream, count); 		if (r < 0) 			return (r); 	} while (count == avail);@@ -163,20 +163,20 @@ }  static ssize_t-skip_prologue(struct archive_read_filter *self)+skip_prologue(struct archive_read_filter *f) { 	const unsigned char *h; 	ssize_t r; 	int header, seen_header = 0;  	/* Skip lead size. */-	r = __archive_read_filter_consume(self->upstream, RPM_LEAD_SIZE);+	r = __archive_read_filter_consume(f->upstream, RPM_LEAD_SIZE); 	if (r < 0) 		return (r);  	do { 		/* Read header intro. */-		h = __archive_read_filter_ahead(self->upstream,+		h = __archive_read_filter_ahead(f->upstream, 		    RPM_MIN_HEAD_SIZE, NULL); 		if (h == NULL) 			return (ARCHIVE_FATAL);@@ -193,13 +193,13 @@ 			length = RPM_MIN_HEAD_SIZE + section * 16 + bytes;  			/* Skip header. */-			r = __archive_read_filter_consume(self->upstream,+			r = __archive_read_filter_consume(f->upstream, 			     length); 			if (r < 0) 				return (r);  			/* Skip padding. */-			r = skip_padding(self);+			r = skip_padding(f); 			if (r != ARCHIVE_OK) 				return (r); 		}@@ -208,7 +208,7 @@ 	/* At least one header must have been encountered. */ 	if (!seen_header) { 		archive_set_error(-		    &self->archive->archive,+		    &f->archive->archive, 		    ARCHIVE_ERRNO_FILE_FORMAT, 		    "Unrecognized rpm header"); 		return (ARCHIVE_FATAL);@@ -218,33 +218,30 @@ }  static ssize_t-rpm_filter_read(struct archive_read_filter *self, const void **buff)+rpm_filter_read(struct archive_read_filter *f, const void **buff) {-	struct rpm *rpm;+	struct rpm *rpm = f->data; 	ssize_t r; -	rpm = (struct rpm *)self->data;- 	if (!rpm->data_reached) {-		r = skip_prologue(self);+		r = skip_prologue(f); 		if (r != ARCHIVE_OK) 			return (r); 		rpm->data_reached = 1; 	} -	*buff = __archive_read_filter_ahead(self->upstream, 1, &r);+	*buff = __archive_read_filter_ahead(f->upstream, 1, &r); 	if (r > 0)-		__archive_read_filter_consume(self->upstream, r);+		__archive_read_filter_consume(f->upstream, r);  	return r; }  static int-rpm_filter_close(struct archive_read_filter *self)+rpm_filter_close(struct archive_read_filter *f) {-	struct rpm *rpm;+	struct rpm *rpm = f->data; -	rpm = (struct rpm *)self->data; 	free(rpm);  	return (ARCHIVE_OK);
c/archive_read_support_filter_uu.c view
@@ -43,7 +43,7 @@ /* Maximum lookahead during bid phase */ #define UUENCODE_BID_MAX_READ 128*1024 /* in bytes */ -struct uudecode {+struct uu { 	int64_t		 total; 	unsigned char	*in_buff; #define IN_BUFF_SIZE	(1024)@@ -63,7 +63,7 @@ };  static int	uudecode_bidder_bid(struct archive_read_filter_bidder *,-		    struct archive_read_filter *filter);+		    struct archive_read_filter *f); static int	uudecode_bidder_init(struct archive_read_filter *);  static int	uudecode_read_header(struct archive_read_filter *,@@ -207,7 +207,7 @@ }  static ssize_t-bid_get_line(struct archive_read_filter *filter,+bid_get_line(struct archive_read_filter *f,     const unsigned char **b, ssize_t *avail, ssize_t *ravail,     ssize_t *nl, size_t* nbytes_read) {@@ -235,12 +235,12 @@ 		if (nbytes_req < (size_t)*ravail + 160) 			nbytes_req <<= 1; -		*b = __archive_read_filter_ahead(filter, nbytes_req, avail);+		*b = __archive_read_filter_ahead(f, nbytes_req, avail); 		if (*b == NULL) { 			if (*ravail >= *avail) 				return (0); 			/* Reading bytes reaches the end of a stream. */-			*b = __archive_read_filter_ahead(filter, *avail, avail);+			*b = __archive_read_filter_ahead(f, *avail, avail); 			quit = 1; 		} 		*nbytes_read = *avail;@@ -258,42 +258,42 @@ #define UUDECODE(c) (((c) - 0x20) & 0x3f)  static int-uudecode_bidder_bid(struct archive_read_filter_bidder *self,-    struct archive_read_filter *filter)+uudecode_bidder_bid(struct archive_read_filter_bidder *b,+    struct archive_read_filter *f) {-	const unsigned char *b;+	const unsigned char *p; 	ssize_t avail, ravail; 	ssize_t len, nl; 	int l; 	int firstline; 	size_t nbytes_read; -	(void)self; /* UNUSED */+	(void)b; /* UNUSED */ -	b = __archive_read_filter_ahead(filter, 1, &avail);-	if (b == NULL)+	p = __archive_read_filter_ahead(f, 1, &avail);+	if (p == NULL) 		return (0);  	firstline = 20; 	ravail = avail; 	nbytes_read = avail; 	for (;;) {-		len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);+		len = bid_get_line(f, &p, &avail, &ravail, &nl, &nbytes_read); 		if (len < 0 || nl == 0) 			return (0); /* No match found. */-		if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)+		if (len - nl >= 11 && memcmp(p, "begin ", 6) == 0) 			l = 6;-		else if (len -nl >= 18 && memcmp(b, "begin-base64 ", 13) == 0)+		else if (len -nl >= 18 && memcmp(p, "begin-base64 ", 13) == 0) 			l = 13; 		else 			l = 0; -		if (l > 0 && (b[l] < '0' || b[l] > '7' ||-		    b[l+1] < '0' || b[l+1] > '7' ||-		    b[l+2] < '0' || b[l+2] > '7' || b[l+3] != ' '))+		if (l > 0 && (p[l] < '0' || p[l] > '7' ||+		    p[l+1] < '0' || p[l+1] > '7' ||+		    p[l+2] < '0' || p[l+2] > '7' || p[l+3] != ' ')) 			l = 0; -		b += len;+		p += len; 		avail -= len; 		if (l) 			break;@@ -305,51 +305,51 @@ 	} 	if (!avail) 		return (0);-	len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);+	len = bid_get_line(f, &p, &avail, &ravail, &nl, &nbytes_read); 	if (len < 0 || nl == 0) 		return (0);/* There are non-ascii characters. */ 	avail -= len;  	if (l == 6) { 		/* "begin " */-		if (!uuchar[*b])+		if (!uuchar[*p]) 			return (0); 		/* Get a length of decoded bytes. */-		l = UUDECODE(*b++); len--;+		l = UUDECODE(*p++); len--; 		if (l > 45) 			/* Normally, maximum length is 45(character 'M'). */ 			return (0); 		if (l > len - nl) 			return (0); /* Line too short. */ 		while (l) {-			if (!uuchar[*b++])+			if (!uuchar[*p++]) 				return (0); 			--len; 			--l; 		} 		if (len-nl == 1 &&-		    (uuchar[*b] ||		 /* Check sum. */-		     (*b >= 'a' && *b <= 'z'))) {/* Padding data(MINIX). */-			++b;+		    (uuchar[*p] ||		 /* Check sum. */+		     (*p >= 'a' && *p <= 'z'))) {/* Padding data(MINIX). */+			++p; 			--len; 		}-		b += nl;-		if (avail && uuchar[*b])+		p += nl;+		if (avail && uuchar[*p]) 			return (firstline+30); 	} else if (l == 13) { 		/* "begin-base64 " */ 		while (len-nl > 0) {-			if (!base64[*b++])+			if (!base64[*p++]) 				return (0); 			--len; 		}-		b += nl;+		p += nl; -		if (avail >= 5 && memcmp(b, "====\n", 5) == 0)+		if (avail >= 5 && memcmp(p, "====\n", 5) == 0) 			return (firstline+40);-		if (avail >= 6 && memcmp(b, "====\r\n", 6) == 0)+		if (avail >= 6 && memcmp(p, "====\r\n", 6) == 0) 			return (firstline+40);-		if (avail > 0 && base64[*b])+		if (avail > 0 && base64[*p]) 			return (firstline+30); 	} @@ -364,46 +364,46 @@ };  static int-uudecode_bidder_init(struct archive_read_filter *self)+uudecode_bidder_init(struct archive_read_filter *f) {-	struct uudecode   *uudecode;+	struct uu   *uu; 	void *out_buff; 	void *in_buff; -	self->code = ARCHIVE_FILTER_UU;-	self->name = "uu";+	f->code = ARCHIVE_FILTER_UU;+	f->name = "uu"; -	uudecode = calloc(1, sizeof(*uudecode));+	uu = calloc(1, sizeof(*uu)); 	out_buff = malloc(OUT_BUFF_SIZE); 	in_buff = malloc(IN_BUFF_SIZE);-	if (uudecode == NULL || out_buff == NULL || in_buff == NULL) {-		archive_set_error(&self->archive->archive, ENOMEM,+	if (uu == NULL || out_buff == NULL || in_buff == NULL) {+		archive_set_error(&f->archive->archive, ENOMEM, 		    "Can't allocate data for uudecode");-		free(uudecode);+		free(uu); 		free(out_buff); 		free(in_buff); 		return (ARCHIVE_FATAL); 	} -	self->data = uudecode;-	uudecode->in_buff = in_buff;-	uudecode->in_cnt = 0;-	uudecode->in_allocated = IN_BUFF_SIZE;-	uudecode->out_buff = out_buff;-	uudecode->state = ST_FIND_HEAD;-	uudecode->mode_set = 0;-	uudecode->name = NULL;-	self->vtable = &uudecode_reader_vtable;+	f->data = uu;+	uu->in_buff = in_buff;+	uu->in_cnt = 0;+	uu->in_allocated = IN_BUFF_SIZE;+	uu->out_buff = out_buff;+	uu->state = ST_FIND_HEAD;+	uu->mode_set = 0;+	uu->name = NULL;+	f->vtable = &uudecode_reader_vtable;  	return (ARCHIVE_OK); }  static int-ensure_in_buff_size(struct archive_read_filter *self,-    struct uudecode *uudecode, size_t size)+ensure_in_buff_size(struct archive_read_filter *f,+    struct uu *uu, size_t size) { -	if (size > uudecode->in_allocated) {+	if (size > uu->in_allocated) { 		unsigned char *ptr; 		size_t newsize; @@ -411,7 +411,7 @@ 		 * Calculate a new buffer size for in_buff. 		 * Increase its value until it is enough for our needs. 		 */-		newsize = uudecode->in_allocated;+		newsize = uu->in_allocated; 		do { 			if (newsize < IN_BUFF_SIZE*32) 				newsize <<= 1;@@ -421,42 +421,40 @@ 		/* Allocate the new buffer. */ 		ptr = malloc(newsize); 		if (ptr == NULL) {-			archive_set_error(&self->archive->archive,+			archive_set_error(&f->archive->archive, 			    ENOMEM,     			    "Can't allocate data for uudecode"); 			return (ARCHIVE_FATAL); 		} 		/* Move the remaining data in in_buff into the new buffer. */-		if (uudecode->in_cnt)-			memmove(ptr, uudecode->in_buff, uudecode->in_cnt);+		if (uu->in_cnt)+			memmove(ptr, uu->in_buff, uu->in_cnt); 		/* Replace in_buff with the new buffer. */-		free(uudecode->in_buff);-		uudecode->in_buff = ptr;-		uudecode->in_allocated = newsize;+		free(uu->in_buff);+		uu->in_buff = ptr;+		uu->in_allocated = newsize; 	} 	return (ARCHIVE_OK); }  static int-uudecode_read_header(struct archive_read_filter *self, struct archive_entry *entry)+uudecode_read_header(struct archive_read_filter *f, struct archive_entry *entry) {--	struct uudecode *uudecode;-	uudecode = (struct uudecode *)self->data;+	struct uu *uu = f->data; -	if (uudecode->mode_set != 0)-		archive_entry_set_mode(entry, S_IFREG | uudecode->mode);+	if (uu->mode_set != 0)+		archive_entry_set_mode(entry, S_IFREG | uu->mode); -	if (uudecode->name != NULL)-		archive_entry_set_pathname(entry, uudecode->name);+	if (uu->name != NULL)+		archive_entry_set_pathname(entry, uu->name);  	return (ARCHIVE_OK); }  static ssize_t-uudecode_filter_read(struct archive_read_filter *self, const void **buff)+uudecode_filter_read(struct archive_read_filter *f, const void **buff) {-	struct uudecode *uudecode;+	struct uu *uu = f->data; 	const unsigned char *b, *d; 	unsigned char *out; 	ssize_t avail_in, ravail;@@ -464,10 +462,8 @@ 	ssize_t total; 	ssize_t len, llen, nl, namelen; -	uudecode = (struct uudecode *)self->data;- read_more:-	d = __archive_read_filter_ahead(self->upstream, 1, &avail_in);+	d = __archive_read_filter_ahead(f->upstream, 1, &avail_in); 	if (d == NULL && avail_in < 0) 		return (ARCHIVE_FATAL); 	/* Quiet a code analyzer; make sure avail_in must be zero@@ -476,17 +472,17 @@ 		avail_in = 0; 	used = 0; 	total = 0;-	out = uudecode->out_buff;+	out = uu->out_buff; 	if (avail_in > 2 * UUENCODE_BID_MAX_READ) 		avail_in = 2 * UUENCODE_BID_MAX_READ; 	ravail = avail_in;-	if (uudecode->state == ST_IGNORE) {+	if (uu->state == ST_IGNORE) { 		used = avail_in; 		goto finish; 	}-	if (uudecode->in_cnt) {-		if (uudecode->in_cnt > UUENCODE_BID_MAX_READ) {-			archive_set_error(&self->archive->archive,+	if (uu->in_cnt) {+		if (uu->in_cnt > UUENCODE_BID_MAX_READ) {+			archive_set_error(&f->archive->archive, 			    ARCHIVE_ERRNO_FILE_FORMAT, 			    "Invalid format data"); 			return (ARCHIVE_FATAL);@@ -495,14 +491,15 @@ 		 * If there is remaining data which is saved by 		 * a previous call, use it first. 		 */-		if (ensure_in_buff_size(self, uudecode,-		    avail_in + uudecode->in_cnt) != ARCHIVE_OK)+		if (ensure_in_buff_size(f, uu,+		    avail_in + uu->in_cnt) != ARCHIVE_OK) 			return (ARCHIVE_FATAL);-		memcpy(uudecode->in_buff + uudecode->in_cnt,-		    d, avail_in);-		d = uudecode->in_buff;-		avail_in += uudecode->in_cnt;-		uudecode->in_cnt = 0;+		if (avail_in > 0)+			memcpy(uu->in_buff + uu->in_cnt,+			    d, avail_in);+		d = uu->in_buff;+		avail_in += uu->in_cnt;+		uu->in_cnt = 0; 	} 	for (;used < avail_in; d += llen, used += llen) { 		ssize_t l, body;@@ -511,28 +508,28 @@ 		len = get_line(b, avail_in - used, &nl); 		if (len < 0) { 			/* Non-ascii character is found. */-			if (uudecode->state == ST_FIND_HEAD &&-			    (uudecode->total > 0 || total > 0)) {-				uudecode->state = ST_IGNORE;+			if (uu->state == ST_FIND_HEAD &&+			    (uu->total > 0 || total > 0)) {+				uu->state = ST_IGNORE; 				used = avail_in; 				goto finish; 			}-			archive_set_error(&self->archive->archive,+			archive_set_error(&f->archive->archive, 			    ARCHIVE_ERRNO_MISC, 			    "Insufficient compressed data"); 			return (ARCHIVE_FATAL); 		} 		if (len > UUENCODE_BID_MAX_READ) {-			archive_set_error(&self->archive->archive,+			archive_set_error(&f->archive->archive, 			    ARCHIVE_ERRNO_FILE_FORMAT, 			    "Invalid format data"); 			return (ARCHIVE_FATAL); 		} 		llen = len;-		if ((nl == 0) && (uudecode->state != ST_UUEND)) {+		if ((nl == 0) && (uu->state != ST_UUEND)) { 			if (total == 0 && ravail <= 0) { 				/* There is nothing more to read, fail */-				archive_set_error(&self->archive->archive,+				archive_set_error(&f->archive->archive, 				    ARCHIVE_ERRNO_FILE_FORMAT, 				    "Missing format data"); 				return (ARCHIVE_FATAL);@@ -541,28 +538,28 @@ 			 * Save remaining data which does not contain 			 * NL('\n','\r'). 			 */-			if (ensure_in_buff_size(self, uudecode, len)+			if (ensure_in_buff_size(f, uu, len) 			    != ARCHIVE_OK) 				return (ARCHIVE_FATAL);-			if (uudecode->in_buff != b)-				memmove(uudecode->in_buff, b, len);-			uudecode->in_cnt = len;+			if (uu->in_buff != b)+				memmove(uu->in_buff, b, len);+			uu->in_cnt = len; 			if (total == 0) { 				/* Do not return 0; it means end-of-file. 				 * We should try to read more bytes. */ 				__archive_read_filter_consume(-				    self->upstream, ravail);+				    f->upstream, ravail); 				goto read_more; 			} 			used += len; 			break; 		}-		switch (uudecode->state) {+		switch (uu->state) { 		default: 		case ST_FIND_HEAD: 			/* Do not read more than UUENCODE_BID_MAX_READ bytes */ 			if (total + len >= UUENCODE_BID_MAX_READ) {-				archive_set_error(&self->archive->archive,+				archive_set_error(&f->archive->archive, 				    ARCHIVE_ERRNO_FILE_FORMAT, 				    "Invalid format data"); 				return (ARCHIVE_FATAL);@@ -578,30 +575,30 @@ 			    b[l+1] >= '0' && b[l+1] <= '7' && 			    b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') { 				if (l == 6)-					uudecode->state = ST_READ_UU;+					uu->state = ST_READ_UU; 				else-					uudecode->state = ST_READ_BASE64;-				uudecode->mode = (mode_t)(+					uu->state = ST_READ_BASE64;+				uu->mode = (mode_t)( 				    ((int)(b[l] - '0') * 64) + 				    ((int)(b[l+1] - '0') * 8) + 				     (int)(b[l+2] - '0'));-				uudecode->mode_set = 1;+				uu->mode_set = 1; 				namelen = len - nl - 4 - l; 				if (namelen > 1) {-					if (uudecode->name != NULL)-						free(uudecode->name);-					uudecode->name = malloc(namelen + 1);-					if (uudecode->name == NULL) {+					if (uu->name != NULL)+						free(uu->name);+					uu->name = malloc(namelen + 1);+					if (uu->name == NULL) { 						archive_set_error(-						    &self->archive->archive,+						    &f->archive->archive, 						    ENOMEM, 						    "Can't allocate data for uudecode"); 						return (ARCHIVE_FATAL); 					}-					strncpy(uudecode->name,+					strncpy(uu->name, 					    (const char *)(b + l + 4), 					    namelen);-					uudecode->name[namelen] = '\0';+					uu->name[namelen] = '\0'; 				} 			} 			break;@@ -610,7 +607,7 @@ 				goto finish; 			body = len - nl; 			if (!uuchar[*b] || body <= 0) {-				archive_set_error(&self->archive->archive,+				archive_set_error(&f->archive->archive, 				    ARCHIVE_ERRNO_MISC, 				    "Insufficient compressed data"); 				return (ARCHIVE_FATAL);@@ -619,13 +616,13 @@ 			l = UUDECODE(*b++); 			body--; 			if (l > body) {-				archive_set_error(&self->archive->archive,+				archive_set_error(&f->archive->archive, 				    ARCHIVE_ERRNO_MISC, 				    "Insufficient compressed data"); 				return (ARCHIVE_FATAL); 			} 			if (l == 0) {-				uudecode->state = ST_UUEND;+				uu->state = ST_UUEND; 				break; 			} 			while (l > 0) {@@ -654,7 +651,7 @@ 				} 			} 			if (l) {-				archive_set_error(&self->archive->archive,+				archive_set_error(&f->archive->archive, 				    ARCHIVE_ERRNO_MISC, 				    "Insufficient compressed data"); 				return (ARCHIVE_FATAL);@@ -662,9 +659,9 @@ 			break; 		case ST_UUEND: 			if (len - nl == 3 && memcmp(b, "end ", 3) == 0)-				uudecode->state = ST_FIND_HEAD;+				uu->state = ST_FIND_HEAD; 			else {-				archive_set_error(&self->archive->archive,+				archive_set_error(&f->archive->archive, 				    ARCHIVE_ERRNO_MISC, 				    "Insufficient compressed data"); 				return (ARCHIVE_FATAL);@@ -676,7 +673,7 @@ 			l = len - nl; 			if (l >= 3 && b[0] == '=' && b[1] == '=' && 			    b[2] == '=') {-				uudecode->state = ST_FIND_HEAD;+				uu->state = ST_FIND_HEAD; 				break; 			} 			while (l > 0) {@@ -709,7 +706,7 @@ 				} 			} 			if (l && *b != '=') {-				archive_set_error(&self->archive->archive,+				archive_set_error(&f->archive->archive, 				    ARCHIVE_ERRNO_MISC, 				    "Insufficient compressed data"); 				return (ARCHIVE_FATAL);@@ -720,23 +717,22 @@ finish: 	if (ravail < avail_in) 		used -= avail_in - ravail;-	__archive_read_filter_consume(self->upstream, used);+	__archive_read_filter_consume(f->upstream, used); -	*buff = uudecode->out_buff;-	uudecode->total += total;+	*buff = uu->out_buff;+	uu->total += total; 	return (total); }  static int-uudecode_filter_close(struct archive_read_filter *self)+uudecode_filter_close(struct archive_read_filter *f) {-	struct uudecode *uudecode;+	struct uu *uu = f->data; -	uudecode = (struct uudecode *)self->data;-	free(uudecode->in_buff);-	free(uudecode->out_buff);-	free(uudecode->name);-	free(uudecode);+	free(uu->in_buff);+	free(uu->out_buff);+	free(uu->name);+	free(uu);  	return (ARCHIVE_OK); }
c/archive_read_support_filter_xz.c view
@@ -50,7 +50,7 @@  #if HAVE_LZMA_H && HAVE_LIBLZMA -struct private_data {+struct xz { 	lzma_stream	 stream; 	unsigned char	*out_block; 	size_t		 out_block_size;@@ -197,14 +197,14 @@  * Test whether we can handle this data.  */ static int-xz_bidder_bid(struct archive_read_filter_bidder *self,-    struct archive_read_filter *filter)+xz_bidder_bid(struct archive_read_filter_bidder *b,+    struct archive_read_filter *f) { 	const unsigned char *buffer; -	(void)self; /* UNUSED */+	(void)b; /* UNUSED */ -	buffer = __archive_read_filter_ahead(filter, 6, NULL);+	buffer = __archive_read_filter_ahead(f, 6, NULL); 	if (buffer == NULL) 		return (0); @@ -230,17 +230,17 @@  * they have other evidence (file name, command-line option) to go on.  */ static int-lzma_bidder_bid(struct archive_read_filter_bidder *self,-    struct archive_read_filter *filter)+lzma_bidder_bid(struct archive_read_filter_bidder *b,+    struct archive_read_filter *f) { 	const unsigned char *buffer; 	uint32_t dicsize; 	uint64_t uncompressed_size; 	int bits_checked; -	(void)self; /* UNUSED */+	(void)b; /* UNUSED */ -	buffer = __archive_read_filter_ahead(filter, 14, NULL);+	buffer = __archive_read_filter_ahead(f, 14, NULL); 	if (buffer == NULL) 		return (0); @@ -336,13 +336,13 @@ }  static int-lzip_has_member(struct archive_read_filter *filter)+lzip_has_member(struct archive_read_filter *f) { 	const unsigned char *buffer; 	int bits_checked; 	int log2dic; -	buffer = __archive_read_filter_ahead(filter, 6, NULL);+	buffer = __archive_read_filter_ahead(f, 6, NULL); 	if (buffer == NULL) 		return (0); @@ -369,12 +369,12 @@ }  static int-lzip_bidder_bid(struct archive_read_filter_bidder *self,-    struct archive_read_filter *filter)+lzip_bidder_bid(struct archive_read_filter_bidder *b,+    struct archive_read_filter *f) { -	(void)self; /* UNUSED */-	return (lzip_has_member(filter));+	(void)b; /* UNUSED */+	return (lzip_has_member(f)); }  #if HAVE_LZMA_H && HAVE_LIBLZMA@@ -383,34 +383,34 @@  * liblzma 4.999.7 and later support both lzma and xz streams.  */ static int-xz_bidder_init(struct archive_read_filter *self)+xz_bidder_init(struct archive_read_filter *f) {-	self->code = ARCHIVE_FILTER_XZ;-	self->name = "xz";-	return (xz_lzma_bidder_init(self));+	f->code = ARCHIVE_FILTER_XZ;+	f->name = "xz";+	return (xz_lzma_bidder_init(f)); }  static int-lzma_bidder_init(struct archive_read_filter *self)+lzma_bidder_init(struct archive_read_filter *f) {-	self->code = ARCHIVE_FILTER_LZMA;-	self->name = "lzma";-	return (xz_lzma_bidder_init(self));+	f->code = ARCHIVE_FILTER_LZMA;+	f->name = "lzma";+	return (xz_lzma_bidder_init(f)); }  static int-lzip_bidder_init(struct archive_read_filter *self)+lzip_bidder_init(struct archive_read_filter *f) {-	self->code = ARCHIVE_FILTER_LZIP;-	self->name = "lzip";-	return (xz_lzma_bidder_init(self));+	f->code = ARCHIVE_FILTER_LZIP;+	f->name = "lzip";+	return (xz_lzma_bidder_init(f)); }  /*  * Set an error code and choose an error message  */ static void-set_error(struct archive_read_filter *self, int ret)+set_error(struct archive_read_filter *f, int ret) {  	switch (ret) {@@ -418,36 +418,36 @@ 	case LZMA_OK: /* Decompressor made some progress. */ 		break; 	case LZMA_MEM_ERROR:-		archive_set_error(&self->archive->archive, ENOMEM,+		archive_set_error(&f->archive->archive, ENOMEM, 		    "Lzma library error: Cannot allocate memory"); 		break; 	case LZMA_MEMLIMIT_ERROR:-		archive_set_error(&self->archive->archive, ENOMEM,+		archive_set_error(&f->archive->archive, ENOMEM, 		    "Lzma library error: Out of memory"); 		break; 	case LZMA_FORMAT_ERROR:-		archive_set_error(&self->archive->archive,+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_MISC, 		    "Lzma library error: format not recognized"); 		break; 	case LZMA_OPTIONS_ERROR:-		archive_set_error(&self->archive->archive,+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_MISC, 		    "Lzma library error: Invalid options"); 		break; 	case LZMA_DATA_ERROR:-		archive_set_error(&self->archive->archive,+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_MISC, 		    "Lzma library error: Corrupted input data"); 		break; 	case LZMA_BUF_ERROR:-		archive_set_error(&self->archive->archive,+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_MISC, 		    "Lzma library error:  No progress is possible"); 		break; 	default: 		/* Return an error. */-		archive_set_error(&self->archive->archive,+		archive_set_error(&f->archive->archive, 		    ARCHIVE_ERRNO_MISC, 		    "Lzma decompression failed:  Unknown error"); 		break;@@ -464,84 +464,83 @@  * Setup the callbacks.  */ static int-xz_lzma_bidder_init(struct archive_read_filter *self)+xz_lzma_bidder_init(struct archive_read_filter *f) { 	static const size_t out_block_size = 64 * 1024; 	void *out_block;-	struct private_data *state;+	struct xz *xz; 	int ret; -	state = calloc(1, sizeof(*state));+	xz = calloc(1, sizeof(*xz)); 	out_block = malloc(out_block_size);-	if (state == NULL || out_block == NULL) {-		archive_set_error(&self->archive->archive, ENOMEM,+	if (xz == NULL || out_block == NULL) {+		archive_set_error(&f->archive->archive, ENOMEM, 		    "Can't allocate data for xz decompression"); 		free(out_block);-		free(state);+		free(xz); 		return (ARCHIVE_FATAL); 	} -	self->data = state;-	state->out_block_size = out_block_size;-	state->out_block = out_block;-	self->vtable = &xz_lzma_reader_vtable;+	f->data = xz;+	xz->out_block_size = out_block_size;+	xz->out_block = out_block;+	f->vtable = &xz_lzma_reader_vtable; -	state->stream.avail_in = 0;+	xz->stream.avail_in = 0; -	state->stream.next_out = state->out_block;-	state->stream.avail_out = state->out_block_size;+	xz->stream.next_out = xz->out_block;+	xz->stream.avail_out = xz->out_block_size; -	state->crc32 = 0;-	if (self->code == ARCHIVE_FILTER_LZIP) {+	xz->crc32 = 0;+	if (f->code == ARCHIVE_FILTER_LZIP) { 		/* 		 * We have to read a lzip header and use it to initialize 		 * compression library, thus we cannot initialize the 		 * library for lzip here. 		 */-		state->in_stream = 0;+		xz->in_stream = 0; 		return (ARCHIVE_OK); 	} else-		state->in_stream = 1;+		xz->in_stream = 1;  	/* Initialize compression library. */-	if (self->code == ARCHIVE_FILTER_XZ)-		ret = lzma_stream_decoder(&(state->stream),+	if (f->code == ARCHIVE_FILTER_XZ)+		ret = lzma_stream_decoder(&(xz->stream), 		    LZMA_MEMLIMIT,/* memlimit */ 		    LZMA_CONCATENATED); 	else-		ret = lzma_alone_decoder(&(state->stream),+		ret = lzma_alone_decoder(&(xz->stream), 		    LZMA_MEMLIMIT);/* memlimit */  	if (ret == LZMA_OK) 		return (ARCHIVE_OK);  	/* Library setup failed: Choose an error message and clean up. */-	set_error(self, ret);+	set_error(f, ret); -	free(state->out_block);-	free(state);-	self->data = NULL;-	self->vtable = NULL;+	free(xz->out_block);+	free(xz);+	f->data = NULL;+	f->vtable = NULL; 	return (ARCHIVE_FATAL); }  static int-lzip_init(struct archive_read_filter *self)+lzip_init(struct archive_read_filter *f) {-	struct private_data *state;+	struct xz *xz = f->data; 	const unsigned char *h; 	lzma_filter filters[2]; 	unsigned char props[5]; 	uint32_t dicsize; 	int log2dic, ret; -	state = (struct private_data *)self->data;-	h = __archive_read_filter_ahead(self->upstream, 6, NULL);+	h = __archive_read_filter_ahead(f->upstream, 6, NULL); 	if (h == NULL) 		return (ARCHIVE_FATAL);  	/* Get a version number. */-	state->lzip_ver = h[4];+	xz->lzip_ver = h[4];  	/* 	 * Setup lzma property.@@ -558,8 +557,8 @@ 	archive_le32enc(props+1, dicsize);  	/* Consume lzip header. */-	__archive_read_filter_consume(self->upstream, 6);-	state->member_in = 6;+	__archive_read_filter_consume(f->upstream, 6);+	xz->member_in = 6;  	filters[0].id = LZMA_FILTER_LZMA1; 	filters[0].options = NULL;@@ -568,74 +567,73 @@  	ret = lzma_properties_decode(&filters[0], NULL, props, sizeof(props)); 	if (ret != LZMA_OK) {-		set_error(self, ret);+		set_error(f, ret); 		return (ARCHIVE_FATAL); 	}-	ret = lzma_raw_decoder(&(state->stream), filters);+	ret = lzma_raw_decoder(&(xz->stream), filters); 	free(filters[0].options); 	if (ret != LZMA_OK) {-		set_error(self, ret);+		set_error(f, ret); 		return (ARCHIVE_FATAL); 	} 	return (ARCHIVE_OK); }  static int-lzip_tail(struct archive_read_filter *self)+lzip_tail(struct archive_read_filter *f) {-	struct private_data *state;-	const unsigned char *f;+	struct xz *xz = f->data;+	const unsigned char *p; 	ssize_t avail_in; 	int tail; -	state = (struct private_data *)self->data;-	if (state->lzip_ver == 0)+	if (xz->lzip_ver == 0) 		tail = 12; 	else 		tail = 20;-	f = __archive_read_filter_ahead(self->upstream, tail, &avail_in);-	if (f == NULL && avail_in < 0)+	p = __archive_read_filter_ahead(f->upstream, tail, &avail_in);+	if (p == NULL && avail_in < 0) 		return (ARCHIVE_FATAL);-	if (f == NULL || avail_in < tail) {-		archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+	if (p == NULL || avail_in < tail) {+		archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, 		    "Lzip: Remaining data is less bytes"); 		return (ARCHIVE_FAILED); 	}  	/* Check the crc32 value of the uncompressed data of the current 	 * member */-	if (state->crc32 != archive_le32dec(f)) {+	if (xz->crc32 != archive_le32dec(p)) { #ifndef DONT_FAIL_ON_CRC_ERROR-		archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+		archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, 		    "Lzip: CRC32 error"); 		return (ARCHIVE_FAILED); #endif 	}  	/* Check the uncompressed size of the current member */-	if ((uint64_t)state->member_out != archive_le64dec(f + 4)) {-		archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+	if ((uint64_t)xz->member_out != archive_le64dec(p + 4)) {+		archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, 		    "Lzip: Uncompressed size error"); 		return (ARCHIVE_FAILED); 	}  	/* Check the total size of the current member */-	if (state->lzip_ver == 1 &&-	    (uint64_t)state->member_in + tail != archive_le64dec(f + 12)) {-		archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,+	if (xz->lzip_ver == 1 &&+	    (uint64_t)xz->member_in + tail != archive_le64dec(p + 12)) {+		archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC, 		    "Lzip: Member size error"); 		return (ARCHIVE_FAILED); 	}-	__archive_read_filter_consume(self->upstream, tail);+	__archive_read_filter_consume(f->upstream, tail);  	/* If current lzip data consists of multi member, try decompressing 	 * a next member. */-	if (lzip_has_member(self->upstream) != 0) {-		state->in_stream = 0;-		state->crc32 = 0;-		state->member_out = 0;-		state->member_in = 0;-		state->eof = 0;+	if (lzip_has_member(f->upstream) != 0) {+		xz->in_stream = 0;+		xz->crc32 = 0;+		xz->member_out = 0;+		xz->member_in = 0;+		xz->eof = 0; 	} 	return (ARCHIVE_OK); }@@ -644,82 +642,80 @@  * Return the next block of decompressed data.  */ static ssize_t-xz_filter_read(struct archive_read_filter *self, const void **p)+xz_filter_read(struct archive_read_filter *f, const void **p) {-	struct private_data *state;+	struct xz *xz = f->data; 	size_t decompressed; 	ssize_t avail_in; 	int64_t member_in; 	int ret; -	state = (struct private_data *)self->data;- 	redo: 	/* Empty our output buffer. */-	state->stream.next_out = state->out_block;-	state->stream.avail_out = state->out_block_size;-	member_in = state->member_in;+	xz->stream.next_out = xz->out_block;+	xz->stream.avail_out = xz->out_block_size;+	member_in = xz->member_in;  	/* Try to fill the output buffer. */-	while (state->stream.avail_out > 0 && !state->eof) {-		if (!state->in_stream) {+	while (xz->stream.avail_out > 0 && !xz->eof) {+		if (!xz->in_stream) { 			/* 			 * Initialize liblzma for lzip 			 */-			ret = lzip_init(self);+			ret = lzip_init(f); 			if (ret != ARCHIVE_OK) 				return (ret);-			state->in_stream = 1;+			xz->in_stream = 1; 		}-		state->stream.next_in =-		    __archive_read_filter_ahead(self->upstream, 1, &avail_in);-		if (state->stream.next_in == NULL && avail_in < 0) {-			archive_set_error(&self->archive->archive,+		xz->stream.next_in =+		    __archive_read_filter_ahead(f->upstream, 1, &avail_in);+		if (xz->stream.next_in == NULL && avail_in < 0) {+			archive_set_error(&f->archive->archive, 			    ARCHIVE_ERRNO_MISC, 			    "truncated input"); 			return (ARCHIVE_FATAL); 		}-		state->stream.avail_in = avail_in;+		xz->stream.avail_in = avail_in;  		/* Decompress as much as we can in one pass. */-		ret = lzma_code(&(state->stream),-		    (state->stream.avail_in == 0)? LZMA_FINISH: LZMA_RUN);+		ret = lzma_code(&(xz->stream),+		    (xz->stream.avail_in == 0)? LZMA_FINISH: LZMA_RUN); 		switch (ret) { 		case LZMA_STREAM_END: /* Found end of stream. */-			state->eof = 1;+			xz->eof = 1; 			/* FALL THROUGH */ 		case LZMA_OK: /* Decompressor made some progress. */-			__archive_read_filter_consume(self->upstream,-			    avail_in - state->stream.avail_in);-			state->member_in +=-			    avail_in - state->stream.avail_in;+			__archive_read_filter_consume(f->upstream,+			    avail_in - xz->stream.avail_in);+			xz->member_in +=+			    avail_in - xz->stream.avail_in; 			break; 		default:-			set_error(self, ret);+			set_error(f, ret); 			return (ARCHIVE_FATAL); 		} 	} -	decompressed = state->stream.next_out - state->out_block;-	state->member_out += decompressed;+	decompressed = xz->stream.next_out - xz->out_block;+	xz->member_out += decompressed; 	if (decompressed == 0) {-		if (member_in != state->member_in &&-		    self->code == ARCHIVE_FILTER_LZIP &&-		    state->eof) {-			ret = lzip_tail(self);+		if (member_in != xz->member_in &&+		    f->code == ARCHIVE_FILTER_LZIP &&+		    xz->eof) {+			ret = lzip_tail(f); 			if (ret != ARCHIVE_OK) 				return (ret);-			if (!state->eof)+			if (!xz->eof) 				goto redo; 		} 		*p = NULL; 	} else {-		*p = state->out_block;-		if (self->code == ARCHIVE_FILTER_LZIP) {-			state->crc32 = lzma_crc32(state->out_block,-			    decompressed, state->crc32);-			if (state->eof) {-				ret = lzip_tail(self);+		*p = xz->out_block;+		if (f->code == ARCHIVE_FILTER_LZIP) {+			xz->crc32 = lzma_crc32(xz->out_block,+			    decompressed, xz->crc32);+			if (xz->eof) {+				ret = lzip_tail(f); 				if (ret != ARCHIVE_OK) 					return (ret); 			}@@ -732,14 +728,13 @@  * Clean up the decompressor.  */ static int-xz_filter_close(struct archive_read_filter *self)+xz_filter_close(struct archive_read_filter *f) {-	struct private_data *state;+	struct xz *xz = f->data; -	state = (struct private_data *)self->data;-	lzma_end(&(state->stream));-	free(state->out_block);-	free(state);+	lzma_end(&(xz->stream));+	free(xz->out_block);+	free(xz); 	return (ARCHIVE_OK); } @@ -753,44 +748,44 @@  *  */ static int-lzma_bidder_init(struct archive_read_filter *self)+lzma_bidder_init(struct archive_read_filter *f) { 	int r; -	r = __archive_read_program(self, "lzma -d -qq");+	r = __archive_read_program(f, "lzma -d -qq"); 	/* Note: We set the format here even if __archive_read_program() 	 * above fails.  We do, after all, know what the format is 	 * even if we weren't able to read it. */-	self->code = ARCHIVE_FILTER_LZMA;-	self->name = "lzma";+	f->code = ARCHIVE_FILTER_LZMA;+	f->name = "lzma"; 	return (r); }  static int-xz_bidder_init(struct archive_read_filter *self)+xz_bidder_init(struct archive_read_filter *f) { 	int r; -	r = __archive_read_program(self, "xz -d -qq");+	r = __archive_read_program(f, "xz -d -qq"); 	/* Note: We set the format here even if __archive_read_program() 	 * above fails.  We do, after all, know what the format is 	 * even if we weren't able to read it. */-	self->code = ARCHIVE_FILTER_XZ;-	self->name = "xz";+	f->code = ARCHIVE_FILTER_XZ;+	f->name = "xz"; 	return (r); }  static int-lzip_bidder_init(struct archive_read_filter *self)+lzip_bidder_init(struct archive_read_filter *f) { 	int r; -	r = __archive_read_program(self, "lzip -d -q");+	r = __archive_read_program(f, "lzip -d -q"); 	/* Note: We set the format here even if __archive_read_program() 	 * above fails.  We do, after all, know what the format is 	 * even if we weren't able to read it. */-	self->code = ARCHIVE_FILTER_LZIP;-	self->name = "lzip";+	f->code = ARCHIVE_FILTER_LZIP;+	f->name = "lzip"; 	return (r); } 
c/archive_read_support_filter_zstd.c view
@@ -54,7 +54,7 @@  #if HAVE_ZSTD_H && HAVE_LIBZSTD -struct private_data {+struct zstd { 	ZSTD_DStream	*dstream; 	unsigned char	*out_block; 	size_t		 out_block_size;@@ -104,8 +104,8 @@  * Test whether we can handle this data.  */ static int-zstd_bidder_bid(struct archive_read_filter_bidder *self,-    struct archive_read_filter *filter)+zstd_bidder_bid(struct archive_read_filter_bidder *b,+    struct archive_read_filter *f) { 	const unsigned char *buffer; 	ssize_t avail;@@ -132,9 +132,9 @@ 	const uint32_t zstd_magic_skippable_start = 0x184D2A50; 	const uint32_t zstd_magic_skippable_mask  = 0xFFFFFFF0; -	(void) self; /* UNUSED */+	(void) b; /* UNUSED */ -	buffer = __archive_read_filter_ahead(filter, min_zstd_frame_size,+	buffer = __archive_read_filter_ahead(f, min_zstd_frame_size, 	    &avail); 	if (buffer == NULL) 		return (0);@@ -151,7 +151,7 @@  		/* Ensure that we can read another 4 bytes. */ 		if (offset_in_buffer + 4 > (size_t)avail) {-			buffer = __archive_read_filter_ahead(filter,+			buffer = __archive_read_filter_ahead(f, 			    offset_in_buffer + 4, &avail); 			if (buffer == NULL) 				return (0);@@ -178,7 +178,7 @@ 			if (min > max_lookahead) 				return (0); -			buffer = __archive_read_filter_ahead(filter,+			buffer = __archive_read_filter_ahead(f, 			    min, &avail); 			if (buffer == NULL) 				return (0);@@ -206,16 +206,16 @@  * in case that's available.  */ static int-zstd_bidder_init(struct archive_read_filter *self)+zstd_bidder_init(struct archive_read_filter *f) { 	int r; -	r = __archive_read_program(self, "zstd -d -qq");+	r = __archive_read_program(f, "zstd -d -qq"); 	/* Note: We set the format here even if __archive_read_program() 	 * above fails.  We do, after all, know what the format is 	 * even if we weren't able to read it. */-	self->code = ARCHIVE_FILTER_ZSTD;-	self->name = "zstd";+	f->code = ARCHIVE_FILTER_ZSTD;+	f->name = "zstd"; 	return (r); } @@ -231,80 +231,78 @@  * Initialize the filter object  */ static int-zstd_bidder_init(struct archive_read_filter *self)+zstd_bidder_init(struct archive_read_filter *f) {-	struct private_data *state;+	struct zstd *zstd; 	size_t out_block_size = ZSTD_DStreamOutSize(); 	void *out_block; 	ZSTD_DStream *dstream; -	self->code = ARCHIVE_FILTER_ZSTD;-	self->name = "zstd";+	f->code = ARCHIVE_FILTER_ZSTD;+	f->name = "zstd"; -	state = calloc(1, sizeof(*state));+	zstd = calloc(1, sizeof(*zstd)); 	out_block = malloc(out_block_size); 	dstream = ZSTD_createDStream(); -	if (state == NULL || out_block == NULL || dstream == NULL) {+	if (zstd == NULL || out_block == NULL || dstream == NULL) { 		free(out_block);-		free(state);+		free(zstd); 		ZSTD_freeDStream(dstream); /* supports free on NULL */-		archive_set_error(&self->archive->archive, ENOMEM,+		archive_set_error(&f->archive->archive, ENOMEM, 		    "Can't allocate data for zstd decompression"); 		return (ARCHIVE_FATAL); 	} -	self->data = state;+	f->data = zstd; -	state->out_block_size = out_block_size;-	state->out_block = out_block;-	state->dstream = dstream;-	self->vtable = &zstd_reader_vtable;+	zstd->out_block_size = out_block_size;+	zstd->out_block = out_block;+	zstd->dstream = dstream;+	f->vtable = &zstd_reader_vtable; -	state->eof = 0;-	state->in_frame = 0;+	zstd->eof = 0;+	zstd->in_frame = 0;  	return (ARCHIVE_OK); }  static ssize_t-zstd_filter_read(struct archive_read_filter *self, const void **p)+zstd_filter_read(struct archive_read_filter *f, const void **p) {-	struct private_data *state;+	struct zstd *zstd = f->data; 	size_t decompressed; 	ssize_t avail_in; 	ZSTD_outBuffer out; 	ZSTD_inBuffer in; 	size_t ret; -	state = (struct private_data *)self->data;--	out = (ZSTD_outBuffer) { state->out_block, state->out_block_size, 0 };+	out = (ZSTD_outBuffer) { zstd->out_block, zstd->out_block_size, 0 };  	/* Try to fill the output buffer. */-	while (out.pos < out.size && !state->eof) {-		if (!state->in_frame) {-			ret = ZSTD_initDStream(state->dstream);+	while (out.pos < out.size && !zstd->eof) {+		if (!zstd->in_frame) {+			ret = ZSTD_initDStream(zstd->dstream); 			if (ZSTD_isError(ret)) {-				archive_set_error(&self->archive->archive,+				archive_set_error(&f->archive->archive, 				    ARCHIVE_ERRNO_MISC, 				    "Error initializing zstd decompressor: %s", 				    ZSTD_getErrorName(ret)); 				return (ARCHIVE_FATAL); 			} 		}-		in.src = __archive_read_filter_ahead(self->upstream, 1,+		in.src = __archive_read_filter_ahead(f->upstream, 1, 		    &avail_in); 		if (avail_in < 0) { 			return avail_in; 		} 		if (in.src == NULL && avail_in == 0) {-			if (!state->in_frame) {+			if (!zstd->in_frame) { 				/* end of stream */-				state->eof = 1;+				zstd->eof = 1; 				break; 			} else {-				archive_set_error(&self->archive->archive,+				archive_set_error(&f->archive->archive, 				    ARCHIVE_ERRNO_MISC, 				    "Truncated zstd input"); 				return (ARCHIVE_FATAL);@@ -314,10 +312,10 @@ 		in.pos = 0;  		{-			ret = ZSTD_decompressStream(state->dstream, &out, &in);+			ret = ZSTD_decompressStream(zstd->dstream, &out, &in);  			if (ZSTD_isError(ret)) {-				archive_set_error(&self->archive->archive,+				archive_set_error(&f->archive->archive, 				    ARCHIVE_ERRNO_MISC, 				    "Zstd decompression failed: %s", 				    ZSTD_getErrorName(ret));@@ -325,10 +323,10 @@ 			}  			/* Decompressor made some progress */-			__archive_read_filter_consume(self->upstream, in.pos);+			__archive_read_filter_consume(f->upstream, in.pos);  			/* ret guaranteed to be > 0 if frame isn't done yet */-			state->in_frame = (ret != 0);+			zstd->in_frame = (ret != 0); 		} 	} @@ -336,7 +334,7 @@ 	if (decompressed == 0) 		*p = NULL; 	else-		*p = state->out_block;+		*p = zstd->out_block; 	return (decompressed); } @@ -344,15 +342,13 @@  * Clean up the decompressor.  */ static int-zstd_filter_close(struct archive_read_filter *self)+zstd_filter_close(struct archive_read_filter *f) {-	struct private_data *state;--	state = (struct private_data *)self->data;+	struct zstd *zstd = f->data; -	ZSTD_freeDStream(state->dstream);-	free(state->out_block);-	free(state);+	ZSTD_freeDStream(zstd->dstream);+	free(zstd->out_block);+	free(zstd);  	return (ARCHIVE_OK); }
c/archive_read_support_format_7zip.c view
@@ -53,6 +53,7 @@ #include "archive.h" #include "archive_entry.h" #include "archive_entry_locale.h"+#include "archive_integer.h" #include "archive_ppmd7_private.h" #include "archive_private.h" #include "archive_read_private.h"@@ -72,12 +73,12 @@ /*  * PE format  */-#define PE_DOS_HDR_LEN				0x40+#define PE_DOS_HDR_LEN			0x40 #define PE_DOS_HDR_ELFANEW_OFFSET	0x3c-#define PE_COFF_HDR_LEN				0x18+#define PE_COFF_HDR_LEN			0x18 #define PE_COFF_HDR_SEC_CNT_OFFSET	0x6 #define PE_COFF_HDR_OPT_SZ_OFFSET	0x14-#define PE_SEC_HDR_LEN 				0x28+#define PE_SEC_HDR_LEN 			0x28 #define PE_SEC_HDR_RAW_ADDR_OFFSET	0x14 #define PE_SEC_HDR_RAW_SZ_OFFSET	0x10 @@ -98,8 +99,8 @@ #define _7Z_BZ2		0x040202 #define _7Z_PPMD	0x030401 #define _7Z_DELTA	0x03-#define _7Z_CRYPTO_MAIN_ZIP			0x06F10101 /* Main Zip crypto algo */-#define _7Z_CRYPTO_RAR_29			0x06F10303 /* Rar29 AES-128 + (modified SHA-1) */+#define _7Z_CRYPTO_MAIN_ZIP		0x06F10101 /* Main Zip crypto algo */+#define _7Z_CRYPTO_RAR_29		0x06F10303 /* Rar29 AES-128 + (modified SHA-1) */ #define _7Z_CRYPTO_AES_256_SHA_256	0x06F10701 /* AES-256 + SHA-256 */  @@ -173,50 +174,48 @@ };  struct _7z_folder {-	uint64_t		 numCoders;+	size_t			 numCoders; 	struct _7z_coder {-		uint64_t	 codec;-		uint64_t	 numInStreams;-		uint64_t	 numOutStreams;-		uint64_t	 propertiesSize;+		int64_t		 codec;+		size_t		 numInStreams;+		size_t		 numOutStreams;+		size_t		 propertiesSize; 		unsigned char	*properties; 	} *coders;-	uint64_t		 numBindPairs;+	size_t			 numBindPairs; 	struct {-		uint64_t	 inIndex;-		uint64_t	 outIndex;+		size_t		 inIndex;+		size_t		 outIndex; 	} *bindPairs;-	uint64_t		 numPackedStreams;-	uint64_t		*packedStreams;-	uint64_t		 numInStreams;-	uint64_t		 numOutStreams;-	uint64_t		*unPackSize;+	size_t			 numPackedStreams;+	size_t			 numInStreams;+	size_t			 numOutStreams;+	int64_t			*unPackSize; 	unsigned char		 digest_defined; 	uint32_t		 digest;-	uint64_t		 numUnpackStreams;-	uint32_t		 packIndex;+	size_t			 numUnpackStreams;+	size_t			 packIndex; 	/* Unoperated bytes. */-	uint64_t		 skipped_bytes;+	int64_t			 skipped_bytes; };  struct _7z_coders_info {-	uint64_t		 numFolders;+	size_t			 numFolders; 	struct _7z_folder	*folders;-	uint64_t		 dataStreamIndex; };  struct _7z_pack_info {-	uint64_t		 pos;-	uint64_t		 numPackStreams;-	uint64_t		*sizes;+	int64_t			 pos;+	size_t			 numPackStreams;+	int64_t			*sizes; 	struct _7z_digests	 digest; 	/* Calculated from pos and numPackStreams. */-	uint64_t		*positions;+	int64_t			*positions; };  struct _7z_substream_info { 	size_t			 unpack_streams;-	uint64_t		*unpackSizes;+	int64_t			*unpackSizes; 	unsigned char		*digestsDefined; 	uint32_t		*digests; };@@ -228,8 +227,6 @@ };  struct _7z_header_info {-	uint64_t		 dataIndex;- 	unsigned char		*emptyStreamBools; 	unsigned char		*emptyFileBools; 	unsigned char		*antiBools;@@ -242,8 +239,8 @@ #if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG) 	const wchar_t		*wname; #endif-	uint32_t		 folderIndex;-	uint32_t		 ssIndex;+	size_t			 folderIndex;+	size_t			 ssIndex; 	unsigned		 flg; #define MTIME_IS_SET	(1<<0) #define ATIME_IS_SET	(1<<1)@@ -267,24 +264,24 @@  	int			 header_is_being_read; 	int			 header_is_encoded;-	uint64_t		 header_bytes_remaining;+	int64_t			 header_bytes_remaining; 	unsigned long		 header_crc32; 	/* Header offset to check that reading points of the file contents 	 * will not exceed the header. */-	uint64_t		 header_offset;+	int64_t			 header_offset; 	/* Base offset of the archive file for a seek in case reading SFX. */-	uint64_t		 seek_base;+	int64_t			 seek_base;  	/* List of entries */ 	size_t			 entries_remaining;-	uint64_t		 numFiles;+	size_t			 numFiles; 	struct _7zip_entry	*entries; 	struct _7zip_entry	*entry; 	unsigned char		*entry_names;  	/* entry_bytes_remaining is the number of bytes we expect. */ 	int64_t			 entry_offset;-	uint64_t		 entry_bytes_remaining;+	int64_t			 entry_bytes_remaining;  	/* Running CRC32 of the decompressed data */ 	unsigned long		 entry_crc32;@@ -305,16 +302,16 @@ 	/* 	 * Decompressing control data. 	 */-	unsigned		 folder_index;-	uint64_t		 folder_outbytes_remaining;-	unsigned		 pack_stream_index;-	unsigned		 pack_stream_remaining;-	uint64_t		 pack_stream_inbytes_remaining;-	size_t			 pack_stream_bytes_unconsumed;+	size_t			 folder_index;+	int64_t			 folder_outbytes_remaining;+	size_t			 pack_stream_index;+	size_t			 pack_stream_remaining;+	int64_t			 pack_stream_inbytes_remaining;+	int64_t			 pack_stream_bytes_unconsumed;  	/* The codec information of a folder. */-	unsigned long		 codec;-	unsigned long		 codec2;+	int64_t			 codec;+	int64_t			 codec2;  	/* 	 * Decompressor controllers.@@ -364,7 +361,7 @@ 	uint32_t		 bcj_ip;  	/* Decoding BCJ2 data. */-	size_t			 main_stream_bytes_remaining;+	int64_t			 main_stream_bytes_remaining; 	unsigned char		*sub_stream_buff[3]; 	size_t			 sub_stream_size[3]; 	size_t			 sub_stream_bytes_remaining[3];@@ -381,13 +378,11 @@ 	uint8_t			 bcj2_prevByte; 	uint32_t		 bcj2_range; 	uint32_t		 bcj2_code;-	uint64_t		 bcj2_outPos;+	size_t			 bcj2_outPos;  	/* Filename character-set conversion data. */ 	struct archive_string_conv *sconv; -	char			 format_name[64];- 	/* Custom value that is non-zero if this archive contains encrypted entries. */ 	int			 has_encrypted_entries; };@@ -395,31 +390,14 @@ /* Maximum entry size. This limitation prevents reading intentional  * corrupted 7-zip files on assuming there are not so many entries in  * the files. */-#define UMAX_ENTRY	ARCHIVE_LITERAL_ULL(100000000)--/*- * Files without unpack streams must be described by the EmptyStream bitmap,- * which consumes one bit for every file entry in FilesInfo.- */-static int-files_info_numfiles_is_sane(const struct _7zip *zip)-{-	uint64_t empty_stream_map_bytes;--	if (zip->numFiles > UMAX_ENTRY)-		return (0);-	if (zip->numFiles > SIZE_MAX / sizeof(*zip->entries))-		return (0);--	if (zip->numFiles <= zip->si.ss.unpack_streams)-		return (1);+#define UMAX_ENTRY	ARCHIVE_LITERAL_LL(100000000) -	empty_stream_map_bytes = (zip->numFiles + 7) / 8;-	return (empty_stream_map_bytes <= zip->header_bytes_remaining);-}+/* Don't try to read more than 16 MB at a time */+#define MAX_READ	16 * 1024 * 1024 +static size_t	align_size(size_t); static int	archive_read_format_7zip_has_encrypted_entries(struct archive_read *);-static int	archive_read_support_format_7zip_capabilities(struct archive_read *a);+static int	archive_read_support_format_7zip_capabilities(struct archive_read *); static int	archive_read_format_7zip_bid(struct archive_read *, int); static int	archive_read_format_7zip_cleanup(struct archive_read *); static int	archive_read_format_7zip_read_data(struct archive_read *,@@ -427,14 +405,15 @@ static int	archive_read_format_7zip_read_data_skip(struct archive_read *); static int	archive_read_format_7zip_read_header(struct archive_read *, 		    struct archive_entry *);-static int	check_7zip_header_in_sfx(const unsigned char *);-static int	decode_codec_id(const unsigned char *, size_t, uint64_t *);+static size_t	check_7zip_header_in_sfx(const unsigned char *);+static int	decode_codec_id(const unsigned char *, size_t, int64_t *); static int	decode_encoded_header_info(struct archive_read *, 		    struct _7z_stream_info *); static int	decompress(struct archive_read *, struct _7zip *, 		    void *, size_t *, const void *, size_t *); static ssize_t	extract_pack_stream(struct archive_read *, size_t);-static uint64_t folder_uncompressed_size(struct _7z_folder *);+static int	files_info_numfiles_is_sane(const struct _7zip *);+static int64_t	folder_uncompressed_size(struct _7z_folder *); static void	free_CodersInfo(struct _7z_coders_info *); static void	free_Digest(struct _7z_digests *); static void	free_Folder(struct _7z_folder *);@@ -445,10 +424,11 @@ static int	free_decompression(struct archive_read *, struct _7zip *); static ssize_t	get_uncompressed_data(struct archive_read *, const void **, 		    size_t, size_t);-static const unsigned char * header_bytes(struct archive_read *, size_t);+static const unsigned char *header_bytes(struct archive_read *, size_t); static int	init_decompression(struct archive_read *, struct _7zip *, 		    const struct _7z_coder *, const struct _7z_coder *);-static int	parse_7zip_uint64(struct archive_read *, uint64_t *);+static int	parse_7zip_size(struct archive_read *, size_t *);+static int	parse_7zip_int64(struct archive_read *, int64_t *); static int	read_Bools(struct archive_read *, unsigned char *, size_t); static int	read_CodersInfo(struct archive_read *, 		    struct _7z_coders_info *);@@ -462,13 +442,12 @@ 		    struct _7z_stream_info *); static int	read_SubStreamsInfo(struct archive_read *, 		    struct _7z_substream_info *, struct _7z_folder *, size_t);-static int	read_Times(struct archive_read *, struct _7z_header_info *,-		    int);-static void	read_consume(struct archive_read *);+static int	read_Times(struct archive_read *, int);+static int	read_consume(struct archive_read *); static ssize_t	read_stream(struct archive_read *, const void **, size_t, 		    size_t); static int	seek_pack(struct archive_read *);-static int64_t	skip_stream(struct archive_read *, size_t);+static int	skip_stream(struct archive_read *, int64_t); static int	get_data_offset(struct archive_read *, int64_t *, int); static int	get_pe_sfx_offset(struct archive_read *, int64_t *); static int	get_elf_sfx_offset(struct archive_read *, int64_t *, int);@@ -481,7 +460,7 @@ static void	arm_Init(struct _7zip *); static size_t	arm_Convert(struct _7zip *, uint8_t *, size_t); static size_t	arm64_Convert(struct _7zip *, uint8_t *, size_t);-static ssize_t		Bcj2_Decode(struct _7zip *, uint8_t *, size_t);+static ssize_t	Bcj2_Decode(struct _7zip *, uint8_t *, size_t); static size_t	sparc_Convert(struct _7zip *, uint8_t *, size_t); static size_t	powerpc_Convert(struct _7zip *, uint8_t *, size_t); static int64_t	seek_compat(struct archive_read *, int64_t, int, int);@@ -530,19 +509,18 @@ }  static int-archive_read_support_format_7zip_capabilities(struct archive_read * a)+archive_read_support_format_7zip_capabilities(struct archive_read *a) { 	(void)a; /* UNUSED */ 	return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA | 			ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA); } - static int-archive_read_format_7zip_has_encrypted_entries(struct archive_read *_a)+archive_read_format_7zip_has_encrypted_entries(struct archive_read *a) {-	if (_a && _a->format) {-		struct _7zip * zip = (struct _7zip *)_a->format->data;+	if (a && a->format) {+		struct _7zip *zip = a->format->data; 		if (zip) { 			return zip->has_encrypted_entries; 		}@@ -601,8 +579,8 @@ 			continue; 		} 		p = buff + offset;-		while (p + 32 < buff + bytes_avail) {-			int step = check_7zip_header_in_sfx(p);+		while (buff + bytes_avail - p >= 32) {+			size_t step = check_7zip_header_in_sfx(p); 			if (step == 0) { 				*data_offset = p - buff; 				return (ARCHIVE_OK);@@ -633,7 +611,7 @@ 	return (48); } -static int+static size_t check_7zip_header_in_sfx(const unsigned char *p) { 	switch (p[5]) {@@ -798,7 +776,7 @@ 			e_shentsize = (*dec16)(h + 0x3A); 			e_shnum = (*dec16)(h + 0x3C); 			e_shstrndx = (*dec16)(h + 0x3E);-			if (e_shnum < e_shstrndx || e_shentsize < 0x28)+			if (e_shnum <= e_shstrndx || e_shentsize < 0x28) 				break;  		} else {@@ -806,7 +784,7 @@ 			e_shentsize = (*dec16)(h + 0x2E); 			e_shnum = (*dec16)(h + 0x30); 			e_shstrndx = (*dec16)(h + 0x32);-			if (e_shnum < e_shstrndx || e_shentsize < 0x18)+			if (e_shnum <= e_shstrndx || e_shentsize < 0x18) 				break; 		} @@ -860,7 +838,7 @@ 			return (ARCHIVE_FATAL); 		} 		size_t data_sym_offset = strtab_size;-		for (size_t offset = 0; offset < strtab_size - 6; offset++) {+		for (size_t offset = 0; offset + 6 <= strtab_size; offset++) { 			if (memcmp(h + offset, ".data\00", 6) == 0) { 				data_sym_offset = offset; 				break;@@ -916,11 +894,10 @@ archive_read_format_7zip_read_header(struct archive_read *a, 	struct archive_entry *entry) {-	struct _7zip *zip = (struct _7zip *)a->format->data;+	struct _7zip *zip = a->format->data; 	struct _7zip_entry *zip_entry; 	int r, ret = ARCHIVE_OK; 	struct _7z_folder *folder = 0;-	uint64_t fidx = 0;  	/* 	 * It should be sufficient to call archive_read_next_header() for@@ -934,8 +911,7 @@ 	}  	a->archive.archive_format = ARCHIVE_FORMAT_7ZIP;-	if (a->archive.archive_format_name == NULL)-		a->archive.archive_format_name = "7-Zip";+	a->archive.archive_format_name = "7-Zip";  	if (zip->entries == NULL) { 		struct _7z_header_info header;@@ -945,20 +921,20 @@ 		free_Header(&header); 		if (r != ARCHIVE_OK) 			return (r);-		zip->entries_remaining = (size_t)zip->numFiles;+		zip->entries_remaining = zip->numFiles; 		zip->entry = zip->entries; 	} else { 		++zip->entry; 	} 	zip_entry = zip->entry; -	if (zip->entries_remaining <= 0 || zip_entry == NULL)+	if (zip->entries_remaining == 0 || zip_entry == NULL) 		return ARCHIVE_EOF; 	--zip->entries_remaining;  	zip->entry_offset = 0; 	zip->end_of_entry = 0;-	zip->entry_crc32 = crc32(0, NULL, 0);+	zip->entry_crc32 = 0;  	/* Setup a string conversion for a filename. */ 	if (zip->sconv == NULL) {@@ -972,9 +948,11 @@ 	   that is associated to the current 7zip entry. If the folder 	   has a coder with a _7Z_CRYPTO codec then the folder is encrypted. 	   Hence the entry must also be encrypted. */-	if (zip_entry && zip_entry->folderIndex < zip->si.ci.numFolders) {+	if (zip_entry->folderIndex < zip->si.ci.numFolders) {+		size_t fidx = 0;+ 		folder = &(zip->si.ci.folders[zip_entry->folderIndex]);-		for (fidx=0; folder && fidx<folder->numCoders; fidx++) {+		for (fidx = 0; fidx < folder->numCoders; fidx++) { 			switch(folder->coders[fidx].codec) { 				case _7Z_CRYPTO_MAIN_ZIP: 				case _7Z_CRYPTO_RAR_29:@@ -987,13 +965,6 @@ 		} 	} -	/* Now that we've checked for encryption, if there were still no-	 * encrypted entries found we can say for sure that there are none.-	 */-	if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {-		zip->has_encrypted_entries = 0;-	}- 	if (archive_entry_copy_pathname_l(entry, 	    (const char *)zip_entry->utf16name, 	    zip_entry->name_len, zip->sconv) != 0) {@@ -1021,7 +992,7 @@ 	if (zip_entry->flg & ATIME_IS_SET) 		archive_entry_set_atime(entry, zip_entry->atime, 		    zip_entry->atime_ns);-	if (zip_entry->ssIndex != (uint32_t)-1) {+	if (zip_entry->ssIndex != (size_t)-1) { 		zip->entry_bytes_remaining = 		    zip->si.ss.unpackSizes[zip_entry->ssIndex]; 		archive_entry_set_size(entry, zip->entry_bytes_remaining);@@ -1035,8 +1006,8 @@  	if (zip_entry->attr & supported_attrs) { 		char buf[sizeof(",rdonly,hidden,system")];-		char *fflags[3] = { "", "", "" };-		char **flag = fflags;+		const char *fflags[3] = { "", "", "" };+		const char **flag = fflags;  		if (zip_entry->attr & FILE_ATTRIBUTE_READONLY) 			*flag++ = ",rdonly";@@ -1117,10 +1088,6 @@ 		archive_entry_set_size(entry, 0); 	} -	/* Set up a more descriptive format name. */-	snprintf(zip->format_name, sizeof(zip->format_name), "7-Zip");-	a->archive.archive_format_name = zip->format_name;- 	return (ret); } @@ -1128,12 +1095,10 @@ archive_read_format_7zip_read_data(struct archive_read *a,     const void **buff, size_t *size, int64_t *offset) {-	struct _7zip *zip;+	struct _7zip *zip = a->format->data; 	ssize_t bytes; 	int ret = ARCHIVE_OK; -	zip = (struct _7zip *)(a->format->data);- 	if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { 		zip->has_encrypted_entries = 0; 	}@@ -1151,8 +1116,8 @@ 	if (zip->end_of_entry) 		return (ARCHIVE_EOF); -	size_t bytes_to_read = 16 * 1024 * 1024;  // Don't try to read more than 16 MB at a time-	if ((uint64_t)bytes_to_read > zip->entry_bytes_remaining) {+	size_t bytes_to_read = MAX_READ;+	if ((int64_t)bytes_to_read > zip->entry_bytes_remaining) { 		bytes_to_read = (size_t)zip->entry_bytes_remaining; 	} 	bytes = read_stream(a, buff, bytes_to_read, 0);@@ -1181,7 +1146,7 @@ 		    zip->entry_crc32) { 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 			    "7-Zip bad CRC: 0x%lx should be 0x%lx",-			    (unsigned long)zip->entry_crc32,+			    zip->entry_crc32, 			    (unsigned long)zip->si.ss.digests[ 			    		zip->entry->ssIndex]); 			ret = ARCHIVE_WARN;@@ -1198,10 +1163,8 @@ static int archive_read_format_7zip_read_data_skip(struct archive_read *a) {-	struct _7zip *zip;-	int64_t bytes_skipped;--	zip = (struct _7zip *)(a->format->data);+	struct _7zip *zip = a->format->data;+	int r;  	if (zip->pack_stream_bytes_unconsumed) 		read_consume(a);@@ -1214,9 +1177,9 @@ 	 * If the length is at the beginning, we can skip the 	 * compressed data much more quickly. 	 */-	bytes_skipped = skip_stream(a, (size_t)zip->entry_bytes_remaining);-	if (bytes_skipped < 0)-		return ((int)bytes_skipped);+	r = skip_stream(a, zip->entry_bytes_remaining);+	if (r < 0)+		return (r); 	zip->entry_bytes_remaining = 0;  	/* This entry is finished and done. */@@ -1227,9 +1190,8 @@ static int archive_read_format_7zip_cleanup(struct archive_read *a) {-	struct _7zip *zip;+	struct _7zip *zip = a->format->data; -	zip = (struct _7zip *)(a->format->data); 	free_StreamsInfo(&(zip->si)); 	free(zip->entries); 	free(zip->entry_names);@@ -1240,24 +1202,30 @@ 	free(zip->sub_stream_buff[2]); 	free(zip->tmp_stream_buff); 	free(zip);-	(a->format->data) = NULL;+	a->format->data = NULL; 	return (ARCHIVE_OK); } -static void+static int read_consume(struct archive_read *a) {-	struct _7zip *zip = (struct _7zip *)a->format->data;+	struct _7zip *zip = a->format->data;  	if (zip->pack_stream_bytes_unconsumed) {-		__archive_read_consume(a, zip->pack_stream_bytes_unconsumed);+		int64_t r;++		if ((r = __archive_read_consume(a,+		    zip->pack_stream_bytes_unconsumed)) < 0)+			return ((int)r);+ 		zip->stream_offset += zip->pack_stream_bytes_unconsumed; 		zip->pack_stream_bytes_unconsumed = 0; 	}++	return (ARCHIVE_OK); }  #ifdef HAVE_LZMA_H- /*  * Set an error code and choose an error message for liblzma.  */@@ -1305,22 +1273,19 @@ 		break; 	} }- #endif  static int-decode_codec_id(const unsigned char *codecId, size_t id_size, uint64_t *id)+decode_codec_id(const unsigned char *codecId, size_t id_size, int64_t *id) {-	unsigned i;-	uint64_t v = 0;+	size_t i; +	*id = 0; 	for (i = 0; i < id_size; i++) {-		if (v > (uint64_t)INT64_MAX / 256)+		if (archive_ckd_mul_i64(id, *id, 256) ||+		    archive_ckd_add_i64(id, *id, codecId[i])) 			return (-1);-		v <<= 8;-		v += codecId[i]; 	}-	*id = v; 	return (0); } @@ -1328,7 +1293,7 @@ ppmd_read(void *p) { 	struct archive_read *a = ((IByteIn*)p)->a;-	struct _7zip *zip = (struct _7zip *)(a->format->data);+	struct _7zip *zip = a->format->data; 	Byte b;  	if (zip->ppstream.avail_in == 0) {@@ -1337,7 +1302,7 @@ 		 * and we are on boundary; 		 * last resort to read using __archive_read_ahead. 		 */-		const uint8_t* data = __archive_read_ahead(a,+		const uint8_t *data = __archive_read_ahead(a, 		    zip->ppstream.stream_in + 1, NULL); 		if (data == NULL) { 			archive_set_error(&a->archive,@@ -1466,7 +1431,7 @@ 				memset(&delta_opt, 0, sizeof(delta_opt)); 				delta_opt.type = LZMA_DELTA_TYPE_BYTE; 				delta_opt.dist =-				    (uint32_t)coder2->properties[0] + 1;+				    coder2->properties[0] + 1; 				filters[fi].options = &delta_opt; 				fi++; 				break;@@ -1506,7 +1471,8 @@ 			default: 				archive_set_error(&a->archive, 				    ARCHIVE_ERRNO_MISC,-				    "Unexpected codec ID: %lX", zip->codec2);+				    "Unexpected codec ID: %jX",+				    (uintmax_t)zip->codec2); 				return (ARCHIVE_FAILED); 			} 		}@@ -1518,7 +1484,7 @@ 		filters[fi].options = NULL; 		ff = &filters[fi]; 		r = lzma_properties_decode(&filters[fi], NULL,-		    coder1->properties, (size_t)coder1->propertiesSize);+		    coder1->properties, coder1->propertiesSize); 		if (r != LZMA_OK) { 			set_error(a, r); 			return (ARCHIVE_FAILED);@@ -1673,7 +1639,7 @@ 	case _7Z_SPARC: 	case _7Z_DELTA: 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,-		    "Unexpected codec ID: %lX", zip->codec);+		    "Unexpected codec ID: %jX", (uintmax_t)zip->codec); 		return (ARCHIVE_FAILED); 	case _7Z_CRYPTO_MAIN_ZIP: 	case _7Z_CRYPTO_RAR_29:@@ -1684,11 +1650,12 @@ 			zip->has_encrypted_entries = 1; 		} 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,-		    "Crypto codec not supported yet (ID: 0x%lX)", zip->codec);+		    "Crypto codec not supported yet (ID: 0x%jX)",+		    (uintmax_t)zip->codec); 		return (ARCHIVE_FAILED); 	default: 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,-		    "Unknown codec ID: %lX", zip->codec);+		    "Unknown codec ID: %jX", (uintmax_t)zip->codec); 		return (ARCHIVE_FAILED); 	} @@ -1740,7 +1707,7 @@ 	bcj2_avail_out = t_avail_out; 	if (zip->codec2 == _7Z_X86_BCJ2) { 		/*-		 * Decord a remaining decompressed main stream for BCJ2.+		 * Decode a remaining decompressed main stream for BCJ2. 		 */ 		if (zip->tmp_stream_bytes_remaining) { 			ssize_t bytes;@@ -1774,8 +1741,8 @@ 	switch (zip->codec) { 	case _7Z_COPY: 	{-		size_t bytes =-		    (t_avail_in > t_avail_out)?t_avail_out:t_avail_in;+		size_t bytes = (t_avail_in > t_avail_out) ?+		    t_avail_out : t_avail_in;  		memcpy(t_next_out, t_next_in, bytes); 		t_avail_in -= bytes;@@ -1813,10 +1780,14 @@ #endif #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR) 	case _7Z_BZ2:+		if (t_avail_in > UINT_MAX)+			t_avail_in = UINT_MAX;+		if (t_avail_out > UINT_MAX)+			t_avail_out = UINT_MAX; 		zip->bzstream.next_in = (char *)(uintptr_t)t_next_in;-		zip->bzstream.avail_in = (uint32_t)t_avail_in;+		zip->bzstream.avail_in = (unsigned int)t_avail_in; 		zip->bzstream.next_out = (char *)(uintptr_t)t_next_out;-		zip->bzstream.avail_out = (uint32_t)t_avail_out;+		zip->bzstream.avail_out = (unsigned int)t_avail_out; 		r = BZ2_bzDecompress(&(zip->bzstream)); 		switch (r) { 		case BZ_STREAM_END: /* Found end of stream. */@@ -1846,6 +1817,10 @@ #endif #ifdef HAVE_ZLIB_H 	case _7Z_DEFLATE:+		if (t_avail_in > UINT_MAX)+			t_avail_in = UINT_MAX;+		if (t_avail_out > UINT_MAX)+			t_avail_out = UINT_MAX; 		zip->stream.next_in = (Bytef *)(uintptr_t)t_next_in; 		zip->stream.avail_in = (uInt)t_avail_in; 		zip->stream.next_out = t_next_out;@@ -1869,12 +1844,17 @@ #if HAVE_ZSTD_H && HAVE_LIBZSTD 	case _7Z_ZSTD: 	{-		ZSTD_inBuffer input = { t_next_in, t_avail_in, 0 }; // src, size, pos-		ZSTD_outBuffer output = { t_next_out, t_avail_out, 0 }; // dst, size, pos+		/* src, size, pos */+		ZSTD_inBuffer input = { t_next_in, t_avail_in, 0 };+		/* dst, size, pos */+		ZSTD_outBuffer output = { t_next_out, t_avail_out, 0 }; -		size_t const zret = ZSTD_decompressStream(zip->zstd_dstream, &output, &input);+		size_t const zret = ZSTD_decompressStream(zip->zstd_dstream,+		    &output, &input); 		if (ZSTD_isError(zret)) {-			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Zstd decompression failed: %s", ZSTD_getErrorName(zret));+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+			    "Zstd decompression failed: %s",+			    ZSTD_getErrorName(zret)); 			return ARCHIVE_FAILED; 		} 		t_avail_in -= input.pos;@@ -1884,7 +1864,7 @@ #endif 	case _7Z_PPMD: 	{-		uint64_t flush_bytes;+		int64_t flush_bytes;  		if (!zip->ppmd7_valid || zip->ppmd7_stat < 0 || 		    t_avail_out <= 0) {@@ -1942,7 +1922,7 @@ 			} 			*zip->ppstream.next_out++ = (unsigned char)sym; 			zip->ppstream.avail_out--;-			if (flush_bytes)+			if (flush_bytes > 0) 				flush_bytes--; 		} while (zip->ppstream.avail_out && 			(zip->ppstream.avail_in || flush_bytes));@@ -1963,7 +1943,7 @@ 	*outbytes = o_avail_out - t_avail_out;  	/*-	 * Decord BCJ.+	 * Decode BCJ. 	 */ 	if (zip->codec != _7Z_LZMA2) { 		if (zip->codec2 == _7Z_X86) {@@ -1971,9 +1951,10 @@  			zip->odd_bcj_size = *outbytes - l; 			if (zip->odd_bcj_size > 0 && zip->odd_bcj_size <= 4 &&-		    	o_avail_in && ret != ARCHIVE_EOF) {-				memcpy(zip->odd_bcj, ((unsigned char *)buff) + l,-			    	zip->odd_bcj_size);+			    o_avail_in && ret != ARCHIVE_EOF) {+				memcpy(zip->odd_bcj,+				    ((unsigned char *)buff) + l,+				    zip->odd_bcj_size); 				*outbytes = l; 			} else 				zip->odd_bcj_size = 0;@@ -1989,7 +1970,7 @@ 	}  	/*-	 * Decord BCJ2 with a decompressed main stream.+	 * Decode BCJ2 with a decompressed main stream. 	 */ 	if (zip->codec2 == _7Z_X86_BCJ2) { 		ssize_t bytes;@@ -1997,7 +1978,7 @@ 		zip->tmp_stream_bytes_avail = 		    zip->tmp_stream_buff_size - t_avail_out; 		if (zip->tmp_stream_bytes_avail >-		      zip->main_stream_bytes_remaining)+		      (uint64_t)zip->main_stream_bytes_remaining) 			zip->tmp_stream_bytes_avail = 			    zip->main_stream_bytes_remaining; 		zip->tmp_stream_bytes_remaining = zip->tmp_stream_bytes_avail;@@ -2065,8 +2046,21 @@ }  static int-parse_7zip_uint64(struct archive_read *a, uint64_t *val)+parse_7zip_size(struct archive_read *a, size_t *val) {+	int64_t v;++	if (parse_7zip_int64(a, &v) < 0 || v > UMAX_ENTRY)+		return (-1);++	*val = (size_t)v;+	return (0);+}++static int+parse_7zip_int64(struct archive_read *a, int64_t *val)+{+	uint64_t v; 	const unsigned char *p; 	unsigned char avail, mask; 	int i;@@ -2075,18 +2069,21 @@ 		return (-1); 	avail = *p; 	mask = 0x80;-	*val = 0;+	v = 0; 	for (i = 0; i < 8; i++) { 		if (avail & mask) { 			if ((p = header_bytes(a, 1)) == NULL) 				return (-1);-			*val |= ((uint64_t)*p) << (8 * i);+			v |= ((uint64_t)*p) << (8 * i); 			mask >>= 1; 			continue; 		}-		*val += ((uint64_t)(avail & (mask -1))) << (8 * i);+		v += ((uint64_t)(avail & (mask - 1))) << (8 * i); 		break; 	}+	if (v > (uint64_t)INT64_MAX)+		return (-1);+	*val = (int64_t)v; 	return (0); } @@ -2094,7 +2091,8 @@ read_Bools(struct archive_read *a, unsigned char *data, size_t num) { 	const unsigned char *p;-	unsigned i, mask = 0, avail = 0;+	size_t i;+	unsigned mask = 0, avail = 0;  	for (i = 0; i < num; i++) { 		if (mask == 0) {@@ -2103,7 +2101,7 @@ 			avail = *p; 			mask = 0x80; 		}-		data[i] = (avail & mask)?1:0;+		data[i] = (avail & mask) ? 1 : 0; 		mask >>= 1; 	} 	return (0);@@ -2120,7 +2118,7 @@ read_Digests(struct archive_read *a, struct _7z_digests *d, size_t num) { 	const unsigned char *p;-	unsigned i;+	size_t i;  	if (num == 0) 		return (-1);@@ -2167,25 +2165,23 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi) { 	const unsigned char *p;-	unsigned i;+	size_t i;  	memset(pi, 0, sizeof(*pi));  	/* 	 * Read PackPos. 	 */-	if (parse_7zip_uint64(a, &(pi->pos)) < 0)+	if (parse_7zip_int64(a, &(pi->pos)) < 0) 		return (-1);  	/* 	 * Read NumPackStreams. 	 */-	if (parse_7zip_uint64(a, &(pi->numPackStreams)) < 0)+	if (parse_7zip_size(a, &(pi->numPackStreams)) < 0) 		return (-1); 	if (pi->numPackStreams == 0) 		return (-1);-	if (UMAX_ENTRY < pi->numPackStreams)-		return (-1);  	/* 	 * Read PackSizes[num]@@ -2197,13 +2193,13 @@ 		return (0); 	if (*p != kSize) 		return (-1);-	pi->sizes = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));-	pi->positions = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));+	pi->sizes = calloc(pi->numPackStreams, sizeof(int64_t));+	pi->positions = calloc(pi->numPackStreams, sizeof(int64_t)); 	if (pi->sizes == NULL || pi->positions == NULL) 		return (-1);  	for (i = 0; i < pi->numPackStreams; i++) {-		if (parse_7zip_uint64(a, &(pi->sizes[i])) < 0)+		if (parse_7zip_int64(a, &(pi->sizes[i])) < 0) 			return (-1); 	} @@ -2215,9 +2211,9 @@ 	if (*p == kEnd) { 		/* PackStreamDigests[num] are not present. */ 		pi->digest.defineds =-		    calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.defineds));+		    calloc(pi->numPackStreams, sizeof(*pi->digest.defineds)); 		pi->digest.digests =-		    calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.digests));+		    calloc(pi->numPackStreams, sizeof(*pi->digest.digests)); 		if (pi->digest.defineds == NULL || pi->digest.digests == NULL) 			return (-1); 		return (0);@@ -2226,7 +2222,7 @@ 	if (*p != kCRC) 		return (-1); -	if (read_Digests(a, &(pi->digest), (size_t)pi->numPackStreams) < 0)+	if (read_Digests(a, &(pi->digest), pi->numPackStreams) < 0) 		return (-1);  	/*@@ -2242,40 +2238,39 @@ static void free_Folder(struct _7z_folder *f) {-	unsigned i;- 	if (f->coders) {+		size_t i;+ 		for (i = 0; i< f->numCoders; i++) { 			free(f->coders[i].properties); 		} 		free(f->coders); 	} 	free(f->bindPairs);-	free(f->packedStreams); 	free(f->unPackSize); }  static int read_Folder(struct archive_read *a, struct _7z_folder *f) {-	struct _7zip *zip = (struct _7zip *)a->format->data;+	struct _7zip *zip = a->format->data; 	const unsigned char *p;-	uint64_t numInStreamsTotal = 0;-	uint64_t numOutStreamsTotal = 0;-	unsigned i;+	size_t numInStreamsTotal = 0;+	size_t numOutStreamsTotal = 0;+	size_t i;  	memset(f, 0, sizeof(*f));  	/* 	 * Read NumCoders. 	 */-	if (parse_7zip_uint64(a, &(f->numCoders)) < 0)+	if (parse_7zip_size(a, &(f->numCoders)) < 0) 		return (-1); 	if (f->numCoders > 4) 		/* Too many coders. */ 		return (-1); -	f->coders = calloc((size_t)f->numCoders, sizeof(*f->coders));+	f->coders = calloc(f->numCoders, sizeof(*f->coders)); 	if (f->coders == NULL) 		return (-1); 	for (i = 0; i< f->numCoders; i++) {@@ -2293,7 +2288,7 @@ 		 * 7:  Must be zero. 		 */ 		codec_size = *p & 0xf;-		simple = (*p & 0x10)?0:1;+		simple = (*p & 0x10) ? 0 : 1; 		attr = *p & 0x20; 		if (*p & 0x80) 			return (-1);/* Not supported. */@@ -2311,37 +2306,34 @@ 			f->coders[i].numInStreams = 1; 			f->coders[i].numOutStreams = 1; 		} else {-			if (parse_7zip_uint64(+			if (parse_7zip_size( 			    a, &(f->coders[i].numInStreams)) < 0) 				return (-1);-			if (UMAX_ENTRY < f->coders[i].numInStreams)-				return (-1);-			if (parse_7zip_uint64(+			if (parse_7zip_size( 			    a, &(f->coders[i].numOutStreams)) < 0) 				return (-1);-			if (UMAX_ENTRY < f->coders[i].numOutStreams)-				return (-1); 		}  		if (attr) {-			if (parse_7zip_uint64(+			if (parse_7zip_size( 			    a, &(f->coders[i].propertiesSize)) < 0) 				return (-1);-			if (UMAX_ENTRY < f->coders[i].propertiesSize)-				return (-1); 			if ((p = header_bytes(-			    a, (size_t)f->coders[i].propertiesSize)) == NULL)+			    a, f->coders[i].propertiesSize)) == NULL) 				return (-1); 			f->coders[i].properties =-			    malloc((size_t)f->coders[i].propertiesSize);+			    malloc(f->coders[i].propertiesSize); 			if (f->coders[i].properties == NULL) 				return (-1); 			memcpy(f->coders[i].properties, p,-			    (size_t)f->coders[i].propertiesSize);+			    f->coders[i].propertiesSize); 		} -		numInStreamsTotal += f->coders[i].numInStreams;-		numOutStreamsTotal += f->coders[i].numOutStreams;+		if (archive_ckd_add_size(&numInStreamsTotal,+		    numInStreamsTotal, f->coders[i].numInStreams) ||+		    archive_ckd_add_size(&numOutStreamsTotal,+		    numOutStreamsTotal, f->coders[i].numOutStreams))+			return (-1); 	}  	if (numOutStreamsTotal == 0 ||@@ -2349,34 +2341,27 @@ 		return (-1);  	f->numBindPairs = numOutStreamsTotal - 1;-	if (zip->header_bytes_remaining < f->numBindPairs)+	if ((uint64_t)zip->header_bytes_remaining < f->numBindPairs) 			return (-1); 	if (f->numBindPairs > 0) { 		f->bindPairs =-			calloc((size_t)f->numBindPairs, sizeof(*f->bindPairs));+			calloc(f->numBindPairs, sizeof(*f->bindPairs)); 		if (f->bindPairs == NULL) 			return (-1); 	} else 		f->bindPairs = NULL; 	for (i = 0; i < f->numBindPairs; i++) {-		if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0)-			return (-1);-		if (UMAX_ENTRY < f->bindPairs[i].inIndex)-			return (-1);-		if (parse_7zip_uint64(a, &(f->bindPairs[i].outIndex)) < 0)+		if (parse_7zip_size(a, &(f->bindPairs[i].inIndex)) < 0) 			return (-1);-		if (UMAX_ENTRY < f->bindPairs[i].outIndex)+		if (parse_7zip_size(a, &(f->bindPairs[i].outIndex)) < 0) 			return (-1); 	}  	f->numPackedStreams = numInStreamsTotal - f->numBindPairs;-	f->packedStreams =-	    calloc((size_t)f->numPackedStreams, sizeof(*f->packedStreams));-	if (f->packedStreams == NULL)-		return (-1);+	/* packedStreams are not needed; parse/verify nonetheless */ 	if (f->numPackedStreams == 1) { 		for (i = 0; i < numInStreamsTotal; i++) {-			unsigned j;+			size_t j; 			for (j = 0; j < f->numBindPairs; j++) { 				if (f->bindPairs[j].inIndex == i) 					break;@@ -2386,12 +2371,10 @@ 		} 		if (i == numInStreamsTotal) 			return (-1);-		f->packedStreams[0] = i; 	} else { 		for (i = 0; i < f->numPackedStreams; i++) {-			if (parse_7zip_uint64(a, &(f->packedStreams[i])) < 0)-				return (-1);-			if (UMAX_ENTRY < f->packedStreams[i])+			size_t packedStream;+			if (parse_7zip_size(a, &packedStream) < 0) 				return (-1); 		} 	}@@ -2404,7 +2387,7 @@ static void free_CodersInfo(struct _7z_coders_info *ci) {-	unsigned i;+	size_t i;  	if (ci->folders) { 		for (i = 0; i < ci->numFolders; i++)@@ -2416,9 +2399,10 @@ static int read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci) {+	struct _7zip *zip = a->format->data; 	const unsigned char *p; 	struct _7z_digests digest;-	unsigned i;+	size_t dataStreamIndex, i;  	memset(ci, 0, sizeof(*ci)); 	memset(&digest, 0, sizeof(digest));@@ -2431,10 +2415,16 @@ 	/* 	 * Read NumFolders. 	 */-	if (parse_7zip_uint64(a, &(ci->numFolders)) < 0)+	if (parse_7zip_size(a, &(ci->numFolders)) < 0) 		goto failed;-	if (UMAX_ENTRY < ci->numFolders)-		return (-1);+	/*+	 * Each folder is encoded by at least one byte in the coders+	 * list that follows, so a folder count larger than the bytes+	 * left in the header cannot be honored and is rejected here+	 * before it is used to size the folders allocation.+	 */+	if (ci->numFolders > (uint64_t)zip->header_bytes_remaining)+		goto failed;  	/* 	 * Read External.@@ -2444,7 +2434,7 @@ 	switch (*p) { 	case 0: 		ci->folders =-			calloc((size_t)ci->numFolders, sizeof(*ci->folders));+			calloc(ci->numFolders, sizeof(*ci->folders)); 		if (ci->folders == NULL) 			return (-1); 		for (i = 0; i < ci->numFolders; i++) {@@ -2453,9 +2443,7 @@ 		} 		break; 	case 1:-		if (parse_7zip_uint64(a, &(ci->dataStreamIndex)) < 0)-			return (-1);-		if (UMAX_ENTRY < ci->dataStreamIndex)+		if (parse_7zip_size(a, &dataStreamIndex) < 0) 			return (-1); 		if (ci->numFolders > 0) { 			archive_set_error(&a->archive, -1,@@ -2476,14 +2464,14 @@  	for (i = 0; i < ci->numFolders; i++) { 		struct _7z_folder *folder = &(ci->folders[i]);-		unsigned j;+		size_t j;  		folder->unPackSize =-		    calloc((size_t)folder->numOutStreams, sizeof(*folder->unPackSize));+		    calloc(folder->numOutStreams, sizeof(*folder->unPackSize)); 		if (folder->unPackSize == NULL) 			goto failed; 		for (j = 0; j < folder->numOutStreams; j++) {-			if (parse_7zip_uint64(a, &(folder->unPackSize[j])) < 0)+			if (parse_7zip_int64(a, &(folder->unPackSize[j])) < 0) 				goto failed; 		} 	}@@ -2497,7 +2485,7 @@ 		return (0); 	if (*p != kCRC) 		goto failed;-	if (read_Digests(a, &digest, (size_t)ci->numFolders) < 0)+	if (read_Digests(a, &digest, ci->numFolders) < 0) 		goto failed; 	for (i = 0; i < ci->numFolders; i++) { 		ci->folders[i].digest_defined = digest.defineds[i];@@ -2518,16 +2506,16 @@ 	return (-1); } -static uint64_t+static int64_t folder_uncompressed_size(struct _7z_folder *f) {-	int n = (int)f->numOutStreams;-	unsigned pairs = (unsigned)f->numBindPairs;+	size_t n = f->numOutStreams;+	size_t pairs = f->numBindPairs; -	while (--n >= 0) {-		unsigned i;+	while (n-- > 0) {+		size_t i; 		for (i = 0; i < pairs; i++) {-			if (f->bindPairs[i].outIndex == (uint64_t)n)+			if (f->bindPairs[i].outIndex == n) 				break; 		} 		if (i >= pairs)@@ -2549,11 +2537,11 @@     struct _7z_folder *f, size_t numFolders) { 	const unsigned char *p;-	uint64_t *usizes;+	int64_t *usizes;+	size_t numDigests; 	size_t unpack_streams;+	size_t i; 	int type;-	unsigned i;-	uint32_t numDigests;  	memset(ss, 0, sizeof(*ss)); @@ -2567,13 +2555,11 @@ 	if (type == kNumUnPackStream) { 		unpack_streams = 0; 		for (i = 0; i < numFolders; i++) {-			if (parse_7zip_uint64(a, &(f[i].numUnpackStreams)) < 0)+			if (parse_7zip_size(a, &(f[i].numUnpackStreams)) < 0) 				return (-1);-			if (f[i].numUnpackStreams >-			    UMAX_ENTRY - unpack_streams) {+			if (archive_ckd_add_size(&unpack_streams,+			    unpack_streams, f[i].numUnpackStreams)) 				return (-1);-			}-			unpack_streams += (size_t)f[i].numUnpackStreams; 		} 		if ((p = header_bytes(a, 1)) == NULL) 			return (-1);@@ -2581,6 +2567,9 @@ 	} else 		unpack_streams = numFolders; +	if (unpack_streams > UMAX_ENTRY)+		return (-1);+ 	if (type != kSize) { 		for (i = 0; i < numFolders; i++) { 			if (f[i].numUnpackStreams > 1)@@ -2603,8 +2592,8 @@  	usizes = ss->unpackSizes; 	for (i = 0; i < numFolders; i++) {-		unsigned pack;-		uint64_t size, sum;+		int64_t size, sum;+		size_t pack;  		if (f[i].numUnpackStreams == 0) 			continue;@@ -2612,11 +2601,10 @@ 		sum = 0; 		if (type == kSize) { 			for (pack = 1; pack < f[i].numUnpackStreams; pack++) {-				if (parse_7zip_uint64(a, usizes) < 0)+				if (parse_7zip_int64(a, usizes) < 0) 					return (-1);-				if (*usizes > UINT64_MAX - sum)+				if (archive_ckd_add_i64(&sum, sum, *usizes++)) 					return (-1);-				sum += *usizes++; 			} 		} 		size = folder_uncompressed_size(&f[i]);@@ -2634,14 +2622,18 @@ 	numDigests = 0; 	for (i = 0; i < numFolders; i++) { 		if (f[i].numUnpackStreams != 1 || !f[i].digest_defined)-			numDigests += (uint32_t)f[i].numUnpackStreams;+			if (archive_ckd_add_size(&numDigests,+			    numDigests, f[i].numUnpackStreams)) {+				errno = ENOMEM;+				return (-1);+			} 	}  	if (type == kCRC) { 		struct _7z_digests tmpDigests; 		unsigned char *digestsDefined = ss->digestsDefined;-		uint32_t * digests = ss->digests;-		int di = 0;+		uint32_t *digests = ss->digests;+		size_t di = 0;  		memset(&tmpDigests, 0, sizeof(tmpDigests)); 		if (read_Digests(a, &(tmpDigests), numDigests) < 0) {@@ -2653,7 +2645,7 @@ 				*digestsDefined++ = 1; 				*digests++ = f[i].digest; 			} else {-				unsigned j;+				size_t j;  				for (j = 0; j < f[i].numUnpackStreams; 				    j++, di++) {@@ -2689,16 +2681,16 @@ static int read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si) {-	struct _7zip *zip = (struct _7zip *)a->format->data;+	struct _7zip *zip = a->format->data; 	const unsigned char *p;-	unsigned i;+	size_t i;  	memset(si, 0, sizeof(*si));  	if ((p = header_bytes(a, 1)) == NULL) 		return (-1); 	if (*p == kPackInfo) {-		uint64_t packPos;+		int64_t packPos;  		if (read_PackInfo(a, &(si->pi)) < 0) 			return (-1);@@ -2711,9 +2703,9 @@ 		packPos = si->pi.pos; 		for (i = 0; i < si->pi.numPackStreams; i++) { 			si->pi.positions[i] = packPos;-			if (packPos > UINT64_MAX - si->pi.sizes[i])+			if (archive_ckd_add_i64(&packPos,+			    packPos, si->pi.sizes[i])) 				return (-1);-			packPos += si->pi.sizes[i]; 			if (packPos > zip->header_offset) 				return (-1); 		}@@ -2721,7 +2713,7 @@ 			return (-1); 	} 	if (*p == kUnPackInfo) {-		uint32_t packIndex;+		size_t packIndex; 		struct _7z_folder *f;  		if (read_CodersInfo(a, &(si->ci)) < 0)@@ -2734,12 +2726,9 @@ 		f = si->ci.folders; 		for (i = 0; i < si->ci.numFolders; i++) { 			f[i].packIndex = packIndex;-			if (f[i].numPackedStreams > UINT32_MAX)-				return (-1);-			if (packIndex > UINT32_MAX - (uint32_t)f[i].numPackedStreams)-				return (-1);-			packIndex += (uint32_t)f[i].numPackedStreams;-			if (packIndex > si->pi.numPackStreams)+			if (archive_ckd_add_size(&packIndex,+			    packIndex, f[i].numPackedStreams) ||+			    packIndex > si->pi.numPackStreams) 				return (-1); 		} 		if ((p = header_bytes(a, 1)) == NULL)@@ -2748,7 +2737,7 @@  	if (*p == kSubStreamsInfo) { 		if (read_SubStreamsInfo(a, &(si->ss),-		    si->ci.folders, (size_t)si->ci.numFolders) < 0)+		    si->ci.folders, si->ci.numFolders) < 0) 			return (-1); 		if ((p = header_bytes(a, 1)) == NULL) 			return (-1);@@ -2771,18 +2760,38 @@ 	free(h->attrBools); } +/*+ * Files without unpack streams must be described by the EmptyStream bitmap,+ * which consumes one bit for every file entry in FilesInfo.+ */ static int+files_info_numfiles_is_sane(const struct _7zip *zip)+{+	int64_t empty_stream_map_bytes;++	if (zip->numFiles > SIZE_MAX / sizeof(*zip->entries))+		return (0);++	if (zip->numFiles <= zip->si.ss.unpack_streams)+		return (1);++	empty_stream_map_bytes = (zip->numFiles + 7) / 8;+	return (empty_stream_map_bytes <= zip->header_bytes_remaining);+}++static int read_Header(struct archive_read *a, struct _7z_header_info *h,     int check_header_id) {-	struct _7zip *zip = (struct _7zip *)a->format->data;+	struct _7zip *zip = a->format->data; 	const unsigned char *p; 	struct _7z_folder *folders; 	struct _7z_stream_info *si = &(zip->si); 	struct _7zip_entry *entries;-	uint32_t folderIndex, indexInFolder;-	unsigned i;-	int eindex, empty_streams, sindex;+	size_t folderIndex, indexInFolder;+	size_t i;+	size_t eindex, empty_streams, sindex;+	int attr_seen = 0;  	if (check_header_id) { 		/*@@ -2801,13 +2810,26 @@ 		return (-1); 	if (*p == kArchiveProperties) { 		for (;;) {-			uint64_t size;+			int64_t size; 			if ((p = header_bytes(a, 1)) == NULL) 				return (-1);-			if (*p == 0)+			if (*p == kEnd) 				break;-			if (parse_7zip_uint64(a, &size) < 0)+			if (parse_7zip_int64(a, &size) < 0) 				return (-1);+			if (size < 0 || zip->header_bytes_remaining < size)+				return (-1);++			/* Skip the property data to keep header parsing aligned. */+			while (size > 0) {+				int64_t skip = size;++				if (skip > UBUFF_SIZE)+					skip = UBUFF_SIZE;+				if (header_bytes(a, (size_t)skip) == NULL)+					return (-1);+				size -= skip;+			} 		} 		if ((p = header_bytes(a, 1)) == NULL) 			return (-1);@@ -2831,12 +2853,12 @@ 	if (*p != kFilesInfo) 		return (-1); -	if (parse_7zip_uint64(a, &(zip->numFiles)) < 0)+	if (parse_7zip_size(a, &(zip->numFiles)) < 0) 		return (-1); 	if (!files_info_numfiles_is_sane(zip)) 		return (-1); -	zip->entries = calloc((size_t)zip->numFiles, sizeof(*zip->entries));+	zip->entries = calloc(zip->numFiles, sizeof(*zip->entries)); 	if (zip->entries == NULL) 		return (-1); 	entries = zip->entries;@@ -2844,7 +2866,7 @@ 	empty_streams = 0; 	for (;;) { 		int type;-		uint64_t size;+		int64_t size; 		size_t ll;  		if ((p = header_bytes(a, 1)) == NULL)@@ -2853,9 +2875,10 @@ 		if (type == kEnd) 			break; -		if (parse_7zip_uint64(a, &size) < 0)+		if (parse_7zip_int64(a, &size) < 0) 			return (-1);-		if (zip->header_bytes_remaining < size || size > SIZE_MAX / 4)+		if (zip->header_bytes_remaining < size ||+		    size > (int64_t)(SIZE_MAX / 4)) 			return (-1); 		ll = (size_t)size; @@ -2863,12 +2886,12 @@ 		case kEmptyStream: 			if (h->emptyStreamBools != NULL) 				return (-1);-			h->emptyStreamBools = calloc((size_t)zip->numFiles,+			h->emptyStreamBools = calloc(zip->numFiles, 			    sizeof(*h->emptyStreamBools)); 			if (h->emptyStreamBools == NULL) 				return (-1); 			if (read_Bools(-			    a, h->emptyStreamBools, (size_t)zip->numFiles) < 0)+			    a, h->emptyStreamBools, zip->numFiles) < 0) 				return (-1); 			empty_streams = 0; 			for (i = 0; i < zip->numFiles; i++) {@@ -2911,7 +2934,7 @@ 		case kCTime: 		case kATime: 		case kMTime:-			if (read_Times(a, h, type) < 0)+			if (read_Times(a, type) < 0) 				return (-1); 			break; 		case kName:@@ -2981,21 +3004,20 @@ 			if ((p = header_bytes(a, 2)) == NULL) 				return (-1); 			allAreDefined = *p;-			if (h->attrBools != NULL)-				return (-1);-			h->attrBools = calloc((size_t)zip->numFiles,-			    sizeof(*h->attrBools));-			if (h->attrBools == NULL)+			if (attr_seen) 				return (-1);-			if (allAreDefined)-				memset(h->attrBools, 1, (size_t)zip->numFiles);-			else {+			attr_seen = 1;+			if (!allAreDefined) {+				h->attrBools = calloc(zip->numFiles,+				    sizeof(*h->attrBools));+				if (h->attrBools == NULL)+					return (-1); 				if (read_Bools(a, h->attrBools,-				      (size_t)zip->numFiles) < 0)+				    zip->numFiles) < 0) 					return (-1); 			} 			for (i = 0; i < zip->numFiles; i++) {-				if (h->attrBools[i]) {+				if (allAreDefined || h->attrBools[i]) { 					if ((p = header_bytes(a, 4)) == NULL) 						return (-1); 					entries[i].attr = archive_le32dec(p);@@ -3048,7 +3070,7 @@ 		}  		if (entries[i].flg & HAS_STREAM) {-			if ((size_t)sindex >= si->ss.unpack_streams)+			if (sindex >= si->ss.unpack_streams) 				return (-1); 			if (entries[i].mode == 0) 				entries[i].mode = AE_IFREG | 0666;@@ -3057,14 +3079,10 @@ 			entries[i].ssIndex = sindex; 			sindex++; 		} else {-			int dir;-			if (h->emptyFileBools == NULL)-				dir = 1;-			else {-				if (h->emptyFileBools[eindex])-					dir = 0;-				else-					dir = 1;+			int dir = 1;++			if (h->emptyFileBools != NULL) {+				dir = !h->emptyFileBools[eindex]; 				eindex++; 			} 			if (entries[i].mode == 0) {@@ -3121,42 +3139,38 @@ }  static int-read_Times(struct archive_read *a, struct _7z_header_info *h, int type)+read_Times(struct archive_read *a, int type) {-	struct _7zip *zip = (struct _7zip *)a->format->data;+	struct _7zip *zip = a->format->data; 	const unsigned char *p; 	struct _7zip_entry *entries = zip->entries;-	unsigned char *timeBools;+	unsigned char *timeBools = NULL; 	int allAreDefined;-	unsigned i;--	timeBools = calloc((size_t)zip->numFiles, sizeof(*timeBools));-	if (timeBools == NULL)-		return (-1);+	size_t dataIndex, i;  	/* Read allAreDefined. */ 	if ((p = header_bytes(a, 1)) == NULL) 		goto failed; 	allAreDefined = *p;-	if (allAreDefined)-		memset(timeBools, 1, (size_t)zip->numFiles);-	else {-		if (read_Bools(a, timeBools, (size_t)zip->numFiles) < 0)++	if (!allAreDefined) {+		timeBools = calloc(zip->numFiles, sizeof(*timeBools));+		if (timeBools == NULL) 			goto failed;+		if (read_Bools(a, timeBools, zip->numFiles) < 0)+			goto failed; 	}  	/* Read external. */ 	if ((p = header_bytes(a, 1)) == NULL) 		goto failed; 	if (*p) {-		if (parse_7zip_uint64(a, &(h->dataIndex)) < 0)-			goto failed;-		if (UMAX_ENTRY < h->dataIndex)+		if (parse_7zip_size(a, &dataIndex) < 0) 			goto failed; 	}  	for (i = 0; i < zip->numFiles; i++) {-		if (!timeBools[i])+		if (!allAreDefined && !timeBools[i]) 			continue; 		if ((p = header_bytes(a, 8)) == NULL) 			goto failed;@@ -3192,7 +3206,8 @@ static int decode_encoded_header_info(struct archive_read *a, struct _7z_stream_info *si) {-	struct _7zip *zip = (struct _7zip *)a->format->data;+	struct _7zip *zip = a->format->data;+	int64_t pi_end;  	errno = 0; 	if (read_StreamsInfo(a, si) < 0) {@@ -3210,9 +3225,12 @@ 		return (ARCHIVE_FATAL); 	} -	if (zip->header_offset < si->pi.pos + si->pi.sizes[0] ||-	    (int64_t)(si->pi.pos + si->pi.sizes[0]) < 0 ||-	    si->pi.sizes[0] == 0 || (int64_t)si->pi.pos < 0) {+	if (archive_ckd_add_i64(&pi_end, si->pi.pos, si->pi.sizes[0])) {+		archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");+		return (ARCHIVE_FATAL);+	}++	if (zip->header_offset < pi_end) { 		archive_set_error(&a->archive, -1, "Malformed Header offset"); 		return (ARCHIVE_FATAL); 	}@@ -3223,10 +3241,10 @@ static const unsigned char * header_bytes(struct archive_read *a, size_t rbytes) {-	struct _7zip *zip = (struct _7zip *)a->format->data;+	struct _7zip *zip = a->format->data; 	const unsigned char *p; -	if (zip->header_bytes_remaining < rbytes)+	if ((uint64_t)zip->header_bytes_remaining < rbytes) 		return (NULL); 	if (zip->pack_stream_bytes_unconsumed) 		read_consume(a);@@ -3258,8 +3276,8 @@     struct _7z_header_info *header) { 	const unsigned char *p;-	uint64_t next_header_offset;-	uint64_t next_header_size;+	int64_t next_header_offset;+	int64_t next_header_size; 	uint32_t next_header_crc; 	ssize_t bytes_avail; 	int64_t data_offset;@@ -3277,7 +3295,10 @@ 		return (ARCHIVE_FATAL); 	} -	zip->seek_base = (uint64_t)data_offset + 32;+	if (archive_ckd_add_i64(&zip->seek_base, data_offset, 32)) {+		archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");+		return (ARCHIVE_FATAL);+	}  	if (memcmp(p, _7ZIP_SIGNATURE, 6) != 0) { 		archive_set_error(&a->archive, -1, "Not 7-Zip archive file");@@ -3294,25 +3315,35 @@ 	}  	next_header_offset = archive_le64dec(p + 12);+	if (next_header_offset < 0) {+		archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");+		return (ARCHIVE_FATAL);+	} 	next_header_size = archive_le64dec(p + 20);+	if (next_header_size < 0) {+		archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");+		return (ARCHIVE_FATAL);+	} 	next_header_crc = archive_le32dec(p + 28);  	if (next_header_size == 0)-		/* There is no entry in an archive file. */+		/* There is no entry in the archive file. */ 		return (ARCHIVE_EOF); -	if (((int64_t)next_header_offset) < 0) {-		archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");-		return (ARCHIVE_FATAL);-	} 	__archive_read_consume(a, 32); 	if (next_header_offset != 0) {-		if (bytes_avail >= (ssize_t)next_header_offset)+		if (bytes_avail >= next_header_offset) 			__archive_read_consume(a, next_header_offset);-		else if (seek_compat(a,-		    next_header_offset + zip->seek_base, SEEK_SET, 1) < 0) {-			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");-			return (ARCHIVE_FATAL);+		else {+			int64_t target;++			if (archive_ckd_add_i64(&target,+			    zip->seek_base, next_header_offset) ||+			    seek_compat(a, target, SEEK_SET, 1) < 0) {+				archive_set_error(&a->archive,+				    ARCHIVE_ERRNO_MISC, "Seek error");+				return (ARCHIVE_FATAL);+			} 		} 	} 	zip->stream_offset = next_header_offset;@@ -3424,10 +3455,10 @@ get_uncompressed_data(struct archive_read *a, const void **buff, size_t size,     size_t minimum) {-	struct _7zip *zip = (struct _7zip *)a->format->data;+	struct _7zip *zip = a->format->data; 	ssize_t bytes_avail; -	if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {+	if (zip->codec == _7Z_COPY && zip->codec2 == -1) { 		/* Copy mode. */  		*buff = __archive_read_ahead(a, minimum, &bytes_avail);@@ -3473,14 +3504,25 @@ 	return (bytes_avail); } +static size_t+align_size(size_t s)+{+	size_t r;++	if (archive_ckd_add_size(&r, s, 1023))+		return (s);+	r &= ~0x3ff;+	return (r);+}+ static ssize_t extract_pack_stream(struct archive_read *a, size_t minimum) {-	struct _7zip *zip = (struct _7zip *)a->format->data;+	struct _7zip *zip = a->format->data; 	ssize_t bytes_avail; 	int r; -	if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {+	if (zip->codec == _7Z_COPY && zip->codec2 == -1) { 		if (minimum == 0) 			minimum = 1; 		if (__archive_read_ahead(a, minimum, &bytes_avail) == NULL@@ -3490,10 +3532,10 @@ 			    "Truncated 7-Zip file body"); 			return (ARCHIVE_FATAL); 		}-		if ((uint64_t)bytes_avail > zip->pack_stream_inbytes_remaining)+		if (bytes_avail > zip->pack_stream_inbytes_remaining) 			bytes_avail = (ssize_t)zip->pack_stream_inbytes_remaining; 		zip->pack_stream_inbytes_remaining -= bytes_avail;-		if ((uint64_t)bytes_avail > zip->folder_outbytes_remaining)+		if (bytes_avail > zip->folder_outbytes_remaining) 			bytes_avail = (ssize_t)zip->folder_outbytes_remaining; 		zip->folder_outbytes_remaining -= bytes_avail; 		zip->uncompressed_buffer_bytes_remaining = bytes_avail;@@ -3502,18 +3544,17 @@  	/* If the buffer hasn't been allocated, allocate it now. */ 	if (zip->uncompressed_buffer == NULL) {-		zip->uncompressed_buffer_size = UBUFF_SIZE;-		if (zip->uncompressed_buffer_size < minimum) {-			zip->uncompressed_buffer_size = minimum + 1023;-			zip->uncompressed_buffer_size &= ~0x3ff;-		}-		zip->uncompressed_buffer =-		    malloc(zip->uncompressed_buffer_size);+		size_t new_size = UBUFF_SIZE;++		if (new_size < minimum)+		    new_size = align_size(minimum);+		zip->uncompressed_buffer = malloc(new_size); 		if (zip->uncompressed_buffer == NULL) { 			archive_set_error(&a->archive, ENOMEM, 			    "No memory for 7-Zip decompression"); 			return (ARCHIVE_FATAL); 		}+		zip->uncompressed_buffer_size = new_size; 		zip->uncompressed_buffer_bytes_remaining = 0; 	} else if (zip->uncompressed_buffer_size < minimum || 	    zip->uncompressed_buffer_bytes_remaining < minimum) {@@ -3534,10 +3575,8 @@ 			 * the minimum size. 			 */ 			void *p;-			size_t new_size;+			size_t new_size = align_size(minimum); -			new_size = minimum + 1023;-			new_size &= ~0x3ff; 			p = realloc(zip->uncompressed_buffer, new_size); 			if (p == NULL) { 				archive_set_error(&a->archive, ENOMEM,@@ -3583,7 +3622,7 @@ 		bytes_out = zip->uncompressed_buffer_size 			- zip->uncompressed_buffer_bytes_remaining; 		bytes_in = bytes_avail;-		if (bytes_in > zip->pack_stream_inbytes_remaining)+		if (bytes_in > (uint64_t)zip->pack_stream_inbytes_remaining) 			bytes_in = (size_t)zip->pack_stream_inbytes_remaining; 		/* Drive decompression. */ 		r = decompress(a, zip, buff_out, &bytes_out,@@ -3599,7 +3638,7 @@ 			return (ARCHIVE_FATAL); 		} 		zip->pack_stream_inbytes_remaining -= bytes_in;-		if (bytes_out > zip->folder_outbytes_remaining)+		if (bytes_out > (uint64_t)zip->folder_outbytes_remaining) 			bytes_out = (size_t)zip->folder_outbytes_remaining; 		zip->folder_outbytes_remaining -= bytes_out; 		zip->uncompressed_buffer_bytes_remaining += bytes_out;@@ -3637,10 +3676,10 @@ static int seek_pack(struct archive_read *a) {-	struct _7zip *zip = (struct _7zip *)a->format->data;+	struct _7zip *zip = a->format->data; 	int64_t pack_offset; -	if (zip->pack_stream_remaining <= 0) {+	if (zip->pack_stream_remaining == 0) { 		archive_set_error(&(a->archive), 		    ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive"); 		return (ARCHIVE_FATAL);@@ -3649,8 +3688,11 @@ 	    zip->si.pi.sizes[zip->pack_stream_index]; 	pack_offset = zip->si.pi.positions[zip->pack_stream_index]; 	if (zip->stream_offset != pack_offset) {-		if (0 > seek_compat(a, pack_offset + zip->seek_base,-		    SEEK_SET, 1)) {+		int64_t target;++		if (archive_ckd_add_i64(&target,+		    zip->seek_base, pack_offset) ||+		    0 > seek_compat(a, target, SEEK_SET, 1)) { 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error"); 			return (ARCHIVE_FATAL); 		}@@ -3665,8 +3707,8 @@ read_stream(struct archive_read *a, const void **buff, size_t size,     size_t minimum) {-	struct _7zip *zip = (struct _7zip *)a->format->data;-	uint64_t skip_bytes = 0;+	struct _7zip *zip = a->format->data;+	int64_t skip_bytes = 0; 	ssize_t r;  	if (zip->uncompressed_buffer_bytes_remaining == 0) {@@ -3737,9 +3779,10 @@ 		return (r);  	/*-	 * Skip the bytes we already has skipped in skip_stream().+	 * Skip the bytes we already have skipped in skip_stream(). 	 */ 	while (1) {+		size_t request; 		ssize_t skipped;  		if (zip->uncompressed_buffer_bytes_remaining == 0) {@@ -3763,8 +3806,12 @@ 		if (!skip_bytes) 			break; -		skipped = get_uncompressed_data(-			a, buff, (size_t)skip_bytes, 0);+		if (skip_bytes > MAX_READ)+			request = MAX_READ;+		else+			request = (size_t)skip_bytes;++		skipped = get_uncompressed_data(a, buff, request, 0); 		if (skipped < 0) 			return (skipped); 		skip_bytes -= skipped;@@ -3779,10 +3826,10 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,     int header) {-	struct _7zip *zip = (struct _7zip *)a->format->data;+	struct _7zip *zip = a->format->data; 	const struct _7z_coder *coder1, *coder2; 	const char *cname = (header)?"archive header":"file content";-	unsigned i;+	size_t i; 	int r, found_bcj2 = 0;  	/*@@ -3840,8 +3887,8 @@ 	/* 	 * Initialize a stream reader. 	 */-	zip->pack_stream_remaining = (unsigned)folder->numPackedStreams;-	zip->pack_stream_index = (unsigned)folder->packIndex;+	zip->pack_stream_remaining = folder->numPackedStreams;+	zip->pack_stream_index = folder->packIndex; 	zip->folder_outbytes_remaining = folder_uncompressed_size(folder); 	zip->uncompressed_buffer_bytes_remaining = 0; 	coder1 = &(folder->coders[0]);@@ -3863,8 +3910,8 @@ 		const void *buff; 		ssize_t bytes; 		unsigned char *b[3] = {NULL, NULL, NULL};-		uint64_t sunpack[3] ={-1, -1, -1};-		uint64_t remaining;+		int64_t sunpack[3] ={-1, -1, -1};+		int64_t remaining; 		size_t s[3] = {0, 0, 0}; 		int idx[3] = {0, 1, 2}; @@ -3917,15 +3964,11 @@ 				} 			} 			coder2 = &(fc[3]);-			zip->main_stream_bytes_remaining =-				(size_t)folder->unPackSize[2]; 			remaining = folder->unPackSize[2]; 		} else if (coder2 != NULL && coder2->codec == _7Z_X86_BCJ2 && 		    zip->pack_stream_remaining == 4 && 		    folder->numInStreams == 5 && folder->numOutStreams == 2) { 			/* Source type 0 made by 7z */-			zip->main_stream_bytes_remaining =-				(size_t)folder->unPackSize[0]; 			remaining = folder->unPackSize[0]; 		} else { 			/* We got an unexpected form. */@@ -3934,13 +3977,6 @@ 			    "Unsupported form of BCJ2 streams"); 			return (ARCHIVE_FATAL); 		}-		if (remaining > SIZE_MAX) {-			archive_set_error(&(a->archive),-			    ARCHIVE_ERRNO_MISC,-			    "7-Zip sub-stream size exceeds "-			    "platform maximum");-			return (ARCHIVE_FATAL);-		} 		zip->main_stream_bytes_remaining = remaining;  @@ -3948,8 +3984,9 @@ 		if ((r = seek_pack(a)) < 0) 			return (r); 		zip->pack_stream_bytes_unconsumed =-		    (size_t)zip->pack_stream_inbytes_remaining;-		read_consume(a);+		    zip->pack_stream_inbytes_remaining;+		if ((r = read_consume(a)) < 0)+			return (r);  		/* Read following three sub streams. */ 		for (i = 0; i < 3; i++) {@@ -3960,7 +3997,7 @@ 				return (r); 			} -			if (sunpack[i] == (uint64_t)-1)+			if (sunpack[i] == -1) 				zip->folder_outbytes_remaining = 				    zip->pack_stream_inbytes_remaining; 			else@@ -3974,7 +4011,7 @@  			/* Allocate memory for the decoded data of a sub 			 * stream. */-			if (zip->folder_outbytes_remaining > SIZE_MAX) {+			if ((uint64_t)zip->folder_outbytes_remaining > SIZE_MAX) { 				free(b[0]); free(b[1]); free(b[2]); 				archive_set_error(&a->archive, 				    ARCHIVE_ERRNO_MISC,@@ -4039,7 +4076,7 @@ 		 * of BCJ2. 		 */ 		zip->pack_stream_remaining = 1;-		zip->pack_stream_index = (unsigned)folder->packIndex;+		zip->pack_stream_index = folder->packIndex; 		zip->folder_outbytes_remaining = 		    folder_uncompressed_size(folder); 		zip->uncompressed_buffer_bytes_remaining = 0;@@ -4054,26 +4091,40 @@ 	return (ARCHIVE_OK); } -static int64_t-skip_stream(struct archive_read *a, size_t skip_bytes)+static int+skip_stream(struct archive_read *a, int64_t skip_bytes) {-	struct _7zip *zip = (struct _7zip *)a->format->data;+	struct _7zip *zip = a->format->data; 	const void *p; 	int64_t skipped_bytes;-	size_t bytes = skip_bytes;+	int64_t bytes = skip_bytes;  	if (zip->folder_index == 0) {+		int64_t *v;+ 		/* 		 * Optimization for a list mode. 		 * Avoid unnecessary decoding operations. 		 */-		zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes-		    += skip_bytes;-		return (skip_bytes);+		v = &zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes;+		if (archive_ckd_add_i64(v, *v, skip_bytes)) {+			archive_set_error(&a->archive,+			    ARCHIVE_ERRNO_FILE_FORMAT,+			    "Too many bytes to skip");+			return (ARCHIVE_FATAL);+		}+		return (ARCHIVE_OK); 	}  	while (bytes) {-		skipped_bytes = read_stream(a, &p, bytes, 0);+		size_t request;++		if (bytes > MAX_READ)+			request = MAX_READ;+		else+			request = (size_t)bytes;++		skipped_bytes = read_stream(a, &p, request, 0); 		if (skipped_bytes < 0) 			return (skipped_bytes); 		if (skipped_bytes == 0) {@@ -4082,11 +4133,11 @@ 			    "Truncated 7-Zip file body"); 			return (ARCHIVE_FATAL); 		}-		bytes -= (size_t)skipped_bytes;+		bytes -= skipped_bytes; 		if (zip->pack_stream_bytes_unconsumed) 			read_consume(a); 	}-	return (skip_bytes);+	return (ARCHIVE_OK); }  /*@@ -4135,7 +4186,7 @@ 		if (p >= limit) 			break; 		prevPosT = bufferPos - prevPosT;-		if (prevPosT > 3)+		if (prevPosT == 0 || prevPosT > 3) 			prevMask = 0; 		else { 			prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;@@ -4439,7 +4490,7 @@ 	const uint8_t *buf0, *buf1, *buf2, *buf3; 	size_t size0, size1, size2, size3; 	const uint8_t *buffer, *bufferLim;-	unsigned int i, j;+	size_t i, j;  	size0 = zip->tmp_stream_bytes_remaining; 	buf0 = zip->tmp_stream_buff + zip->tmp_stream_bytes_avail - size0;@@ -4538,7 +4589,7 @@ 				size2 -= 4; 			} 			dest = archive_be32dec(v) --			    ((uint32_t)zip->bcj2_outPos + (uint32_t)outPos + 4);+			    (zip->bcj2_outPos + outPos + 4); 			archive_le32enc(out, dest); 			zip->bcj2_prevByte = out[3]; @@ -4549,7 +4600,7 @@ 				 * Save odd bytes which we could not add into 				 * the output buffer because of out of space. 				 */-				zip->odd_bcj_size = 4 -i;+				zip->odd_bcj_size = 4 - i; 				for (; i < 4; i++) { 					j = i - 4 + (unsigned)zip->odd_bcj_size; 					zip->odd_bcj[j] = out[i];
c/archive_read_support_format_all.c view
@@ -80,7 +80,7 @@ 	/* Note: We always return ARCHIVE_OK here, even if some of the 	 * above return ARCHIVE_WARN.  The intent here is to enable 	 * "as much as possible."  Clients who need specific-	 * compression should enable those individually so they can+	 * formats should enable those individually so they can 	 * verify the level of support. */ 	/* Clear any warning messages set by the above functions. */ 	archive_clear_error(a);
c/archive_read_support_format_ar.c view
@@ -55,7 +55,7 @@ 	 * but haven't yet marked as consumed.  Must be paired with 	 * entry_bytes_remaining usage/modification. 	 */-	size_t   entry_bytes_unconsumed;+	int64_t  entry_bytes_unconsumed; 	int64_t	 entry_offset; 	int64_t	 entry_padding; 	char	*strtab;@@ -81,18 +81,18 @@ #define AR_fmag_offset 58 #define AR_fmag_size 2 -static int	archive_read_format_ar_bid(struct archive_read *a, int);-static int	archive_read_format_ar_cleanup(struct archive_read *a);-static int	archive_read_format_ar_read_data(struct archive_read *a,-		    const void **buff, size_t *size, int64_t *offset);-static int	archive_read_format_ar_skip(struct archive_read *a);-static int	archive_read_format_ar_read_header(struct archive_read *a,-		    struct archive_entry *e);-static uint64_t	ar_atol8(const char *p, unsigned char_cnt);-static uint64_t	ar_atol10(const char *p, unsigned char_cnt);-static int	ar_parse_gnu_filename_table(struct archive_read *a);-static int	ar_parse_common_header(struct ar *ar, struct archive_entry *,-		    const char *h);+static int	archive_read_format_ar_bid(struct archive_read *, int);+static int	archive_read_format_ar_cleanup(struct archive_read *);+static int	archive_read_format_ar_read_data(struct archive_read *,+		    const void **, size_t *, int64_t *);+static int	archive_read_format_ar_skip(struct archive_read *);+static int	archive_read_format_ar_read_header(struct archive_read *,+		    struct archive_entry *);+static uint64_t	ar_atol8(const char *, size_t);+static uint64_t	ar_atol10(const char *, size_t);+static int	ar_parse_gnu_filename_table(struct archive_read *);+static void	ar_parse_common_header(struct ar *, struct archive_entry *,+		    const char *);  int archive_read_support_format_ar(struct archive *_a)@@ -135,12 +135,12 @@ static int archive_read_format_ar_cleanup(struct archive_read *a) {-	struct ar *ar;+	struct ar *ar = a->format->data; -	ar = (struct ar *)(a->format->data); 	free(ar->strtab); 	free(ar);-	(a->format->data) = NULL;+	a->format->data = NULL;+ 	return (ARCHIVE_OK); } @@ -165,14 +165,12 @@  static int _ar_read_header(struct archive_read *a, struct archive_entry *entry,-	struct ar *ar, const char *h, size_t *unconsumed)+	struct ar *ar, const char *h, int64_t *unconsumed) { 	char filename[AR_name_size + 1]; 	uint64_t number; /* Used to hold parsed numbers before validation. */-	size_t bsd_name_length, entry_size;-	char *p, *st;+	char *p; 	const void *b;-	int r;  	/* Verify the magic signature on the file header. */ 	if (strncmp(h + AR_fmag_offset, "`\n", 2) != 0) {@@ -248,14 +246,20 @@ 	}  	/*+	 * Parse the time, owner, mode, size fields.+	 * This must come before any call to _read_ahead.+	 */+	ar_parse_common_header(ar, entry, h);++	/* 	 * '//' is the GNU filename table. 	 * Later entries can refer to names in this table. 	 */ 	if (strcmp(filename, "//") == 0) {-		/* This must come before any call to _read_ahead. */-		ar_parse_common_header(ar, entry, h);+		char *st;+		size_t entry_size;+ 		archive_entry_copy_pathname(entry, filename);-		archive_entry_set_filetype(entry, AE_IFREG); 		/* Get the size of the filename table. */ 		number = ar_atol10(h + AR_size_offset, AR_size_size); 		if (number > SIZE_MAX || number > 1024 * 1024 * 1024) {@@ -310,22 +314,15 @@ 	 */ 	if (filename[0] == '/' && filename[1] >= '0' && filename[1] <= '9') { 		number = ar_atol10(h + AR_name_offset + 1, AR_name_size - 1);-		/*-		 * If we can't look up the real name, warn and return-		 * the entry with the wrong name.-		 */+		/* Fail if we can't look up the real name. */ 		if (ar->strtab == NULL || number >= ar->strtab_size) { 			archive_set_error(&a->archive, EINVAL, 			    "Can't find long filename for GNU/SVR4 archive entry");-			archive_entry_copy_pathname(entry, filename);-			/* Parse the time, owner, mode, size fields. */-			ar_parse_common_header(ar, entry, h); 			return (ARCHIVE_FATAL); 		}  		archive_entry_copy_pathname(entry, &ar->strtab[(size_t)number]);-		/* Parse the time, owner, mode, size fields. */-		return (ar_parse_common_header(ar, entry, h));+		return (ARCHIVE_OK); 	}  	/*@@ -334,9 +331,7 @@ 	 * the filename to the file contents. 	 */ 	if (strncmp(filename, "#1/", 3) == 0) {-		/* Parse the time, owner, mode, size fields. */-		/* This must occur before _read_ahead is called again. */-		ar_parse_common_header(ar, entry, h);+		size_t bsd_name_length;  		/* Parse the size of the name, adjust the file size. */ 		number = ar_atol10(h + AR_name_offset + 3, AR_name_size - 3);@@ -347,7 +342,7 @@ 		 */ 		if (number > SIZE_MAX - 1 		    || number > 1024 * 1024-		    || (int64_t)number > ar->entry_bytes_remaining) {+		    || number > (uint64_t)ar->entry_bytes_remaining) { 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 			    "Bad input file size"); 			return (ARCHIVE_FATAL);@@ -386,49 +381,33 @@ 	}  	/*-	 * "/" is the SVR4/GNU archive symbol table.-	 * "/SYM64/" is the SVR4/GNU 64-bit variant archive symbol table.-	 */-	if (strcmp(filename, "/") == 0 || strcmp(filename, "/SYM64/") == 0) {-		archive_entry_copy_pathname(entry, filename);-		/* Parse the time, owner, mode, size fields. */-		r = ar_parse_common_header(ar, entry, h);-		/* Force the file type to a regular file. */-		archive_entry_set_filetype(entry, AE_IFREG);-		return (r);-	}--	/*-	 * "__.SYMDEF" is a BSD archive symbol table.-	 */-	if (strcmp(filename, "__.SYMDEF") == 0) {-		archive_entry_copy_pathname(entry, filename);-		/* Parse the time, owner, mode, size fields. */-		return (ar_parse_common_header(ar, entry, h));-	}--	/* 	 * Otherwise, this is a standard entry.  The filename 	 * has already been trimmed as much as possible, based 	 * on our current knowledge of the format.+	 *+	 * Note for future implementations:+	 *+	 * - "/" is the SVR4/GNU archive symbol table.+	 * - "/SYM64/" is the SVR4/GNU 64-bit variant archive symbol table.+	 * - "__.SYMDEF" is a BSD archive symbol table. 	 */ 	archive_entry_copy_pathname(entry, filename);-	return (ar_parse_common_header(ar, entry, h));+	return (ARCHIVE_OK); }  static int archive_read_format_ar_read_header(struct archive_read *a,     struct archive_entry *entry) {-	struct ar *ar = (struct ar*)(a->format->data);-	size_t unconsumed;+	struct ar *ar = a->format->data;+	int64_t unconsumed; 	const void *header_data; 	int ret;  	if (!ar->read_global_header) { 		/*-		 * We are now at the beginning of the archive,-		 * so we need first consume the ar global header.+		 * We are at the beginning of the archive now,+		 * so we have to consume the ar global header first. 		 */ 		__archive_read_consume(a, 8); 		ar->read_global_header = 1;@@ -452,11 +431,11 @@ }  -static int+static void ar_parse_common_header(struct ar *ar, struct archive_entry *entry,     const char *h) {-	uint64_t n;+	int64_t n;  	/* Copy remaining header */ 	archive_entry_set_mtime(entry,@@ -468,24 +447,21 @@ 	archive_entry_set_mode(entry, 	    (mode_t)ar_atol8(h + AR_mode_offset, AR_mode_size)); 	archive_entry_set_filetype(entry, AE_IFREG);-	n = ar_atol10(h + AR_size_offset, AR_size_size);+	n = (int64_t)ar_atol10(h + AR_size_offset, AR_size_size);  	ar->entry_offset = 0; 	ar->entry_padding = n % 2; 	archive_entry_set_size(entry, n); 	ar->entry_bytes_remaining = n;-	return (ARCHIVE_OK); }  static int archive_read_format_ar_read_data(struct archive_read *a,     const void **buff, size_t *size, int64_t *offset) {+	struct ar *ar = a->format->data; 	ssize_t bytes_read;-	struct ar *ar; -	ar = (struct ar *)(a->format->data);- 	if (ar->entry_bytes_unconsumed) { 		__archive_read_consume(a, ar->entry_bytes_unconsumed); 		ar->entry_bytes_unconsumed = 0;@@ -509,17 +485,9 @@ 		ar->entry_bytes_remaining -= bytes_read; 		return (ARCHIVE_OK); 	} else {-		int64_t skipped = __archive_read_consume(a, ar->entry_padding);-		if (skipped >= 0) {-			ar->entry_padding -= skipped;-		}-		if (ar->entry_padding) {-			if (skipped >= 0) {-				archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,-					"Truncated ar archive - failed consuming padding");-			}+		if (__archive_read_consume(a, ar->entry_padding) < 0) 			return (ARCHIVE_FATAL);-		}+		ar->entry_padding = 0; 		*buff = NULL; 		*size = 0; 		*offset = ar->entry_offset;@@ -530,15 +498,11 @@ static int archive_read_format_ar_skip(struct archive_read *a) {-	int64_t bytes_skipped;-	struct ar* ar;--	ar = (struct ar *)(a->format->data);+	struct ar *ar = a->format->data; -	bytes_skipped = __archive_read_consume(a,-	    ar->entry_bytes_remaining + ar->entry_padding-	    + ar->entry_bytes_unconsumed);-	if (bytes_skipped < 0)+	if (__archive_read_consume(a,+	    ar->entry_bytes_remaining + ar->entry_padding ++	    ar->entry_bytes_unconsumed) < 0) 		return (ARCHIVE_FATAL);  	ar->entry_bytes_remaining = 0;@@ -551,11 +515,10 @@ static int ar_parse_gnu_filename_table(struct archive_read *a) {-	struct ar *ar;+	struct ar *ar = a->format->data; 	char *p; 	size_t size; -	ar = (struct ar*)(a->format->data); 	size = ar->strtab_size;  	for (p = ar->strtab; p < ar->strtab + size - 1; ++p) {@@ -587,7 +550,7 @@ }  static uint64_t-ar_atol8(const char *p, unsigned char_cnt)+ar_atol8(const char *p, size_t char_cnt) { 	uint64_t l; 	unsigned int digit, base;@@ -611,7 +574,7 @@ }  static uint64_t-ar_atol10(const char *p, unsigned char_cnt)+ar_atol10(const char *p, size_t char_cnt) { 	uint64_t l; 	unsigned int base, digit;
c/archive_read_support_format_cab.c view
@@ -49,85 +49,186 @@ #include "archive_endian.h"  +/*+ * Huffman coding.+ *+ * Array representation of a Huffman tree for codes of up to 16 bit lengths.+ * Lookups are performed through a direct, expanded lookup table.+ *+ * An expanded table has as many elements as needed to cover all possible+ * indices formable with bit patterns of given lookup_bits length.+ *+ * If less codes exist, these span multiple entries for all possible+ * combinations of following bits.+ *+ * Example of a Huffman tree with len_size = 3, lookup_bits = 2:+ *+ * Symbol | Code+ * -------+-----+ *      A | 0b0+ *      B | 0b10+ *      C | 0b11+ *+ * The bit sequences 0b00 and 0b01 are rightfully not covered by a code,+ * since code 0b0 already maps to symbol A. The table will contain two+ * entries for symbol A instead:+ *+ *  idx | tbl[idx]+ * -----+---------+ * 0b00 |        A+ * 0b01 |        A+ * 0b10 |        B+ * 0b11 |        C+ *+ * By using lookup_bits bits as a lookup, it becomes apparent that 0b00 and+ * 0b01 point to a symbol which actually has the code 0b0. A user of this+ * data structure must check the code bit length of a retrieved symbol after+ * the lookup to properly advance the bit stream:+ *+ * idx | bitlen[idx]+ * ----+------------+ *   A |           1+ *   B |           2+ *   C |           2+ *+ * Thus, a proper code sequence would be:+ *+ * symbol = tbl[read_bits(lookup_bits)]+ * consume_bits(bitlen[symbol])+ */+struct huffman {+	/*+	 * Amount of symbols.+	 *+	 * This implementation keeps track of unused symbols as well,+	 * thus symbols start with 0x0000 up to given symbol amount:+	 * [0..symbol_count)+	 *+	 * Used to construct tbl.+	 */+	uint16_t	 symbol_count;+	/*+	 * Frequency of code bit lengths.+	 *+	 * Represents the amount of occurrences of given bit lengths.+	 * Index 0 is used for "empty" codes (aka unused symbols),+	 * otherwise index represents the bit length+	 * (index 1 is bit length 1 and so on).+	 *+	 * Used to construct tbl.+	 */+	uint16_t	 freq[17];+	/* Map of symbols to their code bit lengths. */+	uint8_t		*bitlen;+	/* Amount of bits to use for lookup (<= tbl_bits). */+	uint8_t		 lookup_bits;+	/*+	 * Code bit length used for allocation (<= 16).+	 *+	 * Used to construct tbl.+	 */+	uint8_t		 tbl_bits;+	/* Direct, expanded lookup table. */+	uint16_t	*tbl;+};++/*+ * Bit stream reader.+ */+struct lzx_br {+#define CACHE_TYPE		uint64_t+#define CACHE_BITS		(8 * sizeof(CACHE_TYPE))+	/* Cache buffer. */+	CACHE_TYPE	 cache_buffer;+	/* Indicates how many bits avail in cache_buffer. */+	size_t		 cache_avail;+	uint8_t		 odd;+	int		 have_odd;+};++struct lzx_pos_tbl {+	uint32_t	 base;+	uint8_t		 footer_bits;+};+ struct lzx_dec { 	/* Decoding status. */ 	int     		 state;+#define ST_RD_TRANSLATION	0+#define ST_RD_TRANSLATION_SIZE	1+#define ST_RD_BLOCK_TYPE	2+#define ST_RD_BLOCK_SIZE	3+#define ST_RD_ALIGNMENT		4+#define ST_RD_R0		5+#define ST_RD_R1		6+#define ST_RD_R2		7+#define ST_COPY_UNCOMP1		8+#define ST_COPY_UNCOMP2		9+#define ST_RD_ALIGNED_OFFSET	10+#define ST_RD_VERBATIM		11+#define ST_RD_PRE_MAIN_TREE_256	12+#define ST_MAIN_TREE_256	13+#define ST_RD_PRE_MAIN_TREE_REM	14+#define ST_MAIN_TREE_REM	15+#define ST_RD_PRE_LENGTH_TREE	16+#define ST_LENGTH_TREE		17+#define ST_MAIN			18+#define ST_LENGTH		19+#define ST_OFFSET		20+#define ST_REAL_POS		21+#define ST_COPY			22  	/*-	 * Window to see last decoded data, from 32KBi to 2MBi.+	 * Window to see last decoded data, from 32 KiB to 2 MiB. 	 */-	int			 w_size;-	int			 w_mask;+	size_t			 w_size;+	size_t			 w_mask; 	/* Window buffer, which is a loop buffer. */-	unsigned char		*w_buff;+	uint8_t			*w_buff; 	/* The insert position to the window. */-	int			 w_pos;+	size_t			 w_pos; 	/* The position where we can copy decoded code from the window. */-	int     		 copy_pos;+	size_t			 copy_pos; 	/* The length how many bytes we can copy decoded code from 	 * the window. */-	int     		 copy_len;+	size_t			 copy_len; 	/* Translation reversal for x86 processor CALL byte sequence(E8). 	 * This is used for LZX only. */-	uint32_t		 translation_size;-	char			 translation;-	char			 block_type;+	int32_t			 translation_size;+	int			 translation;+	uint8_t			 block_type; #define VERBATIM_BLOCK		1 #define ALIGNED_OFFSET_BLOCK	2 #define UNCOMPRESSED_BLOCK	3 	size_t			 block_size; 	size_t			 block_bytes_avail; 	/* Repeated offset. */-	int			 r0, r1, r2;-	unsigned char		 rbytes[4];-	int			 rbytes_avail;-	int			 length_header;-	int			 position_slot;-	int			 offset_bits;+	size_t			 r0, r1, r2;+	uint8_t			 rbytes[4];+	size_t			 rbytes_avail;+	uint8_t			 length_header;+	uint16_t		 position_slot;+	uint8_t			 offset_bits; -	struct lzx_pos_tbl {-		int		 base;-		int		 footer_bits;-	}			*pos_tbl;+	struct lzx_pos_tbl 	*pos_tbl; 	/* 	 * Bit stream reader. 	 */-	struct lzx_br {-#define CACHE_TYPE		uint64_t-#define CACHE_BITS		(8 * sizeof(CACHE_TYPE))-	 	/* Cache buffer. */-		CACHE_TYPE	 cache_buffer;-		/* Indicates how many bits avail in cache_buffer. */-		int		 cache_avail;-		unsigned char	 odd;-		char		 have_odd;-	} br;+	struct lzx_br		 br;  	/* 	 * Huffman coding. 	 */-	struct huffman {-		int		 len_size;-		int		 freq[17];-		unsigned char	*bitlen;--		/*-		 * Use an index table. It's faster than searching a huffman-		 * coding tree, which is a binary tree. But usage of a large-		 * index table causes L1 cache read miss many times.-		 */-		int		 max_bits;-		int		 tbl_bits;-		int		 tree_used;-		/* Direct access table. */-		uint16_t	*tbl;-	}			 at, lt, mt, pt;+	struct huffman		 at;+	struct huffman		 lt;+	struct huffman		 mt;+	struct huffman		 pt; -	int			 loop;+	uint16_t		 loop; 	int			 error; }; -static const int slots[] = {+static const size_t slots[] = { 	30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290 }; #define SLOT_BASE	15@@ -135,11 +236,11 @@  struct lzx_stream { 	const unsigned char	*next_in;-	int64_t			 avail_in;-	int64_t			 total_in;+	size_t			 avail_in;+	size_t			 total_in; 	unsigned char		*next_out;-	int64_t			 avail_out;-	int64_t			 total_out;+	size_t			 avail_out;+	size_t			 total_out; 	struct lzx_dec		*ds; }; @@ -179,6 +280,11 @@ #define CFDATA_cbData		4 #define CFDATA_cbUncomp		6 +/* Limits */+#define MAX_UNCOMPRESS_SIZE	0x8000+#define MAX_FILE_SIZE		(UINT16_MAX * MAX_UNCOMPRESS_SIZE)+#define MAX_E8_TRANSLATION	(0x8000 * MAX_UNCOMPRESS_SIZE)+ static const char * const compression_name[] = { 	"NONE", 	"MSZIP",@@ -240,8 +346,6 @@ };  struct cfheader {-	/* Total bytes of all file size in a Cabinet. */-	uint32_t		 total_bytes; 	uint32_t		 files_offset; 	uint16_t		 folder_count; 	uint16_t		 file_count;@@ -249,7 +353,6 @@ #define PREV_CABINET	0x0001 #define NEXT_CABINET	0x0002 #define RESERVE_PRESENT	0x0004-	uint16_t		 setid; 	uint16_t		 cabinet; 	/* Version number. */ 	unsigned char		 major;@@ -268,8 +371,6 @@ 	int64_t			 entry_offset; 	int64_t			 entry_bytes_remaining; 	int64_t			 entry_unconsumed;-	int64_t			 entry_compressed_bytes_read;-	int64_t			 entry_uncompressed_bytes_read; 	struct cffolder		*entry_cffolder; 	struct cffile		*entry_cffile; 	struct cfdata		*entry_cfdata;@@ -314,7 +415,7 @@ static int	archive_read_format_cab_cleanup(struct archive_read *);  static int	cab_skip_sfx(struct archive_read *);-static time_t	cab_dos_time(const unsigned char *);+static time_t	cab_dos_time(const char *); static int	cab_read_data(struct archive_read *, const void **, 		    size_t *, int64_t *); static int	cab_read_header(struct archive_read *);@@ -335,15 +436,15 @@ static int	lzx_read_blocks(struct lzx_stream *, int); static int	lzx_decode_blocks(struct lzx_stream *, int); static void	lzx_decode_free(struct lzx_stream *);-static void	lzx_translation(struct lzx_stream *, void *, size_t, uint32_t);+static void	lzx_translation(struct lzx_stream *, unsigned char *, size_t, int32_t); static void	lzx_cleanup_bitstream(struct lzx_stream *); static int	lzx_decode(struct lzx_stream *, int); static int	lzx_read_pre_tree(struct lzx_stream *);-static int	lzx_read_bitlen(struct lzx_stream *, struct huffman *, int);-static int	lzx_huffman_init(struct huffman *, size_t, int);+static int	lzx_read_bitlen(struct lzx_stream *, struct huffman *, uint16_t);+static int	lzx_huffman_init(struct huffman *, uint16_t, uint8_t); static void	lzx_huffman_free(struct huffman *); static int	lzx_make_huffman_table(struct huffman *);-static inline int lzx_decode_huffman(struct huffman *, unsigned);+static uint16_t	lzx_decode_huffman(struct huffman *, uint16_t);   int@@ -465,10 +566,9 @@ archive_read_format_cab_options(struct archive_read *a,     const char *key, const char *val) {-	struct cab *cab;+	struct cab *cab = a->format->data; 	int ret = ARCHIVE_FAILED; -	cab = (struct cab *)(a->format->data); 	if (strcmp(key, "hdrcharset")  == 0) { 		if (val == NULL || val[0] == 0) 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,@@ -540,19 +640,21 @@ 	return (ARCHIVE_FATAL); } -static ssize_t-cab_strnlen(const unsigned char *p, size_t maxlen)+#ifdef HAVE_STRNLEN+#define cab_strnlen(a,b) strnlen(a,b)+#else+static size_t+cab_strnlen(const char *p, size_t maxlen) { 	size_t i; -	for (i = 0; i <= maxlen; i++) {+	for (i = 0; i < maxlen; i++) { 		if (p[i] == 0) 			break; 	}-	if (i > maxlen)-		return (-1);/* invalid */-	return ((ssize_t)i);+	return (i); }+#endif  /* Read up to max remaining bytes. */ static const void *@@ -622,11 +724,11 @@ static int cab_read_header(struct archive_read *a) {-	const unsigned char *p;-	struct cab *cab;+	struct cab *cab = a->format->data;+	const char *p; 	struct cfheader *hd;-	size_t bytes, used;-	ssize_t avail, len;+	size_t bytes, len, maxlen, used;+	ssize_t avail; 	int64_t skip; 	int err, i; 	int cur_folder, prev_folder;@@ -639,7 +741,6 @@ 	if ((p = __archive_read_ahead(a, 42, NULL)) == NULL) 		return (truncated_error(a)); -	cab = (struct cab *)(a->format->data); 	if (cab->found_header == 0 && 	    p[0] == 'M' && p[1] == 'Z') { 		/* This is an executable?  Must be self-extracting... */@@ -663,7 +764,6 @@ 		    "Couldn't find out CAB header"); 		return (ARCHIVE_FATAL); 	}-	hd->total_bytes = archive_le32dec(p + CFHEADER_cbCabinet); 	hd->files_offset = archive_le32dec(p + CFHEADER_coffFiles); 	hd->minor = p[CFHEADER_versionMinor]; 	hd->major = p[CFHEADER_versionMajor];@@ -674,7 +774,6 @@ 	if (hd->file_count == 0) 		goto invalid; 	hd->flags = archive_le16dec(p + CFHEADER_flags);-	hd->setid = archive_le16dec(p + CFHEADER_setID); 	hd->cabinet = archive_le16dec(p + CFHEADER_iCabinet); 	used = CFHEADER_iCabinet + 2; 	if (hd->flags & RESERVE_PRESENT) {@@ -693,7 +792,9 @@ 		if ((p = cab_read_ahead_remaining(a, used + 256, 		    &avail)) == NULL || (size_t)avail <= used) 			return (truncated_error(a));-		if ((len = cab_strnlen(p + used, avail - used - 1)) <= 0) {+		maxlen = avail - used;+		len = cab_strnlen(p + used, maxlen);+		if (len == 0 || len == maxlen) { 			goto invalid; 		} 		used += len + 1;@@ -701,7 +802,9 @@ 		if ((p = cab_read_ahead_remaining(a, used + 256, 		    &avail)) == NULL || (size_t)avail <= used) 			return (truncated_error(a));-		if ((len = cab_strnlen(p + used, avail - used - 1)) < 0)+		maxlen = avail - used;+		len = cab_strnlen(p + used, maxlen);+		if (len == maxlen) 			goto invalid; 		used += len + 1; 	}@@ -710,14 +813,18 @@ 		if ((p = cab_read_ahead_remaining(a, used + 256, 		    &avail)) == NULL || (size_t)avail <= used) 			return (truncated_error(a));-		if ((len = cab_strnlen(p + used, avail - used - 1)) <= 0)+		maxlen = avail - used;+		len = cab_strnlen(p + used, maxlen);+		if (len == 0 || len == maxlen) 			goto invalid; 		used += len + 1; 		/* How many bytes are used for szDiskNext. */ 		if ((p = cab_read_ahead_remaining(a, used + 256, 		    &avail)) == NULL || (size_t)avail <= used) 			return (truncated_error(a));-		if ((len = cab_strnlen(p + used, avail - used - 1)) < 0)+		maxlen = avail - used;+		len = cab_strnlen(p + used, maxlen);+		if (len == maxlen) 			goto invalid; 		used += len + 1; 	}@@ -787,7 +894,8 @@ 		return (ARCHIVE_FATAL); 	} 	if (skip) {-		__archive_read_consume(a, skip);+		if (__archive_read_consume(a, skip) < 0)+			return (truncated_error(a)); 		cab->cab_offset += skip; 	} 	/* Allocate memory for CFDATA */@@ -812,7 +920,9 @@ 		cab->cab_offset += 16; 		if ((p = cab_read_ahead_remaining(a, 256, &avail)) == NULL) 			return (truncated_error(a));-		if ((len = cab_strnlen(p, avail-1)) <= 0)+		maxlen = avail;+		len = cab_strnlen(p, maxlen);+		if (len == 0 || len == maxlen) 			goto invalid;  		/* Copy a pathname.  */@@ -824,10 +934,10 @@ 		/* 		 * Sanity check if each data is acceptable. 		 */-		if (file->uncompressed_size > 0x7FFF8000)+		if (file->uncompressed_size > MAX_FILE_SIZE) 			goto invalid;/* Too large */ 		if ((int64_t)file->offset + (int64_t)file->uncompressed_size-		    > ARCHIVE_LITERAL_LL(0x7FFF8000))+		    > (int64_t)MAX_FILE_SIZE) 			goto invalid;/* Too large */ 		switch (file->folder) { 		case iFoldCONTINUED_TO_NEXT:@@ -893,14 +1003,13 @@ archive_read_format_cab_read_header(struct archive_read *a,     struct archive_entry *entry) {-	struct cab *cab;+	struct cab *cab = a->format->data; 	struct cfheader *hd; 	struct cffolder *prev_folder; 	struct cffile *file; 	struct archive_string_conv *sconv; 	int err = ARCHIVE_OK, r;-	-	cab = (struct cab *)(a->format->data);+ 	if (cab->found_header == 0) { 		err = cab_read_header(a);  		if (err < ARCHIVE_WARN)@@ -918,8 +1027,6 @@  	cab->end_of_entry = 0; 	cab->end_of_entry_cleanup = 0;-	cab->entry_compressed_bytes_read = 0;-	cab->entry_uncompressed_bytes_read = 0; 	cab->entry_unconsumed = 0; 	cab->entry_cffile = file; @@ -1017,7 +1124,7 @@ archive_read_format_cab_read_data(struct archive_read *a,     const void **buff, size_t *size, int64_t *offset) {-	struct cab *cab = (struct cab *)(a->format->data);+	struct cab *cab = a->format->data; 	int r;  	switch (cab->entry_cffile->folder) {@@ -1117,7 +1224,7 @@ static void cab_checksum_update(struct archive_read *a, size_t bytes) {-	struct cab *cab = (struct cab *)(a->format->data);+	struct cab *cab = a->format->data; 	struct cfdata *cfdata = cab->entry_cfdata; 	const unsigned char *p; 	size_t sumbytes;@@ -1157,7 +1264,7 @@ static int cab_checksum_finish(struct archive_read *a) {-	struct cab *cab = (struct cab *)(a->format->data);+	struct cab *cab = a->format->data; 	struct cfdata *cfdata = cab->entry_cfdata; 	int l; @@ -1202,7 +1309,7 @@ static int cab_next_cfdata(struct archive_read *a) {-	struct cab *cab = (struct cab *)(a->format->data);+	struct cab *cab = a->format->data; 	struct cfdata *cfdata = cab->entry_cfdata;  	/* There are remaining bytes in current CFDATA, use it first. */@@ -1280,9 +1387,9 @@ 		 * Sanity check if data size is acceptable. 		 */ 		if (cfdata->compressed_size == 0 ||-		    cfdata->compressed_size > (0x8000+6144))+		    cfdata->compressed_size > (MAX_UNCOMPRESS_SIZE + 6144)) 			goto invalid;-		if (cfdata->uncompressed_size > 0x8000)+		if (cfdata->uncompressed_size > MAX_UNCOMPRESS_SIZE) 			goto invalid; 		if (cfdata->uncompressed_size == 0) { 			switch (cab->entry_cffile->folder) {@@ -1295,10 +1402,10 @@ 			} 		} 		/* If CFDATA is not last in a folder, an uncompressed-		 * size must be 0x8000(32KBi) */+		 * size must be 0x8000 (32 KiB) */ 		if ((cab->entry_cffolder->cfdata_index < 		     cab->entry_cffolder->cfdata_count) &&-		       cfdata->uncompressed_size != 0x8000)+		       cfdata->uncompressed_size != MAX_UNCOMPRESS_SIZE) 			goto invalid;  		/* A compressed data size and an uncompressed data size must@@ -1339,10 +1446,6 @@ 	} 	return (ARCHIVE_OK); invalid:-	cfdata->compressed_size = 0;-	cfdata->compressed_bytes_remaining = 0;-	cfdata->uncompressed_size = 0;-	cfdata->uncompressed_bytes_remaining = 0; 	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 	    "Invalid CFDATA"); 	return (ARCHIVE_FATAL);@@ -1354,7 +1457,7 @@ static const void * cab_read_ahead_cfdata(struct archive_read *a, ssize_t *avail) {-	struct cab *cab = (struct cab *)(a->format->data);+	struct cab *cab = a->format->data; 	int err;  	err = cab_next_cfdata(a);@@ -1385,7 +1488,7 @@ static const void * cab_read_ahead_cfdata_none(struct archive_read *a, ssize_t *avail) {-	struct cab *cab = (struct cab *)(a->format->data);+	struct cab *cab = a->format->data; 	struct cfdata *cfdata; 	const void *d; @@ -1417,7 +1520,7 @@ static const void * cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail) {-	struct cab *cab = (struct cab *)(a->format->data);+	struct cab *cab = a->format->data; 	struct cfdata *cfdata; 	const void *d; 	int r, mszip;@@ -1427,7 +1530,7 @@ 	cfdata = cab->entry_cfdata; 	/* If the buffer hasn't been allocated, allocate it now. */ 	if (cab->uncompressed_buffer == NULL) {-		cab->uncompressed_buffer_size = 0x8000;+		cab->uncompressed_buffer_size = MAX_UNCOMPRESS_SIZE; 		cab->uncompressed_buffer 		    = malloc(cab->uncompressed_buffer_size); 		if (cab->uncompressed_buffer == NULL) {@@ -1485,14 +1588,6 @@ 		    cab->uncompressed_buffer + cab->stream.total_out; 		cab->stream.avail_out = 		    cfdata->uncompressed_size - cab->stream.total_out;-		if ((size_t)cfdata->uncompressed_size >-		    cab->uncompressed_buffer_size) {-			archive_set_error(&a->archive,-			    ARCHIVE_ERRNO_FILE_FORMAT,-			    "Invalid CFDATA uncompressed size");-			*avail = ARCHIVE_FATAL;-			return (NULL);-		}  		d = __archive_read_ahead(a, 1, &bytes_avail); 		if (bytes_avail <= 0) {@@ -1653,7 +1748,7 @@ static const void * cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail) {-	struct cab *cab = (struct cab *)(a->format->data);+	struct cab *cab = a->format->data; 	struct cfdata *cfdata; 	const void *d; 	int r;@@ -1662,7 +1757,7 @@ 	cfdata = cab->entry_cfdata; 	/* If the buffer hasn't been allocated, allocate it now. */ 	if (cab->uncompressed_buffer == NULL) {-		cab->uncompressed_buffer_size = 0x8000;+		cab->uncompressed_buffer_size = MAX_UNCOMPRESS_SIZE; 		cab->uncompressed_buffer 		    = malloc(cab->uncompressed_buffer_size); 		if (cab->uncompressed_buffer == NULL) {@@ -1703,13 +1798,6 @@ 		    cab->uncompressed_buffer + cab->xstrm.total_out; 		cab->xstrm.avail_out = 		    cfdata->uncompressed_size - cab->xstrm.total_out;-		-		if ((size_t)cfdata->uncompressed_size > cab->uncompressed_buffer_size) {-			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-				"Invalid CFDATA uncompressed size");-			*avail = ARCHIVE_FATAL;-			return (NULL);-		}  		d = __archive_read_ahead(a, 1, &bytes_avail); 		if (d == NULL) {@@ -1769,7 +1857,7 @@ 	 */ 	lzx_translation(&cab->xstrm, cab->uncompressed_buffer, 	    cfdata->uncompressed_size,-	    (cab->entry_cffolder->cfdata_index-1) * 0x8000);+	    (cab->entry_cffolder->cfdata_index - 1) * MAX_UNCOMPRESS_SIZE);  	d = cab->uncompressed_buffer + cfdata->read_offset; 	*avail = uavail - cfdata->read_offset;@@ -1790,7 +1878,7 @@ static int64_t cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes) {-	struct cab *cab = (struct cab *)(a->format->data);+	struct cab *cab = a->format->data; 	struct cfdata *cfdata; 	int64_t cbytes, rbytes; 	int err;@@ -1883,7 +1971,7 @@ static int64_t cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes) {-	struct cab *cab = (struct cab *)(a->format->data);+	struct cab *cab = a->format->data; 	struct cfdata *cfdata; 	int64_t cbytes, rbytes; 	int err;@@ -1940,7 +2028,7 @@ cab_read_data(struct archive_read *a, const void **buff,     size_t *size, int64_t *offset) {-	struct cab *cab = (struct cab *)(a->format->data);+	struct cab *cab = a->format->data; 	ssize_t bytes_avail;  	if (cab->entry_bytes_remaining == 0) {@@ -1986,12 +2074,10 @@ static int archive_read_format_cab_read_data_skip(struct archive_read *a) {-	struct cab *cab;+	struct cab *cab = a->format->data; 	int64_t bytes_skipped; 	int r; -	cab = (struct cab *)(a->format->data);- 	if (cab->end_of_archive) 		return (ARCHIVE_EOF); @@ -2041,9 +2127,9 @@ static int archive_read_format_cab_cleanup(struct archive_read *a) {-	struct cab *cab = (struct cab *)(a->format->data);+	struct cab *cab = a->format->data; 	struct cfheader *hd = &cab->cfheader;-	int i;+	uint16_t i;  	if (hd->folder_array != NULL) { 		for (i = 0; i < hd->folder_count; i++)@@ -2063,13 +2149,13 @@ 	archive_wstring_free(&cab->ws); 	free(cab->uncompressed_buffer); 	free(cab);-	(a->format->data) = NULL;+	a->format->data = NULL; 	return (ARCHIVE_OK); }  /* Convert an MSDOS-style date/time into Unix-style time. */ static time_t-cab_dos_time(const unsigned char *p)+cab_dos_time(const char *p) { 	int msTime, msDate; 	struct tm ts;@@ -2105,10 +2191,11 @@ static int lzx_decode_init(struct lzx_stream *strm, int w_bits) {-	struct lzx_dec *ds;-	int slot, w_size, w_slot;-	int base, footer; 	int base_inc[18];+	struct lzx_dec *ds;+	uint32_t base;+	uint16_t slot, w_size, w_slot;+	uint8_t footer;  	if (strm->ds == NULL) { 		strm->ds = calloc(1, sizeof(*strm->ds));@@ -2118,7 +2205,7 @@ 	ds = strm->ds; 	ds->error = ARCHIVE_FAILED; -	/* Allow bits from 15(32KBi) up to 21(2MBi) */+	/* Allow bits from 15 (32 KiB) up to 21 (2 MiB) */ 	if (w_bits < SLOT_BASE || w_bits > SLOT_MAX) 		return (ARCHIVE_FAILED); @@ -2130,7 +2217,7 @@ 	w_size = ds->w_size; 	w_slot = slots[w_bits - SLOT_BASE]; 	ds->w_size = 1U << w_bits;-	ds->w_mask = ds->w_size -1;+	ds->w_mask = ds->w_size - 1; 	if (ds->w_buff == NULL || w_size != ds->w_size) { 		free(ds->w_buff); 		ds->w_buff = malloc(ds->w_size);@@ -2152,18 +2239,20 @@ 		else 			base += base_inc[footer]; 		if (footer < 17) {-			footer = -2;+			footer = 0; 			for (n = base; n; n >>= 1) 				footer++;-			if (footer <= 0)+			if (footer <= 2) 				footer = 0;+			else+				footer -= 2; 		} 		ds->pos_tbl[slot].base = base; 		ds->pos_tbl[slot].footer_bits = footer; 	}  	ds->w_pos = 0;-	ds->state = 0;+	ds->state = ST_RD_TRANSLATION; 	ds->br.cache_buffer = 0; 	ds->br.cache_avail = 0; 	ds->r0 = ds->r1 = ds->r2 = 1;@@ -2177,7 +2266,7 @@ 		return (ARCHIVE_FATAL);  	/* Initialize Main tree. */-	if (lzx_huffman_init(&(ds->mt), 256+(w_slot<<3), 16)+	if (lzx_huffman_init(&(ds->mt), 256 + (w_slot << 3), 16) 	    != ARCHIVE_OK) 		return (ARCHIVE_FATAL); @@ -2213,29 +2302,36 @@  * E8 Call Translation reversal.  */ static void-lzx_translation(struct lzx_stream *strm, void *p, size_t size, uint32_t offset)+lzx_translation(struct lzx_stream *strm, unsigned char *buffer, size_t size,+    int32_t offset) { 	struct lzx_dec *ds = strm->ds;-	unsigned char *b, *end;+	unsigned char *p, *end; -	if (!ds->translation || size <= 10)+	if (!ds->translation || offset >= MAX_E8_TRANSLATION || size <= 10) 		return;-	b = p;-	end = b + size - 10;-	while (b < end && (b = memchr(b, 0xE8, end - b)) != NULL) {-		size_t i = b - (unsigned char *)p;-		int32_t cp, displacement, value; -		cp = (int32_t)(offset + (uint32_t)i);-		value = archive_le32dec(&b[1]);-		if (value >= -cp && value < (int32_t)ds->translation_size) {-			if (value >= 0)-				displacement = value - cp;+	p = buffer;+	end = buffer + size - 10;++	while (p < end && (p = memchr(p, 0xE8, end - p)) != NULL) {+		int32_t address, position;++		address = archive_le32dec(p + 1);+		position = offset + (p - buffer);++		if (address >= -position && address < ds->translation_size) {+			uint32_t relative;++			if (address >= 0)+				relative = address - position; 			else-				displacement = value + ds->translation_size;-			archive_le32enc(&b[1], (uint32_t)displacement);+				relative = address + ds->translation_size;++			archive_le32enc(p + 1, relative); 		}-		b += 5;++		p += 5; 	} } @@ -2257,7 +2353,7 @@  *  False : we met that strm->next_in is empty, we have to get following  *          bytes. */ #define lzx_br_read_ahead_0(strm, br, n)	\-	(lzx_br_has((br), (n)) || lzx_br_fillup(strm, br))+	(lzx_br_has((br), (n)) || lzx_br_fillup(strm, br) == ARCHIVE_OK) /*  True  : the cache buffer has some bits as much as we need.  *  False : there are no enough bits in the cache buffer to be used,  *          we have to get following bytes if we could. */@@ -2286,8 +2382,8 @@  * Shift away used bits in the cache data and fill it up with following bits.  * Call this when cache buffer does not have enough bits you need.  *- * Returns 1 if the cache buffer is full.- * Returns 0 if the cache buffer is not full; input buffer is empty.+ * Returns ARCHIVE_OK if the cache buffer is full.+ * Returns ARCHIVE_EOF if the cache buffer is not full; input buffer is empty.  */ static int lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)@@ -2295,7 +2391,7 @@ /*  * x86 processor family can read misaligned data without an access error.  */-	int n = CACHE_BITS - br->cache_avail;+	ssize_t n = CACHE_BITS - br->cache_avail;  	for (;;) { 		switch (n >> 4) {@@ -2313,7 +2409,7 @@ 				strm->next_in += 8; 				strm->avail_in -= 8; 				br->cache_avail += 8 * 8;-				return (1);+				return (ARCHIVE_OK); 			} 			break; 		case 3:@@ -2329,13 +2425,13 @@ 				strm->next_in += 6; 				strm->avail_in -= 6; 				br->cache_avail += 6 * 8;-				return (1);+				return (ARCHIVE_OK); 			} 			break; 		case 0: 			/* We have enough compressed data in 			 * the cache buffer.*/-			return (1);+			return (ARCHIVE_EOF); 		default: 			break; 		}@@ -2347,7 +2443,7 @@ 				strm->avail_in--; 				br->have_odd = 1; 			}-			return (0);+			return (ARCHIVE_EOF); 		} 		br->cache_buffer = 		   (br->cache_buffer << 16) |@@ -2362,7 +2458,7 @@ static void lzx_br_fixup(struct lzx_stream *strm, struct lzx_br *br) {-	int n = CACHE_BITS - br->cache_avail;+	ssize_t n = CACHE_BITS - br->cache_avail;  	if (br->have_odd && n >= 16 && strm->avail_in > 0) { 		br->cache_buffer =@@ -2391,35 +2487,11 @@  * 3. Returns ARCHIVE_FAILED if an error occurred; compressed data  *    is broken or you do not set 'last' flag properly.  */-#define ST_RD_TRANSLATION	0-#define ST_RD_TRANSLATION_SIZE	1-#define ST_RD_BLOCK_TYPE	2-#define ST_RD_BLOCK_SIZE	3-#define ST_RD_ALIGNMENT		4-#define ST_RD_R0		5-#define ST_RD_R1		6-#define ST_RD_R2		7-#define ST_COPY_UNCOMP1		8-#define ST_COPY_UNCOMP2		9-#define ST_RD_ALIGNED_OFFSET	10-#define ST_RD_VERBATIM		11-#define ST_RD_PRE_MAIN_TREE_256	12-#define ST_MAIN_TREE_256	13-#define ST_RD_PRE_MAIN_TREE_REM	14-#define ST_MAIN_TREE_REM	15-#define ST_RD_PRE_LENGTH_TREE	16-#define ST_LENGTH_TREE		17-#define ST_MAIN			18-#define ST_LENGTH		19-#define ST_OFFSET		20-#define ST_REAL_POS		21-#define ST_COPY			22- static int lzx_decode(struct lzx_stream *strm, int last) { 	struct lzx_dec *ds = strm->ds;-	int64_t avail_in;+	size_t avail_in; 	int r;  	if (ds->error)@@ -2431,7 +2503,8 @@ 		if (ds->state < ST_MAIN) 			r = lzx_read_blocks(strm, last); 		else {-			int64_t bytes_written = strm->avail_out;+			size_t bytes_written = strm->avail_out;+ 			r = lzx_decode_blocks(strm, last); 			bytes_written -= strm->avail_out; 			strm->next_out += bytes_written;@@ -2447,7 +2520,8 @@ { 	struct lzx_dec *ds = strm->ds; 	struct lzx_br *br = &(ds->br);-	int i, r;+	int r;+	uint16_t i;  	for (;;) { 		switch (ds->state) {@@ -2463,16 +2537,21 @@ 			/* FALL THROUGH */ 		case ST_RD_TRANSLATION_SIZE: 			if (ds->translation) {+				uint32_t v;+ 				if (!lzx_br_read_ahead(strm, br, 32)) { 					ds->state = ST_RD_TRANSLATION_SIZE; 					if (last) 						goto failed; 					return (ARCHIVE_OK); 				}-				ds->translation_size = lzx_br_bits(br, 16);+				v = lzx_br_bits(br, 16); 				lzx_br_consume(br, 16);-				ds->translation_size <<= 16;-				ds->translation_size |= lzx_br_bits(br, 16);+				v <<= 16;+				v |= lzx_br_bits(br, 16);+				if (v > MAX_FILE_SIZE)+					goto failed;+				ds->translation_size = (int32_t)v; 				lzx_br_consume(br, 16); 			} 			/* FALL THROUGH */@@ -2579,17 +2658,17 @@ 				ds->rbytes_avail = 0; 				if (ds->state == ST_RD_R0) { 					ds->r0 = archive_le32dec(ds->rbytes);-					if (ds->r0 < 0)+					if (ds->r0 > (size_t)INT32_MAX) 						goto failed; 					ds->state = ST_RD_R1; 				} else if (ds->state == ST_RD_R1) { 					ds->r1 = archive_le32dec(ds->rbytes);-					if (ds->r1 < 0)+					if (ds->r1 > (size_t)INT32_MAX) 						goto failed; 					ds->state = ST_RD_R2; 				} else if (ds->state == ST_RD_R2) { 					ds->r2 = archive_le32dec(ds->rbytes);-					if (ds->r2 < 0)+					if (ds->r2 > (size_t)INT32_MAX) 						goto failed; 					/* We've gotten all repeated offsets. */ 					ds->state = ST_COPY_UNCOMP1;@@ -2598,10 +2677,10 @@ 			/* FALL THROUGH */ 		case ST_COPY_UNCOMP1: 			/*-			 * Copy bytes form next_in to next_out directly.+			 * Copy bytes from next_in to next_out directly. 			 */ 			while (ds->block_bytes_avail) {-				int l;+				size_t l;  				if (strm->avail_out <= 0) 					/* Output buffer is empty. */@@ -2612,13 +2691,13 @@ 						goto failed; 					return (ARCHIVE_OK); 				}-				l = (int)ds->block_bytes_avail;+				l = ds->block_bytes_avail; 				if (l > ds->w_size - ds->w_pos) 					l = ds->w_size - ds->w_pos; 				if (l > strm->avail_out)-					l = (int)strm->avail_out;+					l = strm->avail_out; 				if (l > strm->avail_in)-					l = (int)strm->avail_in;+					l = strm->avail_in; 				memcpy(strm->next_out, strm->next_in, l); 				memcpy(&(ds->w_buff[ds->w_pos]), 				    strm->next_in, l);@@ -2652,19 +2731,19 @@ 			/* 			 * Read Aligned offset tree. 			 */-			if (!lzx_br_read_ahead(strm, br, 3 * ds->at.len_size)) {+			if (!lzx_br_read_ahead(strm, br, 3 * ds->at.symbol_count)) { 				ds->state = ST_RD_ALIGNED_OFFSET; 				if (last) 					goto failed; 				return (ARCHIVE_OK); 			} 			memset(ds->at.freq, 0, sizeof(ds->at.freq));-			for (i = 0; i < ds->at.len_size; i++) {+			for (i = 0; i < ds->at.symbol_count; i++) { 				ds->at.bitlen[i] = lzx_br_bits(br, 3); 				ds->at.freq[ds->at.bitlen[i]]++; 				lzx_br_consume(br, 3); 			}-			if (!lzx_make_huffman_table(&ds->at))+			if (lzx_make_huffman_table(&ds->at) < 0) 				goto failed; 			/* FALL THROUGH */ 		case ST_RD_VERBATIM:@@ -2674,13 +2753,13 @@ 			/* 			 * Read Pre-tree for first 256 elements of main tree. 			 */-			if (!lzx_read_pre_tree(strm)) {+			if (lzx_read_pre_tree(strm) < 0) { 				ds->state = ST_RD_PRE_MAIN_TREE_256; 				if (last) 					goto failed; 				return (ARCHIVE_OK); 			}-			if (!lzx_make_huffman_table(&ds->pt))+			if (lzx_make_huffman_table(&ds->pt) < 0) 				goto failed; 			ds->loop = 0; 			/* FALL THROUGH */@@ -2689,27 +2768,26 @@ 			 * Get path lengths of first 256 elements of main tree. 			 */ 			r = lzx_read_bitlen(strm, &ds->mt, 256);-			if (r < 0)-				goto failed;-			else if (!r) {+			if (r == ARCHIVE_EOF) { 				ds->state = ST_MAIN_TREE_256; 				if (last) 					goto failed; 				return (ARCHIVE_OK);-			}+			} else if (r < 0)+				goto failed; 			ds->loop = 0; 			/* FALL THROUGH */ 		case ST_RD_PRE_MAIN_TREE_REM: 			/* 			 * Read Pre-tree for remaining elements of main tree. 			 */-			if (!lzx_read_pre_tree(strm)) {+			if (lzx_read_pre_tree(strm) < 0) { 				ds->state = ST_RD_PRE_MAIN_TREE_REM; 				if (last) 					goto failed; 				return (ARCHIVE_OK); 			}-			if (!lzx_make_huffman_table(&ds->pt))+			if (lzx_make_huffman_table(&ds->pt) < 0) 				goto failed; 			ds->loop = 256; 			/* FALL THROUGH */@@ -2717,30 +2795,29 @@ 			/* 			 * Get path lengths of remaining elements of main tree. 			 */-			r = lzx_read_bitlen(strm, &ds->mt, -1);-			if (r < 0)-				goto failed;-			else if (!r) {+			r = lzx_read_bitlen(strm, &ds->mt, 0);+			if (r == ARCHIVE_EOF) { 				ds->state = ST_MAIN_TREE_REM; 				if (last) 					goto failed; 				return (ARCHIVE_OK);-			}-			if (!lzx_make_huffman_table(&ds->mt))+			} else if (r < 0) 				goto failed;+			if (lzx_make_huffman_table(&ds->mt) < 0)+				goto failed; 			ds->loop = 0; 			/* FALL THROUGH */ 		case ST_RD_PRE_LENGTH_TREE: 			/* 			 * Read Pre-tree for remaining elements of main tree. 			 */-			if (!lzx_read_pre_tree(strm)) {+			if (lzx_read_pre_tree(strm) < 0) { 				ds->state = ST_RD_PRE_LENGTH_TREE; 				if (last) 					goto failed; 				return (ARCHIVE_OK); 			}-			if (!lzx_make_huffman_table(&ds->pt))+			if (lzx_make_huffman_table(&ds->pt) < 0) 				goto failed; 			ds->loop = 0; 			/* FALL THROUGH */@@ -2748,17 +2825,16 @@ 			/* 			 * Get path lengths of remaining elements of main tree. 			 */-			r = lzx_read_bitlen(strm, &ds->lt, -1);-			if (r < 0)-				goto failed;-			else if (!r) {+			r = lzx_read_bitlen(strm, &ds->lt, 0);+			if (r == ARCHIVE_EOF) { 				ds->state = ST_LENGTH_TREE; 				if (last) 					goto failed; 				return (ARCHIVE_OK);-			}-			if (!lzx_make_huffman_table(&ds->lt))+			} else if (r < 0) 				goto failed;+			if (lzx_make_huffman_table(&ds->lt) < 0)+				goto failed; 			ds->state = ST_MAIN; 			return (100); 		}@@ -2776,22 +2852,23 @@ 	const struct lzx_pos_tbl *pos_tbl = ds->pos_tbl; 	unsigned char *noutp = strm->next_out; 	unsigned char *endp = noutp + strm->avail_out;-	unsigned char *w_buff = ds->w_buff;-	unsigned char *at_bitlen = at->bitlen;-	unsigned char *lt_bitlen = lt->bitlen;-	unsigned char *mt_bitlen = mt->bitlen;+	uint8_t *w_buff = ds->w_buff;+	uint8_t *at_bitlen = at->bitlen;+	uint8_t *lt_bitlen = lt->bitlen;+	uint8_t *mt_bitlen = mt->bitlen; 	size_t block_bytes_avail = ds->block_bytes_avail;-	int at_max_bits = at->max_bits;-	int lt_max_bits = lt->max_bits;-	int mt_max_bits = mt->max_bits;-	int c, copy_len = ds->copy_len, copy_pos = ds->copy_pos;-	int w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;-	int length_header = ds->length_header;-	int offset_bits = ds->offset_bits;-	int position_slot = ds->position_slot;-	int r0 = ds->r0, r1 = ds->r1, r2 = ds->r2;+	uint8_t at_lookup_bits = at->lookup_bits;+	uint8_t lt_lookup_bits = lt->lookup_bits;+	uint8_t mt_lookup_bits = mt->lookup_bits;+	size_t copy_len = ds->copy_len, copy_pos = ds->copy_pos;+	size_t w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;+	uint8_t length_header = ds->length_header;+	uint8_t offset_bits = ds->offset_bits;+	uint16_t position_slot = ds->position_slot;+	size_t r0 = ds->r0, r1 = ds->r1, r2 = ds->r2; 	int state = ds->state;-	char block_type = ds->block_type;+	uint16_t c;+	uint8_t block_type = ds->block_type;  	for (;;) { 		switch (state) {@@ -2817,26 +2894,26 @@ 					goto next_data;  				if (!lzx_br_read_ahead(strm, &bre,-				    mt_max_bits)) {+				    mt_lookup_bits)) { 					if (!last) 						goto next_data; 					/* Remaining bits are less than-					 * maximum bits(mt.max_bits) but maybe-					 * it still remains as much as we need,-					 * so we should try to use it with-					 * dummy bits. */+					 * maximum bits (mt.lookup_bits) but+					 * maybe it still remains as much as we+					 * need, so we should try to use it+					 * with dummy bits. */ 					c = lzx_decode_huffman(mt, 					      lzx_br_bits_forced(-				 	        &bre, mt_max_bits));-					lzx_br_consume(&bre, mt_bitlen[c]);-					if (!lzx_br_has(&bre, 0))+					        &bre, mt_lookup_bits));+					if (!lzx_br_has(&bre, mt_bitlen[c])) 						goto failed;/* Over read. */+					lzx_br_consume(&bre, mt_bitlen[c]); 				} else { 					c = lzx_decode_huffman(mt,-					      lzx_br_bits(&bre, mt_max_bits));+					      lzx_br_bits(&bre, mt_lookup_bits)); 					lzx_br_consume(&bre, mt_bitlen[c]); 				}-				if ((unsigned int)c > UCHAR_MAX)+				if (c > UCHAR_MAX) 					break; 				/* 				 * 'c' is exactly literal code.@@ -2862,26 +2939,26 @@ 			 */ 			if (length_header == 7) { 				if (!lzx_br_read_ahead(strm, &bre,-				    lt_max_bits)) {+				    lt_lookup_bits)) { 					if (!last) { 						state = ST_LENGTH; 						goto next_data; 					} 					c = lzx_decode_huffman(lt, 					      lzx_br_bits_forced(-					        &bre, lt_max_bits));-					lzx_br_consume(&bre, lt_bitlen[c]);-					if (!lzx_br_has(&bre, 0))+					        &bre, lt_lookup_bits));+					if (!lzx_br_has(&bre, lt_bitlen[c])) 						goto failed;/* Over read. */+					lzx_br_consume(&bre, lt_bitlen[c]); 				} else { 					c = lzx_decode_huffman(lt,-					    lzx_br_bits(&bre, lt_max_bits));+					    lzx_br_bits(&bre, lt_lookup_bits)); 					lzx_br_consume(&bre, lt_bitlen[c]); 				} 				copy_len = c + 7 + 2; 			} else 				copy_len = length_header + 2;-			if ((size_t)copy_len > block_bytes_avail)+			if (copy_len > block_bytes_avail) 				goto failed; 			/* 			 * Get an offset.@@ -2918,7 +2995,7 @@ 			 */ 			if (block_type == ALIGNED_OFFSET_BLOCK && 			    offset_bits >= 3) {-				int offbits = offset_bits - 3;+				unsigned offbits = offset_bits - 3;  				if (!lzx_br_read_ahead(strm, &bre, offbits)) { 					state = ST_OFFSET;@@ -2930,7 +3007,7 @@  				/* Get an aligned number. */ 				if (!lzx_br_read_ahead(strm, &bre,-				    offbits + at_max_bits)) {+				    offbits + at_lookup_bits)) { 					if (!last) { 						state = ST_OFFSET; 						goto next_data;@@ -2938,14 +3015,14 @@ 					lzx_br_consume(&bre, offbits); 					c = lzx_decode_huffman(at, 					      lzx_br_bits_forced(&bre,-					        at_max_bits));-					lzx_br_consume(&bre, at_bitlen[c]);-					if (!lzx_br_has(&bre, 0))+					        at_lookup_bits));+					if (!lzx_br_has(&bre, at_bitlen[c])) 						goto failed;/* Over read. */+					lzx_br_consume(&bre, at_bitlen[c]); 				} else { 					lzx_br_consume(&bre, offbits); 					c = lzx_decode_huffman(at,-					      lzx_br_bits(&bre, at_max_bits));+					      lzx_br_bits(&bre, at_lookup_bits)); 					lzx_br_consume(&bre, at_bitlen[c]); 				} 				/* Add an aligned number. */@@ -2961,7 +3038,7 @@ 				copy_pos = lzx_br_bits(&bre, offset_bits); 				lzx_br_consume(&bre, offset_bits); 			}-			copy_pos += pos_tbl[position_slot].base -2;+			copy_pos += pos_tbl[position_slot].base - 2;  			/* Update repeated offset LRU queue. */ 			r2 = r1;@@ -2980,8 +3057,8 @@ 			 * into the output buffer. 			 */ 			for (;;) {-				const unsigned char *s;-				int l;+				const uint8_t *s;+				size_t l;  				l = copy_len; 				if (copy_pos > w_pos) {@@ -2992,15 +3069,15 @@ 						l = w_size - w_pos; 				} 				if (noutp + l >= endp)-					l = (int)(endp - noutp);+					l = endp - noutp; 				s = w_buff + copy_pos; 				if (l >= 8 && ((copy_pos + l < w_pos) 				  || (w_pos + l < copy_pos))) { 					memcpy(w_buff + w_pos, s, l); 					memcpy(noutp, s, l); 				} else {-					unsigned char *d;-					int li;+					uint8_t *d;+					size_t li;  					d = w_buff + w_pos; 					for (li = 0; li < l; li++)@@ -3046,122 +3123,124 @@ { 	struct lzx_dec *ds = strm->ds; 	struct lzx_br *br = &(ds->br);-	int i;+	uint16_t i;  	if (ds->loop == 0) 		memset(ds->pt.freq, 0, sizeof(ds->pt.freq));-	for (i = ds->loop; i < ds->pt.len_size; i++) {+	for (i = ds->loop; i < ds->pt.symbol_count; i++) { 		if (!lzx_br_read_ahead(strm, br, 4)) { 			ds->loop = i;-			return (0);+			return (ARCHIVE_EOF); 		} 		ds->pt.bitlen[i] = lzx_br_bits(br, 4); 		ds->pt.freq[ds->pt.bitlen[i]]++; 		lzx_br_consume(br, 4); 	} 	ds->loop = i;-	return (1);+	return (ARCHIVE_OK); }  /*  * Read a bunch of bit-lengths from pre-tree.  */ static int-lzx_read_bitlen(struct lzx_stream *strm, struct huffman *d, int end)+lzx_read_bitlen(struct lzx_stream *strm, struct huffman *d, uint16_t end) { 	struct lzx_dec *ds = strm->ds; 	struct lzx_br *br = &(ds->br);-	int c, i, j, ret, same;-	unsigned rbits;+	int ret;+	uint16_t c, i, j, rbits, same;  	i = ds->loop; 	if (i == 0) 		memset(d->freq, 0, sizeof(d->freq));-	ret = 0;-	if (end < 0)-		end = d->len_size;+	ret = ARCHIVE_EOF;+	if (end == 0)+		end = d->symbol_count; 	while (i < end) { 		ds->loop = i;-		if (!lzx_br_read_ahead(strm, br, ds->pt.max_bits))+		if (!lzx_br_read_ahead(strm, br, (unsigned)ds->pt.lookup_bits)) 			goto getdata;-		rbits = lzx_br_bits(br, ds->pt.max_bits);+		rbits = lzx_br_bits(br, ds->pt.lookup_bits); 		c = lzx_decode_huffman(&(ds->pt), rbits); 		switch (c) { 		case 17:/* several zero lengths, from 4 to 19. */-			if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+4))+			if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c] + 4U)) 				goto getdata; 			lzx_br_consume(br, ds->pt.bitlen[c]); 			same = lzx_br_bits(br, 4) + 4;-			if (i + same > end)-				return (-1);/* Invalid */+			if (same > end - i)+				return (ARCHIVE_FATAL); 			lzx_br_consume(br, 4); 			for (j = 0; j < same; j++) 				d->bitlen[i++] = 0; 			break; 		case 18:/* many zero lengths, from 20 to 51. */-			if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+5))+			if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c] + 5U)) 				goto getdata; 			lzx_br_consume(br, ds->pt.bitlen[c]); 			same = lzx_br_bits(br, 5) + 20;-			if (i + same > end)-				return (-1);/* Invalid */+			if (same > end - i)+				return (ARCHIVE_FATAL); 			lzx_br_consume(br, 5); 			memset(d->bitlen + i, 0, same); 			i += same; 			break; 		case 19:/* a few same lengths. */ 			if (!lzx_br_read_ahead(strm, br,-			    ds->pt.bitlen[c]+1+ds->pt.max_bits))+			    ds->pt.bitlen[c] + 1U + ds->pt.lookup_bits)) 				goto getdata; 			lzx_br_consume(br, ds->pt.bitlen[c]); 			same = lzx_br_bits(br, 1) + 4;-			if (i + same > end)-				return (-1);+			if (same > end - i)+				return (ARCHIVE_FATAL); 			lzx_br_consume(br, 1);-			rbits = lzx_br_bits(br, ds->pt.max_bits);+			rbits = lzx_br_bits(br, ds->pt.lookup_bits); 			c = lzx_decode_huffman(&(ds->pt), rbits); 			lzx_br_consume(br, ds->pt.bitlen[c]);-			c = (d->bitlen[i] - c + 17) % 17;-			if (c < 0)-				return (-1);/* Invalid */+			if (c > d->bitlen[i] + 17)+				return (ARCHIVE_FATAL);+			c = (d->bitlen[i] + 17 - c) % 17; 			for (j = 0; j < same; j++) 				d->bitlen[i++] = c; 			d->freq[c] += same; 			break; 		default: 			lzx_br_consume(br, ds->pt.bitlen[c]);-			c = (d->bitlen[i] - c + 17) % 17;-			if (c < 0)-				return (-1);/* Invalid */+			if (c > d->bitlen[i] + 17)+				return (ARCHIVE_FATAL);+			c = (d->bitlen[i] + 17 - c) % 17; 			d->freq[c]++; 			d->bitlen[i++] = c; 			break; 		} 	}-	ret = 1;+	ret = ARCHIVE_OK; getdata: 	ds->loop = i; 	return (ret); }  static int-lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)+lzx_huffman_init(struct huffman *hf, uint16_t symbol_count, uint8_t tbl_bits) {+	size_t tbl_size = (size_t)1 << tbl_bits; -	if (hf->bitlen == NULL || hf->len_size != (int)len_size) {+	if (hf->bitlen == NULL || hf->symbol_count != symbol_count) { 		free(hf->bitlen);-		hf->bitlen = calloc(len_size,  sizeof(hf->bitlen[0]));+		hf->bitlen = calloc(symbol_count, sizeof(hf->bitlen[0])); 		if (hf->bitlen == NULL) 			return (ARCHIVE_FATAL);-		hf->len_size = (int)len_size;+		hf->symbol_count = symbol_count; 	} else-		memset(hf->bitlen, 0, len_size *  sizeof(hf->bitlen[0]));+		memset(hf->bitlen, 0, symbol_count * sizeof(hf->bitlen[0])); 	if (hf->tbl == NULL) {-		hf->tbl = malloc(((size_t)1 << tbl_bits) * sizeof(hf->tbl[0]));+		hf->tbl = calloc(tbl_size, sizeof(hf->tbl[0])); 		if (hf->tbl == NULL) 			return (ARCHIVE_FATAL); 		hf->tbl_bits = tbl_bits;-	}+	} else+		memset(hf->tbl, 0, tbl_size * sizeof(hf->bitlen[0])); 	return (ARCHIVE_OK); } @@ -3173,19 +3252,47 @@ }  /*- * Make a huffman coding table.+ * Create a direct, expanded Huffman lookup table based on+ * canonical representation.  */ static int lzx_make_huffman_table(struct huffman *hf) {+	uint16_t bitptn[17], weight[17]; 	uint16_t *tbl;-	const unsigned char *bitlen;-	int bitptn[17], weight[17];-	int i, maxbits = 0, ptn, tbl_size, w;-	int len_avail;+	const uint8_t *bitlen;+	uint8_t maxbits = 0;+	uint32_t ptn;+	uint16_t i, symbol_count, w;  	/* 	 * Initialize bit patterns.+	 *+	 * Each bitptn element represents the smallest possible+	 * code sequence allowed. The weight represents the amount+	 * of lookup bit patterns covered by a code of this length.+	 *+	 * Example of a Huffman tree:+	 *+	 * idx | freq[idx]+	 * ----+----------+	 *   1 |         1+	 *   2 |         2+	 *+	 * The result will be:+	 *+	 * idx | bitptn[idx] | weight[idx]+	 * ----+-------------+------------+	 *   1 |      0x0000 |       32768+	 *   2 |      0x8000 |       16384+	 *+	 * This means that a code with bit length 1 will take 32768+	 * possible combinations starting with 0b0. Since one such code exists+	 * (freq[1] = 1), codes with bit length 2 must start with 0b1. Since+	 * two codes with bit length 2 exist (freq[2] = 2), no more codes can+	 * be added.+	 *+	 * In this example, maxbits will be 2 (longest code length is 2). 	 */ 	ptn = 0; 	for (i = 1, w = 1 << 15; i <= 16; i++, w >>= 1) {@@ -3196,65 +3303,108 @@ 			maxbits = i; 		} 	}-	if ((ptn & 0xffff) != 0 || maxbits > hf->tbl_bits)-		return (0);/* Invalid */--	hf->max_bits = maxbits;+	/* Verify Kraft's inequality. */+	if (ptn != 0 && ptn != 0x10000)+		return (ARCHIVE_FATAL);  	/*-	 * Cut out extra bits which we won't house in the table.-	 * This preparation reduces the same calculation in the for-loop-	 * making the table.+	 * Shrink codes to smallest size by removing extra bits after+	 * the actual code sequences as good as possible.+	 *+	 * Continuing the example above:+	 *+	 * idx | bitptn[idx] | weight[idx]+	 * ----+-------------+-------------+	 *   1 |      0x0000 |       32768+	 *   2 |      0x8000 |       16384+	 *+	 * As can be seen, a total of 65536 entries must be created even+	 * though 4 would be sufficient (indices 0b00 to 0b11). Right shift+	 * the pattern and divide weight as much as possible:+	 *+	 * idx | bitptn[idx] | weight[idx]+	 * ----+-------------+-------------+	 *   1 |      0x0000 |           2+	 *   2 |      0x0002 |           1+	 *+	 * Thus, the direct, expanded lookup table only needs 4 entries. 	 */ 	if (maxbits < 16) {-		int ebits = 16 - maxbits;+		uint8_t ebits = 16 - maxbits; 		for (i = 1; i <= maxbits; i++) { 			bitptn[i] >>= ebits; 			weight[i] >>= ebits; 		} 	} +	/* Grow table if necessary. */+	if (maxbits > hf->tbl_bits) {+		size_t tbl_size;++		hf->tbl_bits = 16;+		tbl_size = (size_t)1 << hf->tbl_bits;++		free(hf->tbl);+		hf->tbl = calloc(tbl_size, sizeof(hf->tbl[0]));+		if (hf->tbl == NULL)+			return (ARCHIVE_FATAL);+	}+	hf->lookup_bits = maxbits;+ 	/*-	 * Make the table.+	 * Construct the direct, expanded lookup table.+	 *+	 * Store each symbol in table for every possible bit patterns starting+	 * with their code.+	 *+	 * Following the example with len_avail being 4:+	 *+	 * idx | bitlen[idx]+	 * ----+------------+	 *   0 |           0+	 *   1 |           1+	 *   2 |           0+	 *   3 |           2+	 *   4 |           2+	 *+	 * The resulting table contains all used symbols (1, 3, 4) for up to+	 * max_len bit patterns:+	 *+	 *       idx | tbl[idx]+	 * ----------+---------+	 *  0 (0b00) |        1+	 *  1 (0b01) |        1+	 *  2 (0b10) |        3+	 *  3 (0b11) |        4 	 */-	tbl_size = 1 << hf->tbl_bits; 	tbl = hf->tbl; 	bitlen = hf->bitlen;-	len_avail = hf->len_size;-	hf->tree_used = 0;-	/* Initialize table to invalid values */-	for (i = 0; i < tbl_size; i++) {-		tbl[i] = (uint16_t)hf->len_size;-	}-	for (i = 0; i < len_avail; i++) {+	symbol_count = hf->symbol_count;+	for (i = 0; i < symbol_count; i++) { 		uint16_t *p;-		int len, cnt;+		uint16_t cnt;+		uint8_t len;  		if (bitlen[i] == 0) 			continue; 		/* Get a bit pattern */ 		len = bitlen[i];-		if (len > tbl_size)-			return (0);+		if (len > maxbits)+			return (ARCHIVE_FATAL); 		ptn = bitptn[len]; 		cnt = weight[len]; 		/* Calculate next bit pattern */-		if ((bitptn[len] = ptn + cnt) > tbl_size)-			return (0);/* Invalid */+		bitptn[len] = ptn + cnt; 		/* Update the table */-		p = &(tbl[ptn]);-		while (--cnt >= 0)-			p[cnt] = (uint16_t)i;+		p = tbl + ptn;+		while (cnt-- > 0)+			*p++ = i; 	}-	return (1);+	return (ARCHIVE_OK); } -static inline int-lzx_decode_huffman(struct huffman *hf, unsigned rbits)+static uint16_t+lzx_decode_huffman(struct huffman *hf, uint16_t rbits) {-	int c;-	c = hf->tbl[rbits];-	if (c < hf->len_size)-		return (c);-	return (0);+	return hf->tbl[rbits]; }
c/archive_read_support_format_cpio.c view
@@ -261,14 +261,12 @@ static int archive_read_format_cpio_bid(struct archive_read *a, int best_bid) {+	struct cpio *cpio = a->format->data; 	const unsigned char *p;-	struct cpio *cpio; 	int bid;  	(void)best_bid; /* UNUSED */ -	cpio = (struct cpio *)(a->format->data);- 	if ((p = __archive_read_ahead(a, 6, NULL)) == NULL) 		return (-1); @@ -326,10 +324,9 @@ archive_read_format_cpio_options(struct archive_read *a,     const char *key, const char *val) {-	struct cpio *cpio;+	struct cpio *cpio = a->format->data; 	int ret = ARCHIVE_FAILED; -	cpio = (struct cpio *)(a->format->data); 	if (strcmp(key, "compat-2x")  == 0) { 		/* Handle filenames as libarchive 2.x */ 		cpio->init_default_conversion = (val != NULL)?1:0;@@ -364,14 +361,14 @@ archive_read_format_cpio_read_header(struct archive_read *a,     struct archive_entry *entry) {-	struct cpio *cpio;+	struct cpio *cpio = a->format->data; 	const void *h, *hl; 	struct archive_string_conv *sconv; 	size_t namelength; 	size_t name_pad;+	int is_trailer; 	int r; -	cpio = (struct cpio *)(a->format->data); 	sconv = cpio->opt_sconv; 	if (sconv == NULL) { 		if (!cpio->init_default_conversion) {@@ -411,6 +408,9 @@ 		    archive_string_conversion_charset_name(sconv)); 		r = ARCHIVE_WARN; 	}+	/* Save this before consuming the name buffer below. */+	is_trailer = (namelength == 11 &&+	    memcmp((const char *)h, "TRAILER!!!", 10) == 0); 	cpio->entry_offset = 0;  	__archive_read_consume(a, namelength);@@ -451,8 +451,7 @@ 	 * header.  XXX */  	/* Compare name to "TRAILER!!!" to test for end-of-archive. */-	if (namelength == 11 && strncmp((const char *)h, "TRAILER!!!",-	    10) == 0) {+	if (is_trailer) { 		/* TODO: Store file location of start of block. */ 		archive_clear_error(&a->archive); 		return (ARCHIVE_EOF);@@ -470,11 +469,9 @@ archive_read_format_cpio_read_data(struct archive_read *a,     const void **buff, size_t *size, int64_t *offset) {+	struct cpio *cpio = a->format->data; 	ssize_t bytes_read;-	struct cpio *cpio; -	cpio = (struct cpio *)(a->format->data);- 	if (cpio->entry_bytes_unconsumed) { 		__archive_read_consume(a, cpio->entry_bytes_unconsumed); 		cpio->entry_bytes_unconsumed = 0;@@ -508,7 +505,7 @@ static int archive_read_format_cpio_skip(struct archive_read *a) {-	struct cpio *cpio = (struct cpio *)(a->format->data);+	struct cpio *cpio = a->format->data; 	int64_t to_skip = cpio->entry_bytes_remaining + cpio->entry_padding + 		cpio->entry_bytes_unconsumed; @@ -545,7 +542,8 @@ { 	const void *h; 	const char *p, *q;-	size_t skip, skipped = 0;+	int64_t skip;+	uintmax_t skipped = 0; 	ssize_t bytes;  	for (;;) {@@ -577,9 +575,9 @@ 					if (skipped > 0) { 						archive_set_error(&a->archive, 						    0,-						    "Skipped %d bytes before "+						    "Skipped %ju bytes before " 						    "finding valid header",-						    (int)skipped);+						    skipped); 						return (ARCHIVE_WARN); 					} 					return (ARCHIVE_OK);@@ -1000,9 +998,8 @@ static int archive_read_format_cpio_cleanup(struct archive_read *a) {-	struct cpio *cpio;+	struct cpio *cpio = a->format->data; -	cpio = (struct cpio *)(a->format->data);         /* Free inode->name map */         while (cpio->links_head != NULL) {                 struct links_entry *lp = cpio->links_head->next;@@ -1012,7 +1009,7 @@                 cpio->links_head = lp;         } 	free(cpio);-	(a->format->data) = NULL;+	a->format->data = NULL; 	return (ARCHIVE_OK); } 
c/archive_read_support_format_iso9660.c view
@@ -47,6 +47,7 @@ #include "archive_endian.h" #include "archive_entry.h" #include "archive_entry_locale.h"+#include "archive_integer.h" #include "archive_private.h" #include "archive_read_private.h" #include "archive_string.h"@@ -314,8 +315,8 @@  struct heap_queue { 	struct file_info **files;-	int		 allocated;-	int		 used;+	size_t		 allocated;+	size_t		 used; };  struct iso9660 {@@ -337,8 +338,8 @@ 			uint64_t	 offset;/* Offset of CE on disk. */ 			struct file_info *file; 		}		*reqs;-		int		 cnt;-		int		 allocated;+		size_t		 cnt;+		size_t		 allocated; 	}	read_ce_req;  	int64_t		previous_number;@@ -379,8 +380,6 @@ 	size_t		 utf16be_path_len; 	unsigned char *utf16be_previous_path; 	size_t		 utf16be_previous_path_len;-	/* Null buffer used in bidder to improve its performance. */-	unsigned char	 null[2048]; };  static int	archive_read_format_iso9660_bid(struct archive_read *, int);@@ -403,12 +402,12 @@ static int	isodate17_valid(const unsigned char *); static time_t	isodate7(const unsigned char *); static int	isodate7_valid(const unsigned char *);-static int	isBootRecord(struct iso9660 *, const unsigned char *);+static int	isBootRecord(const unsigned char *); static int	isVolumePartition(struct iso9660 *, const unsigned char *);-static int	isVDSetTerminator(struct iso9660 *, const unsigned char *);+static int	isVDSetTerminator(const unsigned char *); static int	isJolietSVD(struct iso9660 *, const unsigned char *);-static int	isSVD(struct iso9660 *, const unsigned char *);-static int	isEVD(struct iso9660 *, const unsigned char *);+static int	isSVD(const unsigned char *);+static int	isEVD(const unsigned char *); static int	isPVD(struct iso9660 *, const unsigned char *); static int	isRootDirectoryRecord(const unsigned char *); static int	isValid723Integer(const unsigned char *);@@ -503,7 +502,7 @@ static int archive_read_format_iso9660_bid(struct archive_read *a, int best_bid) {-	struct iso9660 *iso9660;+	struct iso9660 *iso9660 = a->format->data; 	ssize_t bytes_read; 	const unsigned char *p; 	int seenTerminator;@@ -513,8 +512,6 @@ 	if (best_bid > 48) 		return (-1); -	iso9660 = (struct iso9660 *)(a->format->data);- 	/* 	 * Skip the first 32k (reserved area) and get the first 	 * 8 sectors of the volume descriptor table.  Of course,@@ -547,15 +544,15 @@ 			if (isJolietSVD(iso9660, p)) 				continue; 		}-		if (isBootRecord(iso9660, p))+		if (isBootRecord(p)) 			continue;-		if (isEVD(iso9660, p))+		if (isEVD(p)) 			continue;-		if (isSVD(iso9660, p))+		if (isSVD(p)) 			continue; 		if (isVolumePartition(iso9660, p)) 			continue;-		if (isVDSetTerminator(iso9660, p)) {+		if (isVDSetTerminator(p)) { 			seenTerminator = 1; 			break; 		}@@ -576,9 +573,7 @@ archive_read_format_iso9660_options(struct archive_read *a, 		const char *key, const char *val) {-	struct iso9660 *iso9660;--	iso9660 = (struct iso9660 *)(a->format->data);+	struct iso9660 *iso9660 = a->format->data;  	if (strcmp(key, "joliet") == 0) { 		if (val == NULL || strcmp(val, "off") == 0 ||@@ -603,26 +598,23 @@ }  static int-isNull(struct iso9660 *iso9660, const unsigned char *h, unsigned offset,-unsigned bytes)+isNull(const unsigned char *h, unsigned offset, unsigned bytes) {--	while (bytes >= sizeof(iso9660->null)) {-		if (!memcmp(iso9660->null, h + offset, sizeof(iso9660->null)))-			return (0);-		offset += sizeof(iso9660->null);-		bytes -= sizeof(iso9660->null);-	}-	if (bytes)-		return memcmp(iso9660->null, h + offset, bytes) == 0;-	else+	if (bytes == 0) 		return (1);++	/*+	 * If the first byte is zero and every byte equals the following+	 * byte, the entire range is zero.+	 */+	return (h[offset] == 0 &&+	    (bytes == 1 ||+	    memcmp(h + offset, h + offset + 1, bytes - 1) == 0)); }  static int-isBootRecord(struct iso9660 *iso9660, const unsigned char *h)+isBootRecord(const unsigned char *h) {-	(void)iso9660; /* UNUSED */  	/* Type of the Volume Descriptor Boot Record must be 0. */ 	if (h[0] != 0)@@ -662,9 +654,8 @@ }  static int-isVDSetTerminator(struct iso9660 *iso9660, const unsigned char *h)+isVDSetTerminator(const unsigned char *h) {-	(void)iso9660; /* UNUSED */  	/* Type of the Volume Descriptor Set Terminator must be 255. */ 	if (h[0] != 255)@@ -675,7 +666,7 @@ 		return (0);  	/* Reserved field must be 0. */-	if (!isNull(iso9660, h, 7, 2048-7))+	if (!isNull(h, 7, 2048-7)) 		return (0);  	return (1);@@ -690,7 +681,7 @@  	/* Check if current sector is a kind of Supplementary Volume 	 * Descriptor. */-	if (!isSVD(iso9660, h))+	if (!isSVD(h)) 		return (0);  	/* FIXME: do more validations according to joliet spec. */@@ -731,25 +722,24 @@ }  static int-isSVD(struct iso9660 *iso9660, const unsigned char *h)+isSVD(const unsigned char *h) { 	const unsigned char *p; 	ssize_t logical_block_size; 	int32_t volume_block; 	int32_t location; -	(void)iso9660; /* UNUSED */  	/* Type 2 means it's a SVD. */ 	if (h[SVD_type_offset] != 2) 		return (0);  	/* Reserved field must be 0. */-	if (!isNull(iso9660, h, SVD_reserved1_offset, SVD_reserved1_size))+	if (!isNull(h, SVD_reserved1_offset, SVD_reserved1_size)) 		return (0);-	if (!isNull(iso9660, h, SVD_reserved2_offset, SVD_reserved2_size))+	if (!isNull(h, SVD_reserved2_offset, SVD_reserved2_size)) 		return (0);-	if (!isNull(iso9660, h, SVD_reserved3_offset, SVD_reserved3_size))+	if (!isNull(h, SVD_reserved3_offset, SVD_reserved3_size)) 		return (0);  	/* File structure version must be 1 for ISO9660/ECMA119. */@@ -791,14 +781,13 @@ }  static int-isEVD(struct iso9660 *iso9660, const unsigned char *h)+isEVD(const unsigned char *h) { 	const unsigned char *p; 	ssize_t logical_block_size; 	int32_t volume_block; 	int32_t location; -	(void)iso9660; /* UNUSED */  	/* Type of the Enhanced Volume Descriptor must be 2. */ 	if (h[PVD_type_offset] != 2)@@ -813,11 +802,11 @@ 		return (0);  	/* Reserved field must be 0. */-	if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))+	if (!isNull(h, PVD_reserved2_offset, PVD_reserved2_size)) 		return (0);  	/* Reserved field must be 0. */-	if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))+	if (!isNull(h, PVD_reserved3_offset, PVD_reserved3_size)) 		return (0);  	/* Logical block size must be > 0. */@@ -853,11 +842,11 @@ 		return (0);  	/* Reserved field must be 0. */-	if (!isNull(iso9660, h, PVD_reserved4_offset, PVD_reserved4_size))+	if (!isNull(h, PVD_reserved4_offset, PVD_reserved4_size)) 		return (0);  	/* Reserved field must be 0. */-	if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))+	if (!isNull(h, PVD_reserved5_offset, PVD_reserved5_size)) 		return (0);  	/* Read Root Directory Record in Volume Descriptor. */@@ -891,7 +880,7 @@ 		return (0);  	/* Reserved field must be 0. */-	if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))+	if (!isNull(h, PVD_reserved2_offset, PVD_reserved2_size)) 		return (0);  	/* Volume space size must be encoded according to 7.3.3 */@@ -903,7 +892,7 @@ 		return (0);  	/* Reserved field must be 0. */-	if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))+	if (!isNull(h, PVD_reserved3_offset, PVD_reserved3_size)) 		return (0);  	/* Volume set size must be encoded according to 7.2.3 */@@ -961,7 +950,7 @@ 			return (0);  	/* Reserved field must be 0. */-	if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))+	if (!isNull(h, PVD_reserved5_offset, PVD_reserved5_size)) 		return (0);  	/* XXX TODO: Check other values for sanity; reject more@@ -1034,12 +1023,11 @@ static int read_children(struct archive_read *a, struct file_info *parent) {-	struct iso9660 *iso9660;+	struct iso9660 *iso9660 = a->format->data; 	const unsigned char *b, *p; 	struct file_info *multi; 	size_t step, skip_size; -	iso9660 = (struct iso9660 *)(a->format->data); 	/* flush any remaining bytes from the last round to ensure 	 * we're positioned */ 	if (iso9660->entry_bytes_unconsumed) {@@ -1086,7 +1074,7 @@ 		p = b; 		b += iso9660->logical_block_size; 		step -= iso9660->logical_block_size;-		for (; *p != 0 && p + DR_name_offset < b && p + *p <= b;+		for (; p < b && b - p > DR_name_offset && *p != 0 && *p <= b - p; 			p += *p) { 			struct file_info *child; @@ -1247,12 +1235,10 @@ archive_read_format_iso9660_read_header(struct archive_read *a,     struct archive_entry *entry) {-	struct iso9660 *iso9660;+	struct iso9660 *iso9660 = a->format->data; 	struct file_info *file; 	int r, rd_r = ARCHIVE_OK; -	iso9660 = (struct iso9660 *)(a->format->data);- 	if (!a->archive.archive_format) { 		a->archive.archive_format = ARCHIVE_FORMAT_ISO9660; 		a->archive.archive_format_name = "ISO9660";@@ -1499,7 +1485,7 @@ zisofs_read_data(struct archive_read *a,     const void **buff, size_t *size, int64_t *offset) {-	struct iso9660 *iso9660;+	struct iso9660 *iso9660 = a->format->data; 	struct zisofs  *zisofs; 	const unsigned char *p; 	size_t avail;@@ -1507,7 +1493,6 @@ 	size_t uncompressed_size; 	int r; -	iso9660 = (struct iso9660 *)(a->format->data); 	zisofs = &iso9660->entry_zisofs;  	p = __archive_read_ahead(a, 1, &bytes_read);@@ -1738,11 +1723,9 @@ archive_read_format_iso9660_read_data(struct archive_read *a,     const void **buff, size_t *size, int64_t *offset) {+	struct iso9660 *iso9660 = a->format->data; 	ssize_t bytes_read;-	struct iso9660 *iso9660; -	iso9660 = (struct iso9660 *)(a->format->data);- 	if (iso9660->entry_bytes_unconsumed) { 		__archive_read_consume(a, iso9660->entry_bytes_unconsumed); 		iso9660->entry_bytes_unconsumed = 0;@@ -1805,10 +1788,9 @@ static int archive_read_format_iso9660_cleanup(struct archive_read *a) {-	struct iso9660 *iso9660;+	struct iso9660 *iso9660 = a->format->data; 	int r = ARCHIVE_OK; -	iso9660 = (struct iso9660 *)(a->format->data); 	release_files(iso9660); 	free(iso9660->read_ce_req.reqs); 	archive_string_free(&iso9660->pathname);@@ -1828,7 +1810,7 @@ 	free(iso9660->utf16be_path); 	free(iso9660->utf16be_previous_path); 	free(iso9660);-	(a->format->data) = NULL;+	a->format->data = NULL; 	return (r); } @@ -1840,7 +1822,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,     const unsigned char *isodirrec, size_t reclen) {-	struct iso9660 *iso9660;+	struct iso9660 *iso9660 = a->format->data; 	struct file_info *file, *filep; 	size_t name_len; 	const unsigned char *rr_start, *rr_end;@@ -1850,8 +1832,6 @@ 	int32_t location; 	int flags; -	iso9660 = (struct iso9660 *)(a->format->data);- 	if (reclen != 0) 		dr_len = (size_t)isodirrec[DR_length_offset]; 	/*@@ -2192,11 +2172,9 @@ parse_rockridge(struct archive_read *a, struct file_info *file,     const unsigned char *p, const unsigned char *end) {-	struct iso9660 *iso9660;+	struct iso9660 *iso9660 = a->format->data; 	int entry_seen = 0; -	iso9660 = (struct iso9660 *)(a->format->data);- 	while (p + 4 <= end  /* Enough space for another entry. */ 	    && p[0] >= 'A' && p[0] <= 'Z' /* Sanity-check 1st char of name. */ 	    && p[1] >= 'A' && p[1] <= 'Z' /* Sanity-check 2nd char of name. */@@ -2366,13 +2344,11 @@ register_CE(struct archive_read *a, int32_t location,     struct file_info *file) {-	struct iso9660 *iso9660;+	struct iso9660 *iso9660 = a->format->data; 	struct read_ce_queue *heap;-	struct read_ce_req *p; 	uint64_t offset, parent_offset;-	int hole, parent;+	size_t hole, parent; -	iso9660 = (struct iso9660 *)(a->format->data); 	offset = ((uint64_t)location) * (uint64_t)iso9660->logical_block_size; 	if (((file->mode & AE_IFMT) == AE_IFREG && 	    offset >= file->offset) ||@@ -2389,14 +2365,13 @@ 	/* Expand our CE list as necessary. */ 	heap = &(iso9660->read_ce_req); 	if (heap->cnt >= heap->allocated) {-		int new_size;+		struct read_ce_req *p;+		size_t new_size;  		if (heap->allocated < 16) 			new_size = 16;-		else-			new_size = heap->allocated * 2;-		/* Overflow might keep us from growing the list. */-		if (new_size <= heap->allocated) {+		else if (archive_ckd_mul_size(&new_size, heap->allocated, 2)) {+			/* Overflow keeps us from growing the list. */ 			archive_set_error(&a->archive, ENOMEM, "Out of memory"); 			return (ARCHIVE_FATAL); 		}@@ -2438,7 +2413,7 @@ next_CE(struct read_ce_queue *heap) { 	uint64_t a_offset, b_offset, c_offset;-	int a, b, c;+	size_t a, b, c; 	struct read_ce_req tmp;  	if (heap->cnt < 1)@@ -2765,7 +2740,7 @@     int data_length) { -	if (data[0] == 0x70 && data[1] == 0x7a && data_length == 12) {+	if (data_length == 12 && data[0] == 0x70 && data[1] == 0x7a) {         /* paged zlib */         file->pz = 1;         file->pz_log2_bs = data[3];@@ -3144,7 +3119,7 @@     struct file_info *file, uint64_t key) { 	uint64_t file_key, parent_key;-	int hole, parent;+	size_t hole, parent;  	/* Reserve 16 bits for possible key collisions (needed for linked items) */ 	/* For ISO files with more than 65535 entries, reordering will still occur */@@ -3154,12 +3129,12 @@ 	/* Expand our pending files list as necessary. */ 	if (heap->used >= heap->allocated) { 		struct file_info **new_pending_files;-		int new_size = heap->allocated * 2;+		size_t new_size;  		if (heap->allocated < 1024) 			new_size = 1024;-		/* Overflow might keep us from growing the list. */-		if (new_size <= heap->allocated) {+		else if (archive_ckd_mul_size(&new_size, heap->allocated, 2)) {+			/* Overflow keeps us from growing the list. */ 			archive_set_error(&a->archive, 			    ENOMEM, "Out of memory"); 			return (ARCHIVE_FATAL);@@ -3186,7 +3161,7 @@ 	 */ 	hole = heap->used++; 	while (hole > 0) {-		parent = (hole - 1)/2;+		parent = (hole - 1) / 2; 		parent_key = heap->files[parent]->key; 		if (file_key >= parent_key) { 			heap->files[hole] = file;@@ -3205,7 +3180,7 @@ heap_get_entry(struct heap_queue *heap) { 	uint64_t a_key, b_key, c_key;-	int a, b, c;+	size_t a, b, c; 	struct file_info *r, *tmp;  	if (heap->used < 1)
c/archive_read_support_format_lha.c view
@@ -390,10 +390,9 @@ archive_read_format_lha_options(struct archive_read *a,     const char *key, const char *val) {-	struct lha *lha;+	struct lha *lha = a->format->data; 	int ret = ARCHIVE_FAILED; -	lha = (struct lha *)(a->format->data); 	if (strcmp(key, "hdrcharset")  == 0) { 		if (val == NULL || val[0] == 0) 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,@@ -472,9 +471,9 @@ archive_read_format_lha_read_header(struct archive_read *a,     struct archive_entry *entry) {+	struct lha *lha = a->format->data; 	struct archive_wstring linkname; 	struct archive_wstring pathname;-	struct lha *lha; 	const unsigned char *p; 	const char *signature; 	int err;@@ -485,7 +484,6 @@ 	if (a->archive.archive_format_name == NULL) 		a->archive.archive_format_name = "lha"; -	lha = (struct lha *)(a->format->data); 	lha->decompress_init = 0; 	lha->end_of_entry = 0; 	lha->end_of_entry_cleanup = 0;@@ -900,7 +898,7 @@ { 	const unsigned char *p; 	size_t extdsize;-	int i, err, err2;+	int err, err2; 	int namelen, padding; 	unsigned char headersum, sum_calculated; @@ -925,10 +923,9 @@ 	if ((p = __archive_read_ahead(a, lha->header_size, NULL)) == NULL) 		return (truncated_error(a)); -	for (i = 0; i < namelen; i++) {-		if (p[i + H1_FILE_NAME_OFFSET] == 0xff)-			goto invalid;/* Invalid filename. */-	}+	if (memchr(p + H1_FILE_NAME_OFFSET, 0xff,+	    (size_t)namelen) != NULL)+		goto invalid; /* Invalid filename. */ 	archive_strncpy(&lha->filename, p + H1_FILE_NAME_OFFSET, namelen); 	lha->crc = archive_le16dec(p + H1_FILE_NAME_OFFSET + namelen); 	lha->setflag |= CRC_IS_SET;@@ -1097,7 +1094,7 @@ 	header_crc = lha_crc16(0, p, H3_FIXED_SIZE); 	__archive_read_consume(a, H3_FIXED_SIZE); -	/* Reject rediculously large header */+	/* Reject ridiculously large header */ 	if (lha->header_size > 65536) { 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 		    "LHa header size too large");@@ -1452,7 +1449,7 @@ static int lha_end_of_entry(struct archive_read *a) {-	struct lha *lha = (struct lha *)(a->format->data);+	struct lha *lha = a->format->data; 	int r = ARCHIVE_EOF;  	if (!lha->end_of_entry_cleanup) {@@ -1473,7 +1470,7 @@ archive_read_format_lha_read_data(struct archive_read *a,     const void **buff, size_t *size, int64_t *offset) {-	struct lha *lha = (struct lha *)(a->format->data);+	struct lha *lha = a->format->data; 	int r;  	if (lha->entry_unconsumed) {@@ -1506,7 +1503,7 @@ lha_read_data_none(struct archive_read *a, const void **buff,     size_t *size, int64_t *offset) {-	struct lha *lha = (struct lha *)(a->format->data);+	struct lha *lha = a->format->data; 	ssize_t bytes_avail;  	if (lha->entry_bytes_remaining == 0) {@@ -1553,7 +1550,7 @@ lha_read_data_lzh(struct archive_read *a, const void **buff,     size_t *size, int64_t *offset) {-	struct lha *lha = (struct lha *)(a->format->data);+	struct lha *lha = a->format->data; 	ssize_t bytes_avail; 	int r; @@ -1643,11 +1640,9 @@ static int archive_read_format_lha_read_data_skip(struct archive_read *a) {-	struct lha *lha;+	struct lha *lha = a->format->data; 	int64_t bytes_skipped; -	lha = (struct lha *)(a->format->data);- 	if (lha->entry_unconsumed) { 		/* Consume as much as the decompressor actually used. */ 		__archive_read_consume(a, lha->entry_unconsumed);@@ -1674,7 +1669,7 @@ static int archive_read_format_lha_cleanup(struct archive_read *a) {-	struct lha *lha = (struct lha *)(a->format->data);+	struct lha *lha = a->format->data;  	lzh_decode_free(&(lha->strm)); 	archive_string_free(&(lha->dirname));@@ -1683,7 +1678,7 @@ 	archive_string_free(&(lha->gname)); 	archive_wstring_free(&(lha->ws)); 	free(lha);-	(a->format->data) = NULL;+	a->format->data = NULL; 	return (ARCHIVE_OK); } 
c/archive_read_support_format_mtree.c view
@@ -141,56 +141,6 @@ static size_t	mtree_strnlen(const char *, size_t); #endif -/*- * There's no standard for TIME_T_MAX/TIME_T_MIN.  So we compute them- * here.  TODO: Move this to configure time, but be careful- * about cross-compile environments.- */-static int64_t-get_time_t_max(void)-{-#if defined(TIME_T_MAX)-	return TIME_T_MAX;-#else-	/* ISO C allows time_t to be a floating-point type,-	   but POSIX requires an integer type.  The following-	   should work on any system that follows the POSIX-	   conventions. */-	if (((time_t)0) < ((time_t)-1)) {-		/* Time_t is unsigned */-		return (~(time_t)0);-	} else {-		/* Time_t is signed. */-		/* Assume it's the same as int64_t or int32_t */-		if (sizeof(time_t) == sizeof(int64_t)) {-			return (time_t)INT64_MAX;-		} else {-			return (time_t)INT32_MAX;-		}-	}-#endif-}--static int64_t-get_time_t_min(void)-{-#if defined(TIME_T_MIN)-	return TIME_T_MIN;-#else-	if (((time_t)0) < ((time_t)-1)) {-		/* Time_t is unsigned */-		return (time_t)0;-	} else {-		/* Time_t is signed. */-		if (sizeof(time_t) == sizeof(int64_t)) {-			return (time_t)INT64_MIN;-		} else {-			return (time_t)INT32_MIN;-		}-	}-#endif-}- #ifdef HAVE_STRNLEN #define mtree_strnlen(a,b) strnlen(a,b) #else@@ -199,12 +149,10 @@ { 	size_t i; -	for (i = 0; i <= maxlen; i++) {+	for (i = 0; i < maxlen; i++) { 		if (p[i] == 0) 			break; 	}-	if (i > maxlen)-		return (-1);/* invalid */ 	return (i); } #endif@@ -213,9 +161,8 @@ archive_read_format_mtree_options(struct archive_read *a,     const char *key, const char *val) {-	struct mtree *mtree;+	struct mtree *mtree = a->format->data; -	mtree = (struct mtree *)(a->format->data); 	if (strcmp(key, "checkfs")  == 0) { 		/* Allows to read information missing from the mtree from the file system */ 		if (val == NULL || val[0] == 0) {@@ -297,11 +244,9 @@ static int cleanup(struct archive_read *a) {-	struct mtree *mtree;+	struct mtree *mtree = a->format->data; 	struct mtree_entry *p, *q; -	mtree = (struct mtree *)(a->format->data);-	 	/* Close any dangling file descriptor before freeing */     if (mtree->fd >= 0) {         close(mtree->fd);@@ -322,7 +267,7 @@  	free(mtree->buff); 	free(mtree);-	(a->format->data) = NULL;+	a->format->data = NULL; 	return (ARCHIVE_OK); } @@ -387,7 +332,7 @@ 	 */ 	while (*nl == 0 && len == *avail && !quit) { 		ssize_t diff = *ravail - *avail;-		size_t nbytes_req = (*ravail+1023) & ~1023U;+		size_t nbytes_req = ((size_t)*ravail + 1023) & ~1023U; 		ssize_t tested;  		/*@@ -876,7 +821,7 @@ 		line = next; 		next = line + strcspn(line, " \t\r\n"); 		eq = strchr(line, '=');-		if (eq > next)+		if (eq == NULL || eq > next) 			len = next - line; 		else 			len = eq - line;@@ -1121,12 +1066,10 @@ static int read_header(struct archive_read *a, struct archive_entry *entry) {-	struct mtree *mtree;+	struct mtree *mtree = a->format->data; 	char *p; 	int r, use_next; -	mtree = (struct mtree *)(a->format->data);- 	if (mtree->fd >= 0) { 		close(mtree->fd); 		mtree->fd = -1;@@ -1781,8 +1724,6 @@ 		} 		if (strcmp(key, "time") == 0) { 			int64_t m;-			int64_t my_time_t_max = get_time_t_max();-			int64_t my_time_t_min = get_time_t_min(); 			long ns = 0;  			*parsed_kws |= MTREE_HAS_MTIME;@@ -1802,10 +1743,10 @@ 				else 					ns = (long)v; 			}-			if (m > my_time_t_max)-				m = my_time_t_max;-			else if (m < my_time_t_min)-				m = my_time_t_min;+			if (m > TIME_MAX)+				m = TIME_MAX;+			else if (m < TIME_MIN)+				m = TIME_MIN; 			archive_entry_set_mtime(entry, (time_t)m, ns); 			return (ARCHIVE_OK); 		}@@ -1892,11 +1833,10 @@ read_data(struct archive_read *a, const void **buff, size_t *size,     int64_t *offset) {+	struct mtree *mtree = a->format->data; 	size_t bytes_to_read; 	ssize_t bytes_read;-	struct mtree *mtree; -	mtree = (struct mtree *)(a->format->data); 	if (mtree->fd < 0) { 		*buff = NULL; 		*offset = 0;@@ -1937,9 +1877,8 @@ static int skip(struct archive_read *a) {-	struct mtree *mtree;+	struct mtree *mtree = a->format->data; -	mtree = (struct mtree *)(a->format->data); 	if (mtree->fd >= 0) { 		close(mtree->fd); 		mtree->fd = -1;
c/archive_read_support_format_rar.c view
@@ -42,6 +42,7 @@ #include "archive_endian.h" #include "archive_entry.h" #include "archive_entry_locale.h"+#include "archive_integer.h" #include "archive_ppmd7_private.h" #include "archive_private.h" #include "archive_read_private.h"@@ -201,8 +202,8 @@ struct huffman_code {   struct huffman_tree_node *tree;-  int numentries;-  int numallocatedentries;+  size_t numentries;+  size_t numallocatedentries;   int minlength;   int maxlength;   int tablesize;@@ -227,8 +228,6 @@ {   uint8_t *staticdata;   uint32_t staticdatalen;-  uint8_t *globalbackup;-  uint32_t globalbackuplen;   uint64_t fingerprint;   uint32_t usagecount;   uint32_t oldfilterlength;@@ -499,7 +498,7 @@ static int rar_br_fillup(struct archive_read *a, struct rar_br *br) {-  struct rar *rar = (struct rar *)(a->format->data);+  struct rar *rar = a->format->data;   int n = CACHE_BITS - br->cache_avail;    for (;;) {@@ -594,7 +593,7 @@ static int rar_br_preparation(struct archive_read *a, struct rar_br *br) {-  struct rar *rar = (struct rar *)(a->format->data);+  struct rar *rar = a->format->data;    if (rar->bytes_remaining > 0) {     br->next_in = rar_read_ahead(a, 1, &(br->avail_in));@@ -709,7 +708,7 @@ ppmd_read(void *p) {   struct archive_read *a = ((IByteIn*)p)->a;-  struct rar *rar = (struct rar *)(a->format->data);+  struct rar *rar = a->format->data;   struct rar_br *br = &(rar->br);   Byte b;   if (!rar_br_read_ahead(a, br, 8))@@ -777,7 +776,7 @@ archive_read_format_rar_has_encrypted_entries(struct archive_read *_a) {   if (_a && _a->format) {-    struct rar * rar = (struct rar *)_a->format->data;+    struct rar *rar = _a->format->data;     if (rar) {       return rar->has_encrypted_entries;     }@@ -877,10 +876,9 @@ archive_read_format_rar_options(struct archive_read *a,     const char *key, const char *val) {-  struct rar *rar;+  struct rar *rar = a->format->data;   int ret = ARCHIVE_FAILED; -  rar = (struct rar *)(a->format->data);   if (strcmp(key, "hdrcharset")  == 0) {     if (val == NULL || val[0] == 0)       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,@@ -907,9 +905,9 @@ archive_read_format_rar_read_header(struct archive_read *a,                                     struct archive_entry *entry) {+  struct rar *rar = a->format->data;   const void *h;   const char *p;-  struct rar *rar;   int64_t skip;   char head_type;   int ret;@@ -920,8 +918,6 @@   if (a->archive.archive_format_name == NULL)     a->archive.archive_format_name = "RAR"; -  rar = (struct rar *)(a->format->data);-   /*    * It should be sufficient to call archive_read_next_header() for    * a reader to determine if an entry is encrypted or not. If the@@ -1100,7 +1096,7 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff,                                   size_t *size, int64_t *offset) {-  struct rar *rar = (struct rar *)(a->format->data);+  struct rar *rar = a->format->data;   int ret;    if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {@@ -1151,12 +1147,10 @@ static int archive_read_format_rar_read_data_skip(struct archive_read *a) {-  struct rar *rar;+  struct rar *rar = a->format->data;   int64_t bytes_skipped;   int ret; -  rar = (struct rar *)(a->format->data);-   if (rar->bytes_unconsumed > 0) {       /* Consume as much as the decompressor actually used. */       __archive_read_consume(a, rar->bytes_unconsumed);@@ -1189,9 +1183,9 @@ archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset,     int whence) {+  struct rar *rar = a->format->data;   int64_t client_offset, ret;   size_t i;-  struct rar *rar = (struct rar *)(a->format->data);    if (rar->compression_method == COMPRESS_METHOD_STORE)   {@@ -1294,6 +1288,12 @@               "Error during seek of RAR file");             return (ARCHIVE_FAILED);           }+          if (rar->cursor == 0)+          {+            archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+              "Invalid RAR seek cursor state");+            return (ARCHIVE_FAILED);+          }           client_offset += rar->dbo[rar->cursor].start_offset -             rar->dbo[rar->cursor-1].end_offset;           continue;@@ -1342,9 +1342,8 @@ static int archive_read_format_rar_cleanup(struct archive_read *a) {-  struct rar *rar;+  struct rar *rar = a->format->data; -  rar = (struct rar *)(a->format->data);   free_codes(a);   clear_filters(&rar->filters);   free(rar->filename);@@ -1354,7 +1353,7 @@   free(rar->lzss.window);   __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context);   free(rar);-  (a->format->data) = NULL;+  a->format->data = NULL;   return (ARCHIVE_OK); } @@ -1362,9 +1361,9 @@ read_header(struct archive_read *a, struct archive_entry *entry,             char head_type) {+  struct rar *rar = a->format->data;   const void *h;   const char *p, *endp;-  struct rar *rar;   struct rar_header rar_header;   struct rar_file_header file_header;   int64_t header_size;@@ -1380,8 +1379,6 @@   char *newptr;   size_t newsize; -  rar = (struct rar *)(a->format->data);-   /* Setup a string conversion object for non-rar-unicode filenames. */   sconv = rar->opt_sconv;   if (sconv == NULL) {@@ -1668,16 +1665,18 @@           return (ARCHIVE_FATAL);       }       fn_sconv = rar->sconv_utf8;-      while ((strp = strchr(filename, '\\')) != NULL)-        *strp = '/';+      strp = filename;+      while ((strp = strchr(strp, '\\')) != NULL)+        *strp++ = '/';       p += filename_size;     }   }   else   {     fn_sconv = sconv;-    while ((strp = strchr(filename, '\\')) != NULL)-      *strp = '/';+    strp = filename;+    while ((strp = strchr(strp, '\\')) != NULL)+      *strp++ = '/';     p += filename_size;   } @@ -1962,12 +1961,11 @@ read_symlink_stored(struct archive_read *a, struct archive_entry *entry,                     struct archive_string_conv *sconv) {+  struct rar *rar = a->format->data;   const void *h;   const char *p;-  struct rar *rar;   int ret = (ARCHIVE_OK); -  rar = (struct rar *)(a->format->data);   if ((uintmax_t)rar->packed_size > SIZE_MAX)   {     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,@@ -2004,10 +2002,9 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size,                  int64_t *offset) {-  struct rar *rar;+  struct rar *rar = a->format->data;   ssize_t bytes_avail; -  rar = (struct rar *)(a->format->data);   if (rar->bytes_remaining == 0 &&     !(rar->main_flags & MHD_VOLUME && rar->file_flags & FHD_SPLIT_AFTER))   {@@ -2052,13 +2049,11 @@   if (looper++ > MAX_COMPRESS_DEPTH)     return (ARCHIVE_FAILED); -  struct rar *rar;+  struct rar *rar = a->format->data;   int64_t start, end;   size_t bs;   int ret = (ARCHIVE_OK), sym, code, lzss_offset, length, i; -  rar = (struct rar *)(a->format->data);-   do {     if (!rar->valid)       return (ARCHIVE_FAILED);@@ -2303,11 +2298,11 @@ static int parse_codes(struct archive_read *a) {+  struct rar *rar = a->format->data;   int i, j, val, n, r;   unsigned char bitlengths[MAX_SYMBOLS], zerocount, ppmd_flags;   unsigned int maxorder;   struct huffman_code precode;-  struct rar *rar = (struct rar *)(a->format->data);   struct rar_br *br = &(rar->br);    free_codes(a);@@ -2589,7 +2584,7 @@ static void free_codes(struct archive_read *a) {-  struct rar *rar = (struct rar *)(a->format->data);+  struct rar *rar = a->format->data;   free(rar->maincode.tree);   free(rar->offsetcode.tree);   free(rar->lowoffsetcode.tree);@@ -2608,10 +2603,10 @@ static int read_next_symbol(struct archive_read *a, struct huffman_code *code) {+  struct rar *rar = a->format->data;   unsigned char bit;   unsigned int bits;   int length, value, node;-  struct rar *rar;   struct rar_br *br;    if (!code->table)@@ -2620,7 +2615,6 @@       return -1;   } -  rar = (struct rar *)(a->format->data);   br = &(rar->br);    /* Look ahead (peek) at bits */@@ -2825,11 +2819,16 @@ {   void *new_tree;   if (code->numallocatedentries == code->numentries) {-    int new_num_entries = 256;-    if (code->numentries > 0) {-        new_num_entries = code->numentries * 2;-    }-    new_tree = realloc(code->tree, new_num_entries * sizeof(*code->tree));+    size_t size, new_num_entries;++    if (code->numentries == 0)+        new_num_entries = 256;+    else if (archive_ckd_mul_size(&new_num_entries, code->numentries, 2)+      || new_num_entries > INT_MAX)+        return -1;+    if (archive_ckd_mul_size(&size, new_num_entries, sizeof(*code->tree)))+        return -1;+    new_tree = realloc(code->tree, size);     if (new_tree == NULL)         return (-1);     code->tree = (struct huffman_tree_node *)new_tree;@@ -2870,7 +2869,7 @@                       "Huffman tree was not created");     return (ARCHIVE_FAILED);   }-  if (node < 0 || node >= code->numentries)+  if (node < 0 || (size_t)node >= code->numentries)   {     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,                       "Invalid location to Huffman tree specified");@@ -2958,9 +2957,9 @@   static const unsigned char shortbits[] =     { 2, 2, 3, 4, 5, 6, 6, 6 }; +  struct rar *rar = a->format->data;   int symbol, offs, len, offsindex, lensymbol, i, offssymbol, lowoffsetsymbol;   unsigned char newfile;-  struct rar *rar = (struct rar *)(a->format->data);   struct rar_br *br = &(rar->br);    if (rar->filters.filterstart < *end)@@ -3148,8 +3147,8 @@ copy_from_lzss_window(struct archive_read *a, uint8_t *buffer,                       int64_t startpos, int length) {+  struct rar *rar = a->format->data;   int windowoffs, firstpart;-  struct rar *rar = (struct rar *)(a->format->data);    windowoffs = lzss_offset_for_position(&rar->lzss, startpos);   firstpart = lzss_size(&rar->lzss) - windowoffs;@@ -3176,8 +3175,8 @@ copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer,                              int64_t startpos, size_t length) {+  struct rar *rar = a->format->data;   int windowoffs, firstpart;-  struct rar *rar = (struct rar *)(a->format->data);    if (length > rar->unp_buffer_size)   {@@ -3233,7 +3232,7 @@ static const void * rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail) {-  struct rar *rar = (struct rar *)(a->format->data);+  struct rar *rar = a->format->data;   const void *h;   int ret; @@ -3270,7 +3269,7 @@ static int parse_filter(struct archive_read *a, const uint8_t *bytes, uint16_t length, uint8_t flags) {-  struct rar *rar = (struct rar *)(a->format->data);+  struct rar *rar = a->format->data;   struct rar_filters *filters = &rar->filters;    struct memory_bit_reader br = { 0 };@@ -3438,7 +3437,7 @@ static int run_filters(struct archive_read *a) {-  struct rar *rar = (struct rar *)(a->format->data);+  struct rar *rar = a->format->data;   struct rar_filters *filters = &rar->filters;   struct rar_filter *filter = filters->stack;   struct rar_filter *f;@@ -3606,7 +3605,6 @@   {     struct rar_program_code *next = prog->next;     free(prog->staticdata);-    free(prog->globalbackup);     free(prog);     prog = next;   }@@ -3659,7 +3657,7 @@ static int read_filter(struct archive_read *a, int64_t *end) {-  struct rar *rar = (struct rar *)(a->format->data);+  struct rar *rar = a->format->data;   uint8_t flags, val, *code;   uint16_t length, i; @@ -3855,7 +3853,7 @@       state.delta[0] = state.lastdelta;       predbyte = ((8 * state.lastbyte + state.weight[0] * state.delta[0] + state.weight[1] * state.delta[1] + state.weight[2] * state.delta[2]) >> 3) & 0xFF;       byte = (predbyte - delta) & 0xFF;-      prederror = delta << 3;+      prederror = delta * 8;       state.error[0] += abs(prederror);       state.error[1] += abs(prederror - state.delta[0]); state.error[2] += abs(prederror + state.delta[0]);       state.error[3] += abs(prederror - state.delta[1]); state.error[4] += abs(prederror + state.delta[1]);@@ -3912,7 +3910,7 @@ static int rar_decode_byte(struct archive_read *a, uint8_t *byte) {-  struct rar *rar = (struct rar *)(a->format->data);+  struct rar *rar = a->format->data;   struct rar_br *br = &(rar->br);   if (!rar_br_read_ahead(a, br, 8))     return 0;
c/archive_read_support_format_rar5.c view
@@ -44,4443 +44,4457 @@  #include "archive_entry.h" #include "archive_entry_locale.h"-#include "archive_ppmd7_private.h"-#include "archive_entry_private.h"-#include "archive_time_private.h"--#ifdef HAVE_BLAKE2_H-#include <blake2.h>-#else-#include "archive_blake2.h"-#endif--/*#define CHECK_CRC_ON_SOLID_SKIP*/-/*#define DONT_FAIL_ON_CRC_ERROR*/-/*#define DEBUG*/--#define rar5_min(a, b) (((a) > (b)) ? (b) : (a))-#define rar5_max(a, b) (((a) > (b)) ? (a) : (b))-#define rar5_countof(X) ((const ssize_t) (sizeof(X) / sizeof(*X)))--#if defined DEBUG-#define DEBUG_CODE if(1)-#define LOG(...) do { printf("rar5: " __VA_ARGS__); puts(""); } while(0)-#else-#define DEBUG_CODE if(0)-#endif--/* Real RAR5 magic number is:- *- * 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00- * "Rar!→•☺·\x00"- *- * Retrieved with `rar5_signature()` by XOR'ing it with 0xA1, because I don't- * want to put this magic sequence in each binary that uses libarchive, so- * applications that scan through the file for this marker won't trigger on- * this "false" one.- *- * The array itself is decrypted in `rar5_init` function. */--static const unsigned char rar5_signature_xor[] = {-	243, 192, 211, 128, 187, 166, 160, 161-};-static const size_t g_unpack_window_size = 0x20000;--/* These could have been static const's, but they aren't, because of- * Visual Studio. */-#define MAX_NAME_IN_CHARS 2048-#define MAX_NAME_IN_BYTES (4 * MAX_NAME_IN_CHARS)--struct file_header {-	ssize_t bytes_remaining;-	ssize_t unpacked_size;-	int64_t last_offset;         /* Used in sanity checks. */-	int64_t last_size;           /* Used in sanity checks. */--	uint8_t solid : 1;           /* Is this a solid stream? */-	uint8_t service : 1;         /* Is this file a service data? */-	uint8_t eof : 1;             /* Did we finish unpacking the file? */-	uint8_t dir : 1;             /* Is this file entry a directory? */--	/* Optional time fields. */-	int64_t e_mtime;-	int64_t e_ctime;-	int64_t e_atime;-	uint32_t e_mtime_ns;-	uint32_t e_ctime_ns;-	uint32_t e_atime_ns;--	/* Optional hash fields. */-	uint32_t stored_crc32;-	uint32_t calculated_crc32;-	uint8_t blake2sp[32];-	blake2sp_state b2state;-	char has_blake2;--	/* Optional redir fields */-	uint64_t redir_type;-	uint64_t redir_flags;--	ssize_t solid_window_size; /* Used in file format check. */-};--enum EXTRA {-	EX_CRYPT = 0x01,-	EX_HASH = 0x02,-	EX_HTIME = 0x03,-	EX_VERSION = 0x04,-	EX_REDIR = 0x05,-	EX_UOWNER = 0x06,-	EX_SUBDATA = 0x07-};--#define REDIR_SYMLINK_IS_DIR	1--enum REDIR_TYPE {-	REDIR_TYPE_NONE = 0,-	REDIR_TYPE_UNIXSYMLINK = 1,-	REDIR_TYPE_WINSYMLINK = 2,-	REDIR_TYPE_JUNCTION = 3,-	REDIR_TYPE_HARDLINK = 4,-	REDIR_TYPE_FILECOPY = 5,-};--#define	OWNER_USER_NAME		0x01-#define	OWNER_GROUP_NAME	0x02-#define	OWNER_USER_UID		0x04-#define	OWNER_GROUP_GID		0x08-#define	OWNER_MAXNAMELEN	256--enum FILTER_TYPE {-	FILTER_DELTA = 0,   /* Generic pattern. */-	FILTER_E8    = 1,   /* Intel x86 code. */-	FILTER_E8E9  = 2,   /* Intel x86 code. */-	FILTER_ARM   = 3,   /* ARM code. */-	FILTER_AUDIO = 4,   /* Audio filter, not used in RARv5. */-	FILTER_RGB   = 5,   /* Color palette, not used in RARv5. */-	FILTER_ITANIUM = 6, /* Intel's Itanium, not used in RARv5. */-	FILTER_PPM   = 7,   /* Predictive pattern matching, not used in-			       RARv5. */-	FILTER_NONE  = 8,-};--struct filter_info {-	int type;-	int channels;-	int pos_r;--	int64_t block_start;-	ssize_t block_length;-	uint16_t width;-};--struct data_ready {-	char used;-	const uint8_t* buf;-	size_t size;-	int64_t offset;-};--struct cdeque {-	uint16_t beg_pos;-	uint16_t end_pos;-	uint16_t cap_mask;-	uint16_t size;-	size_t* arr;-};--struct decode_table {-	uint32_t size;-	int32_t decode_len[16];-	uint32_t decode_pos[16];-	uint32_t quick_bits;-	uint8_t quick_len[1 << 10];-	uint16_t quick_num[1 << 10];-	uint16_t decode_num[306];-};--struct comp_state {-	/* Flag used to specify if unpacker needs to reinitialize the-	   uncompression context. */-	uint8_t initialized : 1;--	/* Flag used when applying filters. */-	uint8_t all_filters_applied : 1;--	/* Flag used to skip file context reinitialization, used when unpacker-	   is skipping through different multivolume archives. */-	uint8_t switch_multivolume : 1;--	/* Flag used to specify if unpacker has processed the whole data block-	   or just a part of it. */-	uint8_t block_parsing_finished : 1;--	/* Flag used to indicate that a previous file using this buffer was-	   encrypted, meaning no data in the buffer can be trusted */-	uint8_t data_encrypted : 1;--	signed int notused : 3;--	int flags;                   /* Uncompression flags. */-	int method;                  /* Uncompression algorithm method. */-	int version;                 /* Uncompression algorithm version. */-	ssize_t window_size;         /* Size of window_buf. */-	uint8_t* window_buf;         /* Circular buffer used during-	                                decompression. */-	uint8_t* filtered_buf;       /* Buffer used when applying filters. */-	const uint8_t* block_buf;    /* Buffer used when merging blocks. */-	ssize_t window_mask;         /* Convenience field; window_size - 1. */-	int64_t write_ptr;           /* This amount of data has been unpacked-					in the window buffer. */-	int64_t last_write_ptr;      /* This amount of data has been stored in-	                                the output file. */-	int64_t last_unstore_ptr;    /* Counter of bytes extracted during-	                                unstoring. This is separate from-	                                last_write_ptr because of how SERVICE-	                                base blocks are handled during skipping-	                                in solid multiarchive archives. */-	int64_t solid_offset;        /* Additional offset inside the window-	                                buffer, used in unpacking solid-	                                archives. */-	ssize_t cur_block_size;      /* Size of current data block. */-	int last_len;                /* Flag used in lzss decompression. */--	/* Decode tables used during lzss uncompression. */--#define HUFF_BC 20-	struct decode_table bd;      /* huffman bit lengths */-#define HUFF_NC 306-	struct decode_table ld;      /* literals */-#define HUFF_DC 64-	struct decode_table dd;      /* distances */-#define HUFF_LDC 16-	struct decode_table ldd;     /* lower bits of distances */-#define HUFF_RC 44-	struct decode_table rd;      /* repeating distances */-#define HUFF_TABLE_SIZE (HUFF_NC + HUFF_DC + HUFF_RC + HUFF_LDC)--	/* Circular deque for storing filters. */-	struct cdeque filters;-	int64_t last_block_start;    /* Used for sanity checking. */-	ssize_t last_block_length;   /* Used for sanity checking. */--	/* Distance cache used during lzss uncompression. */-	int dist_cache[4];--	/* Data buffer stack. */-	struct data_ready dready[2];-};--/* Bit reader state. */-struct bit_reader {-	int8_t bit_addr;    /* Current bit pointer inside current byte. */-	int in_addr;        /* Current byte pointer. */-};--/* RARv5 block header structure. Use bf_* functions to get values from- * block_flags_u8 field. I.e. bf_byte_count, etc. */-struct compressed_block_header {-	/* block_flags_u8 contain fields encoded in little-endian bitfield:-	 *-	 * - table present flag (shr 7, and 1),-	 * - last block flag    (shr 6, and 1),-	 * - byte_count         (shr 3, and 7),-	 * - bit_size           (shr 0, and 7).-	 */-	uint8_t block_flags_u8;-	uint8_t block_cksum;-};--/* RARv5 main header structure. */-struct main_header {-	/* Does the archive contain solid streams? */-	uint8_t solid : 1;--	/* If this a multi-file archive? */-	uint8_t volume : 1;-	uint8_t endarc : 1;-	uint8_t notused : 5;--	unsigned int vol_no;-};--struct generic_header {-	uint8_t split_after : 1;-	uint8_t split_before : 1;-	uint8_t padding : 6;-	int size;-	int last_header_id;-};--struct multivolume {-	unsigned int expected_vol_no;-	uint8_t* push_buf;-};--/* Main context structure. */-struct rar5 {-	int header_initialized;--	/* Set to 1 if current file is positioned AFTER the magic value-	 * of the archive file. This is used in header reading functions. */-	int skipped_magic;--	/* Set to not zero if we're in skip mode (either by calling-	 * rar5_data_skip function or when skipping over solid streams).-	 * Set to 0 when in * extraction mode. This is used during checksum-	 * calculation functions. */-	int skip_mode;--	/* Set to not zero if we're in block merging mode (i.e. when switching-	 * to another file in multivolume archive, last block from 1st archive-	 * needs to be merged with 1st block from 2nd archive). This flag-	 * guards against recursive use of the merging function, which doesn't-	 * support recursive calls. */-	int merge_mode;--	/* An offset to QuickOpen list. This is not supported by this unpacker,-	 * because we're focusing on streaming interface. QuickOpen is designed-	 * to make things quicker for non-stream interfaces, so it's not our-	 * use case. */-	uint64_t qlist_offset;--	/* An offset to additional Recovery data. This is not supported by this-	 * unpacker. Recovery data are additional Reed-Solomon codes that could-	 * be used to calculate bytes that are missing in archive or are-	 * corrupted. */-	uint64_t rr_offset;--	/* Various context variables grouped to different structures. */-	struct generic_header generic;-	struct main_header main;-	struct comp_state cstate;-	struct file_header file;-	struct bit_reader bits;-	struct multivolume vol;--	/* The header of currently processed RARv5 block. Used in main-	 * decompression logic loop. */-	struct compressed_block_header last_block_hdr;--	/*-	 * Custom field to denote that this archive contains encrypted entries-	 */-	int has_encrypted_entries;-	int headers_are_encrypted;-};--/* Forward function declarations. */--static void rar5_signature(char *buf);-static int verify_global_checksums(struct archive_read* a);-static int rar5_read_data_skip(struct archive_read *a);-static int push_data_ready(struct archive_read* a, struct rar5* rar,-	const uint8_t* buf, size_t size, int64_t offset);-static void clear_data_ready_stack(struct rar5* rar);-static void rar5_deinit(struct rar5* rar);--/* CDE_xxx = Circular Double Ended (Queue) return values. */-enum CDE_RETURN_VALUES {-	CDE_OK, CDE_ALLOC, CDE_PARAM, CDE_OUT_OF_BOUNDS,-};--/* Clears the contents of this circular deque. */-static void cdeque_clear(struct cdeque* d) {-	d->size = 0;-	d->beg_pos = 0;-	d->end_pos = 0;-}--/* Creates a new circular deque object. Capacity must be power of 2: 8, 16, 32,- * 64, 256, etc. When the user will add another item above current capacity,- * the circular deque will overwrite the oldest entry. */-static int cdeque_init(struct cdeque* d, int max_capacity_power_of_2) {-	if(d == NULL || max_capacity_power_of_2 == 0)-		return CDE_PARAM;--	d->cap_mask = max_capacity_power_of_2 - 1;-	d->arr = NULL;--	if((max_capacity_power_of_2 & d->cap_mask) != 0)-		return CDE_PARAM;--	cdeque_clear(d);-	d->arr = malloc(sizeof(void*) * max_capacity_power_of_2);--	return d->arr ? CDE_OK : CDE_ALLOC;-}--/* Return the current size (not capacity) of circular deque `d`. */-static size_t cdeque_size(struct cdeque* d) {-	return d->size;-}--/* Returns the first element of current circular deque. Note that this function- * doesn't perform any bounds checking. If you need bounds checking, use- * `cdeque_front()` function instead. */-static void cdeque_front_fast(struct cdeque* d, void** value) {-	*value = (void*) d->arr[d->beg_pos];-}--/* Returns the first element of current circular deque. This function- * performs bounds checking. */-static int cdeque_front(struct cdeque* d, void** value) {-	if(d->size > 0) {-		cdeque_front_fast(d, value);-		return CDE_OK;-	} else-		return CDE_OUT_OF_BOUNDS;-}--/* Pushes a new element into the end of this circular deque object. */-static int cdeque_push_back(struct cdeque* d, void* item) {-	if(d == NULL)-		return CDE_PARAM;--	if(d->size == d->cap_mask + 1)-		return CDE_OUT_OF_BOUNDS;--	d->arr[d->end_pos] = (size_t) item;-	d->end_pos = (d->end_pos + 1) & d->cap_mask;-	d->size++;--	return CDE_OK;-}--/* Pops a front element of this circular deque object and returns its value.- * This function doesn't perform any bounds checking. */-static void cdeque_pop_front_fast(struct cdeque* d, void** value) {-	*value = (void*) d->arr[d->beg_pos];-	d->beg_pos = (d->beg_pos + 1) & d->cap_mask;-	d->size--;-}--/* Pops a front element of this circular deque object and returns its value.- * This function performs bounds checking. */-static int cdeque_pop_front(struct cdeque* d, void** value) {-	if(!d || !value)-		return CDE_PARAM;--	if(d->size == 0)-		return CDE_OUT_OF_BOUNDS;--	cdeque_pop_front_fast(d, value);-	return CDE_OK;-}--/* Convenience function to cast filter_info** to void **. */-static void** cdeque_filter_p(struct filter_info** f) {-	return (void**) (size_t) f;-}--/* Convenience function to cast filter_info* to void *. */-static void* cdeque_filter(struct filter_info* f) {-	return (void**) (size_t) f;-}--/* Destroys this circular deque object. Deallocates the memory of the- * collection buffer, but doesn't deallocate the memory of any pointer passed- * to this deque as a value. */-static void cdeque_free(struct cdeque* d) {-	if(!d)-		return;--	if(!d->arr)-		return;--	free(d->arr);--	d->arr = NULL;-	d->beg_pos = -1;-	d->end_pos = -1;-	d->cap_mask = 0;-}--static inline-uint8_t bf_bit_size(const struct compressed_block_header* hdr) {-	return hdr->block_flags_u8 & 7;-}--static inline-uint8_t bf_byte_count(const struct compressed_block_header* hdr) {-	return (hdr->block_flags_u8 >> 3) & 7;-}--static inline-uint8_t bf_is_table_present(const struct compressed_block_header* hdr) {-	return (hdr->block_flags_u8 >> 7) & 1;-}--static inline-uint8_t bf_is_last_block(const struct compressed_block_header* hdr) {-	return (hdr->block_flags_u8 >> 6) & 1;-}--static inline struct rar5* get_context(struct archive_read* a) {-	return (struct rar5*) a->format->data;-}--/* Convenience functions used by filter implementations. */-static void circular_memcpy(uint8_t* dst, uint8_t* window, const ssize_t mask,-    int64_t start, int64_t end)-{-	if((start & mask) > (end & mask)) {-		ssize_t len1 = mask + 1 - (start & mask);-		ssize_t len2 = end & mask;--		memcpy(dst, &window[start & mask], len1);-		memcpy(dst + len1, window, len2);-	} else {-		memcpy(dst, &window[start & mask], (size_t) (end - start));-	}-}--static uint32_t read_filter_data(struct rar5* rar, uint32_t offset) {-	uint8_t linear_buf[4];-	circular_memcpy(linear_buf, rar->cstate.window_buf,-	    rar->cstate.window_mask, offset, offset + 4);-	return archive_le32dec(linear_buf);-}--static void write_filter_data(struct rar5* rar, uint32_t offset,-    uint32_t value)-{-	archive_le32enc(&rar->cstate.filtered_buf[offset], value);-}--/* Allocates a new filter descriptor and adds it to the filter array. */-static struct filter_info* add_new_filter(struct rar5* rar) {-	struct filter_info* f = calloc(1, sizeof(*f));--	if(!f) {-		return NULL;-	}--	if (CDE_OK != cdeque_push_back(&rar->cstate.filters, cdeque_filter(f))) {-		free(f);-		return NULL;-	}--	return f;-}--static int run_delta_filter(struct rar5* rar, struct filter_info* flt) {-	int i;-	ssize_t dest_pos, src_pos = 0;--	for(i = 0; i < flt->channels; i++) {-		uint8_t prev_byte = 0;-		for(dest_pos = i;-				dest_pos < flt->block_length;-				dest_pos += flt->channels)-		{-			uint8_t byte;--			byte = rar->cstate.window_buf[-			    (rar->cstate.solid_offset + flt->block_start +-			    src_pos) & rar->cstate.window_mask];--			prev_byte -= byte;-			rar->cstate.filtered_buf[dest_pos] = prev_byte;-			src_pos++;-		}-	}--	return ARCHIVE_OK;-}--static int run_e8e9_filter(struct rar5* rar, struct filter_info* flt,-		int extended)-{-	const uint32_t file_size = 0x1000000;-	ssize_t i;--	circular_memcpy(rar->cstate.filtered_buf,-	    rar->cstate.window_buf, rar->cstate.window_mask,-	    rar->cstate.solid_offset + flt->block_start,-	    rar->cstate.solid_offset + flt->block_start + flt->block_length);--	for(i = 0; i < flt->block_length - 4;) {-		uint8_t b = rar->cstate.window_buf[-		    (rar->cstate.solid_offset + flt->block_start +-		    i++) & rar->cstate.window_mask];--		/*-		 * 0xE8 = x86's call <relative_addr_uint32> (function call)-		 * 0xE9 = x86's jmp <relative_addr_uint32> (unconditional jump)-		 */-		if(b == 0xE8 || (extended && b == 0xE9)) {--			uint32_t addr;-			uint32_t offset = (i + flt->block_start) % file_size;--			addr = read_filter_data(rar,-			    (uint32_t)(rar->cstate.solid_offset +-			    flt->block_start + i) & rar->cstate.window_mask);--			if(addr & 0x80000000) {-				if(((addr + offset) & 0x80000000) == 0) {-					write_filter_data(rar, (uint32_t)i,-					    addr + file_size);-				}-			} else {-				if((addr - file_size) & 0x80000000) {-					uint32_t naddr = addr - offset;-					write_filter_data(rar, (uint32_t)i,-					    naddr);-				}-			}--			i += 4;-		}-	}--	return ARCHIVE_OK;-}--static int run_arm_filter(struct rar5* rar, struct filter_info* flt) {-	ssize_t i = 0;-	uint32_t offset;--	circular_memcpy(rar->cstate.filtered_buf,-	    rar->cstate.window_buf, rar->cstate.window_mask,-	    rar->cstate.solid_offset + flt->block_start,-	    rar->cstate.solid_offset + flt->block_start + flt->block_length);--	for(i = 0; i < flt->block_length - 3; i += 4) {-		uint8_t* b = &rar->cstate.window_buf[-		    (rar->cstate.solid_offset +-		    flt->block_start + i + 3) & rar->cstate.window_mask];--		if(*b == 0xEB) {-			/* 0xEB = ARM's BL (branch + link) instruction. */-			offset = read_filter_data(rar,-			    (rar->cstate.solid_offset + flt->block_start + i) &-			     (uint32_t)rar->cstate.window_mask) & 0x00ffffff;--			offset -= (uint32_t) ((i + flt->block_start) / 4);-			offset = (offset & 0x00ffffff) | 0xeb000000;-			write_filter_data(rar, (uint32_t)i, offset);-		}-	}--	return ARCHIVE_OK;-}--static int run_filter(struct archive_read* a, struct filter_info* flt) {-	int ret;-	struct rar5* rar = get_context(a);--	clear_data_ready_stack(rar);-	free(rar->cstate.filtered_buf);--	rar->cstate.filtered_buf = malloc(flt->block_length);-	if(!rar->cstate.filtered_buf) {-		archive_set_error(&a->archive, ENOMEM,-		    "Can't allocate memory for filter data");-		return ARCHIVE_FATAL;-	}--	switch(flt->type) {-		case FILTER_DELTA:-			ret = run_delta_filter(rar, flt);-			break;--		case FILTER_E8:-			/* fallthrough */-		case FILTER_E8E9:-			ret = run_e8e9_filter(rar, flt,-			    flt->type == FILTER_E8E9);-			break;--		case FILTER_ARM:-			ret = run_arm_filter(rar, flt);-			break;--		default:-			archive_set_error(&a->archive,-			    ARCHIVE_ERRNO_FILE_FORMAT,-			    "Unsupported filter type: 0x%x",-			    (unsigned int)flt->type);-			return ARCHIVE_FAILED;-	}--	if(ret != ARCHIVE_OK) {-		/* Filter has failed. */-		return ret;-	}--	if(ARCHIVE_OK != push_data_ready(a, rar, rar->cstate.filtered_buf,-	    flt->block_length, rar->cstate.last_write_ptr))-	{-		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,-		    "Stack overflow when submitting unpacked data");--		return ARCHIVE_FATAL;-	}--	rar->cstate.last_write_ptr += flt->block_length;-	return ARCHIVE_OK;-}--/* The `push_data` function submits the selected data range to the user.- * Next call of `use_data` will use the pointer, size and offset arguments- * that are specified here. These arguments are pushed to the FIFO stack here,- * and popped from the stack by the `use_data` function. */-static void push_data(struct archive_read* a, struct rar5* rar,-    const uint8_t* buf, int64_t idx_begin, int64_t idx_end)-{-	const ssize_t wmask = rar->cstate.window_mask;-	const ssize_t solid_write_ptr = (rar->cstate.solid_offset +-	    rar->cstate.last_write_ptr) & wmask;--	idx_begin += rar->cstate.solid_offset;-	idx_end += rar->cstate.solid_offset;--	/* Check if our unpacked data is wrapped inside the window circular-	 * buffer.  If it's not wrapped, it can be copied out by using-	 * a single memcpy, but when it's wrapped, we need to copy the first-	 * part with one memcpy, and the second part with another memcpy. */--	if((idx_begin & wmask) > (idx_end & wmask)) {-		/* The data is wrapped (begin offset sis bigger than end-		 * offset). */-		const ssize_t frag1_size = rar->cstate.window_size --		    (idx_begin & wmask);-		const ssize_t frag2_size = idx_end & wmask;--		/* Copy the first part of the buffer first. */-		push_data_ready(a, rar, buf + solid_write_ptr, frag1_size,-		    rar->cstate.last_write_ptr);--		/* Copy the second part of the buffer. */-		push_data_ready(a, rar, buf, frag2_size,-		    rar->cstate.last_write_ptr + frag1_size);--		rar->cstate.last_write_ptr += frag1_size + frag2_size;-	} else {-		/* Data is not wrapped, so we can just use one call to copy the-		 * data. */-		push_data_ready(a, rar,-		    buf + solid_write_ptr, (idx_end - idx_begin) & wmask,-		    rar->cstate.last_write_ptr);--		rar->cstate.last_write_ptr += idx_end - idx_begin;-	}-}--/* Convenience function that submits the data to the user. It uses the- * unpack window buffer as a source location. */-static void push_window_data(struct archive_read* a, struct rar5* rar,-    int64_t idx_begin, int64_t idx_end)-{-	push_data(a, rar, rar->cstate.window_buf, idx_begin, idx_end);-}--static int apply_filters(struct archive_read* a) {-	struct filter_info* flt;-	struct rar5* rar = get_context(a);-	int ret;--	rar->cstate.all_filters_applied = 0;--	/* Get the first filter that can be applied to our data. The data-	 * needs to be fully unpacked before the filter can be run. */-	if(CDE_OK == cdeque_front(&rar->cstate.filters,-	    cdeque_filter_p(&flt))) {-		/* Check if our unpacked data fully covers this filter's-		 * range. */-		if(rar->cstate.write_ptr > flt->block_start &&-		    rar->cstate.write_ptr >= flt->block_start +-		    flt->block_length) {-			/* Check if we have some data pending to be written-			 * right before the filter's start offset. */-			if(rar->cstate.last_write_ptr == flt->block_start) {-				/* Run the filter specified by descriptor-				 * `flt`. */-				ret = run_filter(a, flt);-				if(ret != ARCHIVE_OK) {-					/* Filter failure, return error. */-					return ret;-				}--				/* Filter descriptor won't be needed anymore-				 * after it's used, * so remove it from the-				 * filter list and free its memory. */-				(void) cdeque_pop_front(&rar->cstate.filters,-				    cdeque_filter_p(&flt));--				free(flt);-			} else {-				/* We can't run filters yet, dump the memory-				 * right before the filter. */-				push_window_data(a, rar,-				    rar->cstate.last_write_ptr,-				    flt->block_start);-			}--			/* Return 'filter applied or not needed' state to the-			 * caller. */-			return ARCHIVE_RETRY;-		}-	}--	rar->cstate.all_filters_applied = 1;-	return ARCHIVE_OK;-}--static void dist_cache_push(struct rar5* rar, int value) {-	int* q = rar->cstate.dist_cache;--	q[3] = q[2];-	q[2] = q[1];-	q[1] = q[0];-	q[0] = value;-}--static int dist_cache_touch(struct rar5* rar, int idx) {-	int* q = rar->cstate.dist_cache;-	int i, dist = q[idx];--	for(i = idx; i > 0; i--)-		q[i] = q[i - 1];--	q[0] = dist;-	return dist;-}--static void free_filters(struct rar5* rar) {-	struct cdeque* d = &rar->cstate.filters;--	/* Free any remaining filters. All filters should be naturally-	 * consumed by the unpacking function, so remaining filters after-	 * unpacking normally mean that unpacking wasn't successful.-	 * But still of course we shouldn't leak memory in such case. */--	/* cdeque_size() is a fast operation, so we can use it as a loop-	 * expression. */-	while(cdeque_size(d) > 0) {-		struct filter_info* f = NULL;--		/* Pop_front will also decrease the collection's size. */-		if (CDE_OK == cdeque_pop_front(d, cdeque_filter_p(&f)))-			free(f);-	}--	cdeque_clear(d);--	/* Also clear out the variables needed for sanity checking. */-	rar->cstate.last_block_start = 0;-	rar->cstate.last_block_length = 0;-}--static void reset_file_context(struct rar5* rar) {-	memset(&rar->file, 0, sizeof(rar->file));-	blake2sp_init(&rar->file.b2state, 32);--	if(rar->main.solid) {-		rar->cstate.solid_offset += rar->cstate.write_ptr;-	} else {-		rar->cstate.solid_offset = 0;-	}--	rar->cstate.write_ptr = 0;-	rar->cstate.last_write_ptr = 0;-	rar->cstate.last_unstore_ptr = 0;--	rar->file.redir_type = REDIR_TYPE_NONE;-	rar->file.redir_flags = 0;--	free_filters(rar);-}--static inline int get_archive_read(struct archive* a,-    struct archive_read** ar)-{-	*ar = (struct archive_read*) a;-	archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,-	    "archive_read_support_format_rar5");--	return ARCHIVE_OK;-}--static int read_ahead(struct archive_read* a, size_t how_many,-    const uint8_t** ptr)-{-	if(!ptr)-		return 0;--	*ptr = __archive_read_ahead(a, how_many, NULL);-	if(*ptr == NULL) {-		return 0;-	}--	return 1;-}--static int consume(struct archive_read* a, int64_t how_many) {-	int ret;--	ret = how_many == __archive_read_consume(a, how_many)-		? ARCHIVE_OK-		: ARCHIVE_FATAL;--	return ret;-}--/**- * Read a RAR5 variable sized numeric value. This value will be stored in- * `pvalue`. The `pvalue_len` argument points to a variable that will receive- * the byte count that was consumed in order to decode the `pvalue` value, plus- * one.- *- * pvalue_len is optional and can be NULL.- *- * NOTE: if `pvalue_len` is NOT NULL, the caller needs to manually consume- * the number of bytes that `pvalue_len` value contains. If the `pvalue_len`- * is NULL, this consuming operation is done automatically.- *- * Returns 1 if *pvalue was successfully read.- * Returns 0 if there was an error. In this case, *pvalue contains an- *           invalid value.- */--static int read_var(struct archive_read* a, uint64_t* pvalue,-    uint64_t* pvalue_len)-{-	uint64_t result = 0;-	size_t shift, i;-	const uint8_t* p;-	uint8_t b;--	/* We will read maximum of 8 bytes. We don't have to handle the-	 * situation to read the RAR5 variable-sized value stored at the end of-	 * the file, because such situation will never happen. */-	if(!read_ahead(a, 8, &p))-		return 0;--	for(shift = 0, i = 0; i < 8; i++, shift += 7) {-		b = p[i];--		/* Strip the MSB from the input byte and add the resulting-		 * number to the `result`. */-		result += (b & (uint64_t)0x7F) << shift;--		/* MSB set to 1 means we need to continue decoding process.-		 * MSB set to 0 means we're done.-		 *-		 * This conditional checks for the second case. */-		if((b & 0x80) == 0) {-			if(pvalue) {-				*pvalue = result;-			}--			/* If the caller has passed the `pvalue_len` pointer,-			 * store the number of consumed bytes in it and do NOT-			 * consume those bytes, since the caller has all the-			 * information it needs to perform */-			if(pvalue_len) {-				*pvalue_len = 1 + i;-			} else {-				/* If the caller did not provide the-				 * `pvalue_len` pointer, it will not have the-				 * possibility to advance the file pointer,-				 * because it will not know how many bytes it-				 * needs to consume. This is why we handle-				 * such situation here automatically. */-				if(ARCHIVE_OK != consume(a, 1 + i)) {-					return 0;-				}-			}--			/* End of decoding process, return success. */-			return 1;-		}-	}--	/* The decoded value takes the maximum number of 8 bytes.-	 * It's a maximum number of bytes, so end decoding process here-	 * even if the first bit of last byte is 1. */-	if(pvalue) {-		*pvalue = result;-	}--	if(pvalue_len) {-		*pvalue_len = 9;-	} else {-		if(ARCHIVE_OK != consume(a, 9)) {-			return 0;-		}-	}--	return 1;-}--static int read_var_sized(struct archive_read* a, size_t* pvalue,-    size_t* pvalue_len)-{-	uint64_t v;-	uint64_t v_size = 0;--	const int ret = pvalue_len ? read_var(a, &v, &v_size)-				   : read_var(a, &v, NULL);--	if(ret == 1 && pvalue) {-		*pvalue = (size_t) v;-	}--	if(pvalue_len) {-		/* Possible data truncation should be safe. */-		*pvalue_len = (size_t) v_size;-	}--	return ret;-}--static int read_bits_32(struct archive_read* a, struct rar5* rar,-	const uint8_t* p, uint32_t* value)-{-	if(rar->bits.in_addr >= rar->cstate.cur_block_size) {-		archive_set_error(&a->archive,-			ARCHIVE_ERRNO_PROGRAMMER,-			"Premature end of stream during extraction of data (#1)");-		return ARCHIVE_FATAL;-	}--	uint32_t bits = archive_be32dec(p + rar->bits.in_addr);-	bits <<= rar->bits.bit_addr;-	bits |= p[rar->bits.in_addr + 4] >> (8 - rar->bits.bit_addr);-	*value = bits;-	return ARCHIVE_OK;-}--static int read_bits_16(struct archive_read* a, struct rar5* rar,-	const uint8_t* p, uint16_t* value)-{-	if(rar->bits.in_addr >= rar->cstate.cur_block_size) {-		archive_set_error(&a->archive,-			ARCHIVE_ERRNO_PROGRAMMER,-			"Premature end of stream during extraction of data (#2)");-		return ARCHIVE_FATAL;-	}--	uint32_t bits = archive_be24dec(p + (unsigned)rar->bits.in_addr);-	bits >>= (8 - rar->bits.bit_addr);-	*value = bits & 0xffff;-	return ARCHIVE_OK;-}--static void skip_bits(struct rar5* rar, int bits) {-	const int new_bits = rar->bits.bit_addr + bits;-	rar->bits.in_addr += new_bits >> 3;-	rar->bits.bit_addr = new_bits & 7;-}--/* n = up to 16 */-static int read_consume_bits(struct archive_read* a, struct rar5* rar,-	const uint8_t* p, int n, int* value)-{-	uint16_t v;-	int ret, num;--	if(n == 0 || n > 16) {-		/* This is a programmer error and should never happen-		 * in runtime. */-		return ARCHIVE_FATAL;-	}--	ret = read_bits_16(a, rar, p, &v);-	if(ret != ARCHIVE_OK)-		return ret;--	num = (int) v;-	num >>= 16 - n;--	skip_bits(rar, n);--	if(value)-		*value = num;--	return ARCHIVE_OK;-}--static char read_u32(struct archive_read* a, uint32_t* pvalue) {-	const uint8_t* p;-	if(!read_ahead(a, 4, &p))-		return 0;--	*pvalue = archive_le32dec(p);-	return ARCHIVE_OK == consume(a, 4);-}--static char read_u64(struct archive_read* a, uint64_t* pvalue) {-	const uint8_t* p;-	if(!read_ahead(a, 8, &p))-		return 0;--	*pvalue = archive_le64dec(p);-	return ARCHIVE_OK == consume(a, 8);-}--static int bid_standard(struct archive_read* a) {-	const uint8_t* p;-	char signature[sizeof(rar5_signature_xor)];--	rar5_signature(signature);--	if(!read_ahead(a, sizeof(rar5_signature_xor), &p))-		return -1;--	if(!memcmp(signature, p, sizeof(rar5_signature_xor)))-		return 30;--	return -1;-}--static int bid_sfx(struct archive_read *a)-{-	const char *p;--	if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)-		return -1;--	if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {-		/* This is a PE file */-		char signature[sizeof(rar5_signature_xor)];-		ssize_t offset = 0x10000;-		ssize_t window = 4096;-		ssize_t bytes_avail;--		rar5_signature(signature);--		while (offset + window <= (1024 * 512)) {-			const char *buff = __archive_read_ahead(a, offset + window, &bytes_avail);-			if (buff == NULL) {-				/* Remaining bytes are less than window. */-				window >>= 1;-				if (window < 0x40)-					return 0;-				continue;-			}-			p = buff + offset;-			while (p + 8 < buff + bytes_avail) {-				if (memcmp(p, signature, sizeof(signature)) == 0)-					return 30;-				p += 0x10;-			}-			offset = p - buff;-		}-	}--	return 0;-}--static int rar5_bid(struct archive_read* a, int best_bid) {-	int my_bid;--	if(best_bid > 30)-		return -1;--	my_bid = bid_standard(a);-	if(my_bid > -1) {-		return my_bid;-	}-	my_bid = bid_sfx(a);-	if (my_bid > -1) {-		return my_bid;-	}--	return -1;-}--static int rar5_options(struct archive_read *a, const char *key,-    const char *val) {-	(void) a;-	(void) key;-	(void) val;--	/* No options supported in this version. Return the ARCHIVE_WARN code-	 * to signal the options supervisor that the unpacker didn't handle-	 * setting this option. */--	return ARCHIVE_WARN;-}--static void init_header(struct archive_read* a) {-	a->archive.archive_format = ARCHIVE_FORMAT_RAR_V5;-	a->archive.archive_format_name = "RAR5";-}--static void init_window_mask(struct rar5* rar) {-	if (rar->cstate.window_size)-		rar->cstate.window_mask = rar->cstate.window_size - 1;-	else-		rar->cstate.window_mask = 0;-}--enum HEADER_FLAGS {-	HFL_EXTRA_DATA = 0x0001,-	HFL_DATA = 0x0002,-	HFL_SKIP_IF_UNKNOWN = 0x0004,-	HFL_SPLIT_BEFORE = 0x0008,-	HFL_SPLIT_AFTER = 0x0010,-	HFL_CHILD = 0x0020,-	HFL_INHERITED = 0x0040-};--static int process_main_locator_extra_block(struct archive_read* a,-    struct rar5* rar)-{-	uint64_t locator_flags;--	enum LOCATOR_FLAGS {-		QLIST = 0x01, RECOVERY = 0x02,-	};--	if(!read_var(a, &locator_flags, NULL)) {-		return ARCHIVE_EOF;-	}--	if(locator_flags & QLIST) {-		if(!read_var(a, &rar->qlist_offset, NULL)) {-			return ARCHIVE_EOF;-		}--		/* qlist is not used */-	}--	if(locator_flags & RECOVERY) {-		if(!read_var(a, &rar->rr_offset, NULL)) {-			return ARCHIVE_EOF;-		}--		/* rr is not used */-	}--	return ARCHIVE_OK;-}--static int parse_file_extra_hash(struct archive_read* a, struct rar5* rar,-    int64_t* extra_data_size)-{-	size_t hash_type = 0;-	size_t value_len;--	enum HASH_TYPE {-		BLAKE2sp = 0x00-	};--	if(!read_var_sized(a, &hash_type, &value_len))-		return ARCHIVE_EOF;--	*extra_data_size -= value_len;-	if(ARCHIVE_OK != consume(a, value_len)) {-		return ARCHIVE_EOF;-	}--	/* The file uses BLAKE2sp checksum algorithm instead of plain old-	 * CRC32. */-	if(hash_type == BLAKE2sp) {-		const uint8_t* p;-		const int hash_size = sizeof(rar->file.blake2sp);--		if(!read_ahead(a, hash_size, &p))-			return ARCHIVE_EOF;--		rar->file.has_blake2 = 1;-		memcpy(&rar->file.blake2sp, p, hash_size);--		if(ARCHIVE_OK != consume(a, hash_size)) {-			return ARCHIVE_EOF;-		}--		*extra_data_size -= hash_size;-	} else {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Unsupported hash type (0x%jx)", (uintmax_t)hash_type);-		return ARCHIVE_FATAL;-	}--	return ARCHIVE_OK;-}--static int parse_htime_item(struct archive_read* a, char unix_time,-    int64_t* sec, uint32_t* nsec, int64_t* extra_data_size)-{-	if(unix_time) {-		uint32_t time_val;-		if(!read_u32(a, &time_val))-			return ARCHIVE_EOF;--		*extra_data_size -= 4;-		*sec = (int64_t) time_val;-	} else {-		uint64_t windows_time;-		if(!read_u64(a, &windows_time))-			return ARCHIVE_EOF;--		ntfs_to_unix(windows_time, sec, nsec);-		*extra_data_size -= 8;-	}--	return ARCHIVE_OK;-}--static int parse_file_extra_version(struct archive_read* a,-    struct archive_entry* e, int64_t* extra_data_size)-{-	size_t flags = 0;-	size_t version = 0;-	size_t value_len = 0;-	struct archive_string version_string;-	struct archive_string name_utf8_string;-	const char* cur_filename;--	/* Flags are ignored. */-	if(!read_var_sized(a, &flags, &value_len))-		return ARCHIVE_EOF;--	*extra_data_size -= value_len;-	if(ARCHIVE_OK != consume(a, value_len))-		return ARCHIVE_EOF;--	if(!read_var_sized(a, &version, &value_len))-		return ARCHIVE_EOF;--	*extra_data_size -= value_len;-	if(ARCHIVE_OK != consume(a, value_len))-		return ARCHIVE_EOF;--	/* extra_data_size should be zero here. */--	cur_filename = archive_entry_pathname_utf8(e);-	if(cur_filename == NULL) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,-		    "Version entry without file name");-		return ARCHIVE_FATAL;-	}--	archive_string_init(&version_string);-	archive_string_init(&name_utf8_string);--	/* Prepare a ;123 suffix for the filename, where '123' is the version-	 * value of this file. */-	archive_string_sprintf(&version_string, ";%zu", version);--	/* Build the new filename. */-	archive_strcat(&name_utf8_string, cur_filename);-	archive_strcat(&name_utf8_string, version_string.s);--	/* Apply the new filename into this file's context. */-	archive_entry_update_pathname_utf8(e, name_utf8_string.s);--	/* Free buffers. */-	archive_string_free(&version_string);-	archive_string_free(&name_utf8_string);-	return ARCHIVE_OK;-}--static int parse_file_extra_htime(struct archive_read* a,-    struct archive_entry* e, struct rar5* rar, int64_t* extra_data_size)-{-	char unix_time, has_unix_ns, has_mtime, has_ctime, has_atime;-	size_t flags = 0;-	size_t value_len;--	enum HTIME_FLAGS {-		IS_UNIX       = 0x01,-		HAS_MTIME     = 0x02,-		HAS_CTIME     = 0x04,-		HAS_ATIME     = 0x08,-		HAS_UNIX_NS   = 0x10,-	};--	if(!read_var_sized(a, &flags, &value_len))-		return ARCHIVE_EOF;--	*extra_data_size -= value_len;-	if(ARCHIVE_OK != consume(a, value_len)) {-		return ARCHIVE_EOF;-	}--	unix_time = flags & IS_UNIX;-	has_unix_ns = unix_time && (flags & HAS_UNIX_NS);-	has_mtime = flags & HAS_MTIME;-	has_atime = flags & HAS_ATIME;-	has_ctime = flags & HAS_CTIME;-	rar->file.e_atime_ns = rar->file.e_ctime_ns = rar->file.e_mtime_ns = 0;--	if(has_mtime) {-		parse_htime_item(a, unix_time, &rar->file.e_mtime,-		    &rar->file.e_mtime_ns, extra_data_size);-	}--	if(has_ctime) {-		parse_htime_item(a, unix_time, &rar->file.e_ctime,-		    &rar->file.e_ctime_ns, extra_data_size);-	}--	if(has_atime) {-		parse_htime_item(a, unix_time, &rar->file.e_atime,-		    &rar->file.e_atime_ns, extra_data_size);-	}--	if(has_mtime && has_unix_ns) {-		if(!read_u32(a, &rar->file.e_mtime_ns))-			return ARCHIVE_EOF;--		*extra_data_size -= 4;-	}--	if(has_ctime && has_unix_ns) {-		if(!read_u32(a, &rar->file.e_ctime_ns))-			return ARCHIVE_EOF;--		*extra_data_size -= 4;-	}--	if(has_atime && has_unix_ns) {-		if(!read_u32(a, &rar->file.e_atime_ns))-			return ARCHIVE_EOF;--		*extra_data_size -= 4;-	}--	/* The seconds and nanoseconds are either together, or separated in two-	 * fields so we parse them, then set the archive_entry's times. */-	if(has_mtime) {-		archive_entry_set_mtime(e, rar->file.e_mtime, rar->file.e_mtime_ns);-	}--	if(has_ctime) {-		archive_entry_set_ctime(e, rar->file.e_ctime, rar->file.e_ctime_ns);-	}--	if(has_atime) {-		archive_entry_set_atime(e, rar->file.e_atime, rar->file.e_atime_ns);-	}--	return ARCHIVE_OK;-}--static int parse_file_extra_redir(struct archive_read* a,-    struct archive_entry* e, struct rar5* rar, int64_t* extra_data_size)-{-	uint64_t value_size = 0;-	size_t target_size = 0;-	char target_utf8_buf[MAX_NAME_IN_BYTES];-	const uint8_t* p;--	if(!read_var(a, &rar->file.redir_type, &value_size))-		return ARCHIVE_EOF;-	if(ARCHIVE_OK != consume(a, (int64_t)value_size))-		return ARCHIVE_EOF;-	*extra_data_size -= value_size;--	if(!read_var(a, &rar->file.redir_flags, &value_size))-		return ARCHIVE_EOF;-	if(ARCHIVE_OK != consume(a, (int64_t)value_size))-		return ARCHIVE_EOF;-	*extra_data_size -= value_size;--	if(!read_var_sized(a, &target_size, NULL))-		return ARCHIVE_EOF;-	*extra_data_size -= target_size + 1;--	if(target_size > (MAX_NAME_IN_CHARS - 1)) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Link target is too long");-		return ARCHIVE_FATAL;-	}--	if(target_size == 0) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "No link target specified");-		return ARCHIVE_FATAL;-	}--	if(!read_ahead(a, target_size, &p))-		return ARCHIVE_EOF;--	memcpy(target_utf8_buf, p, target_size);-	target_utf8_buf[target_size] = 0;--	if(ARCHIVE_OK != consume(a, (int64_t)target_size))-		return ARCHIVE_EOF;--	switch(rar->file.redir_type) {-		case REDIR_TYPE_UNIXSYMLINK:-		case REDIR_TYPE_WINSYMLINK:-			archive_entry_set_filetype(e, AE_IFLNK);-			archive_entry_update_symlink_utf8(e, target_utf8_buf);-			if (rar->file.redir_flags & REDIR_SYMLINK_IS_DIR) {-				archive_entry_set_symlink_type(e,-					AE_SYMLINK_TYPE_DIRECTORY);-			} else {-				archive_entry_set_symlink_type(e,-				AE_SYMLINK_TYPE_FILE);-			}-			break;--		case REDIR_TYPE_HARDLINK:-			archive_entry_set_filetype(e, AE_IFREG);-			archive_entry_update_hardlink_utf8(e, target_utf8_buf);-			break;--		default:-			/* Unknown redir type, skip it. */-			break;-	}-	return ARCHIVE_OK;-}--static int parse_file_extra_owner(struct archive_read* a,-    struct archive_entry* e, int64_t* extra_data_size)-{-	uint64_t flags = 0;-	uint64_t value_size = 0;-	uint64_t id = 0;-	size_t name_len = 0;-	size_t name_size = 0;-	char namebuf[OWNER_MAXNAMELEN];-	const uint8_t* p;--	if(!read_var(a, &flags, &value_size))-		return ARCHIVE_EOF;-	if(ARCHIVE_OK != consume(a, (int64_t)value_size))-		return ARCHIVE_EOF;-	*extra_data_size -= value_size;--	if ((flags & OWNER_USER_NAME) != 0) {-		if(!read_var_sized(a, &name_size, NULL))-			return ARCHIVE_EOF;-		*extra_data_size -= name_size + 1;--		if(!read_ahead(a, name_size, &p))-			return ARCHIVE_EOF;--		if (name_size >= OWNER_MAXNAMELEN) {-			name_len = OWNER_MAXNAMELEN - 1;-		} else {-			name_len = name_size;-		}--		memcpy(namebuf, p, name_len);-		namebuf[name_len] = 0;-		if(ARCHIVE_OK != consume(a, (int64_t)name_size))-			return ARCHIVE_EOF;--		archive_entry_set_uname(e, namebuf);-	}-	if ((flags & OWNER_GROUP_NAME) != 0) {-		if(!read_var_sized(a, &name_size, NULL))-			return ARCHIVE_EOF;-		*extra_data_size -= name_size + 1;--		if(!read_ahead(a, name_size, &p))-			return ARCHIVE_EOF;--		if (name_size >= OWNER_MAXNAMELEN) {-			name_len = OWNER_MAXNAMELEN - 1;-		} else {-			name_len = name_size;-		}--		memcpy(namebuf, p, name_len);-		namebuf[name_len] = 0;-		if(ARCHIVE_OK != consume(a, (int64_t)name_size))-			return ARCHIVE_EOF;--		archive_entry_set_gname(e, namebuf);-	}-	if ((flags & OWNER_USER_UID) != 0) {-		if(!read_var(a, &id, &value_size))-			return ARCHIVE_EOF;-		if(ARCHIVE_OK != consume(a, (int64_t)value_size))-			return ARCHIVE_EOF;-		*extra_data_size -= value_size;--		archive_entry_set_uid(e, (la_int64_t)id);-	}-	if ((flags & OWNER_GROUP_GID) != 0) {-		if(!read_var(a, &id, &value_size))-			return ARCHIVE_EOF;-		if(ARCHIVE_OK != consume(a, (int64_t)value_size))-			return ARCHIVE_EOF;-		*extra_data_size -= value_size;--		archive_entry_set_gid(e, (la_int64_t)id);-	}-	return ARCHIVE_OK;-}--static int process_head_file_extra(struct archive_read* a,-    struct archive_entry* e, struct rar5* rar, int64_t extra_data_size)-{-	uint64_t extra_field_size;-	uint64_t extra_field_id = 0;-	uint64_t var_size;--	while(extra_data_size > 0) {-		/* Make sure we won't fail if the file declares only unsupported-		attributes. */-		int ret = ARCHIVE_OK;--		if(!read_var(a, &extra_field_size, &var_size))-			return ARCHIVE_EOF;--		extra_data_size -= var_size;-		if(ARCHIVE_OK != consume(a, var_size)) {-			return ARCHIVE_EOF;-		}--		if(!read_var(a, &extra_field_id, &var_size))-			return ARCHIVE_EOF;--		extra_field_size -= var_size;-		extra_data_size -= var_size;-		if(ARCHIVE_OK != consume(a, var_size)) {-			return ARCHIVE_EOF;-		}--		switch(extra_field_id) {-			case EX_HASH:-				ret = parse_file_extra_hash(a, rar,-				    &extra_data_size);-				break;-			case EX_HTIME:-				ret = parse_file_extra_htime(a, e, rar,-				    &extra_data_size);-				break;-			case EX_REDIR:-				ret = parse_file_extra_redir(a, e, rar,-				    &extra_data_size);-				break;-			case EX_UOWNER:-				ret = parse_file_extra_owner(a, e,-				    &extra_data_size);-				break;-			case EX_VERSION:-				ret = parse_file_extra_version(a, e,-				    &extra_data_size);-				break;-			case EX_CRYPT:-				/* Mark the entry as encrypted */-				archive_entry_set_is_data_encrypted(e, 1);-				rar->has_encrypted_entries = 1;-				rar->cstate.data_encrypted = 1;-				/* fallthrough */-			case EX_SUBDATA:-				/* fallthrough */-			default:-				/* Skip unsupported entry. */-				extra_data_size -= extra_field_size;-				if (ARCHIVE_OK != consume(a, extra_field_size)) {-					return ARCHIVE_EOF;-				}--				/* Don't fail on unsupported attribute -- we've handled it-				   by skipping over it. */-				ret = ARCHIVE_OK;-		}--		if (ret != ARCHIVE_OK) {-			/* Forward any errors signalled by the attribute parsing-			   functions. */-			return ret;-		}-	}--	if (extra_data_size != 0) {-		/* We didn't skip everything, or we skipped too much; either way,-		   there's an error in this parsing function. */--		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,-				"unsupported structure of file header extra data");-		return ARCHIVE_FATAL;-	}--	return ARCHIVE_OK;-}--static int file_entry_sanity_checks(struct archive_read* a,-	size_t block_flags, uint8_t is_dir, uint64_t unpacked_size,-	size_t packed_size)-{-	if (is_dir) {-		const int declares_data_size =-			(int) (unpacked_size != 0 || packed_size != 0);--		/* FILE entries for directories still declare HFL_DATA in block flags,-		   even though attaching data to such blocks doesn't make much sense. */-		if (declares_data_size) {-			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-				"directory entries cannot have any data");-			return ARCHIVE_FATAL;-		}-	} else {-		const int declares_hfl_data = (int) ((block_flags & HFL_DATA) != 0);-		if (!declares_hfl_data) {-			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-					"no data found in file/service block");-			return ARCHIVE_FATAL;-		}-	}--	return ARCHIVE_OK;-}--static int process_head_file(struct archive_read* a, struct rar5* rar,-    struct archive_entry* entry, size_t block_flags)-{-	int64_t extra_data_size = 0;-	size_t data_size = 0;-	size_t file_flags = 0;-	size_t file_attr = 0;-	size_t compression_info = 0;-	size_t host_os = 0;-	size_t name_size = 0;-	uint64_t unpacked_size, window_size;-	uint32_t mtime = 0, crc = 0;-	int c_method = 0, c_version = 0;-	char name_utf8_buf[MAX_NAME_IN_BYTES];-	const uint8_t* p;-	int sanity_ret;--	enum FILE_FLAGS {-		DIRECTORY = 0x0001, UTIME = 0x0002, CRC32 = 0x0004,-		UNKNOWN_UNPACKED_SIZE = 0x0008,-	};--	enum FILE_ATTRS {-		ATTR_READONLY = 0x1, ATTR_HIDDEN = 0x2, ATTR_SYSTEM = 0x4,-		ATTR_DIRECTORY = 0x10,-	};--	enum COMP_INFO_FLAGS {-		SOLID = 0x0040,-	};--	enum HOST_OS {-		HOST_WINDOWS = 0,-		HOST_UNIX = 1,-	};--	archive_entry_clear(entry);--	/* Do not reset file context if we're switching archives. */-	if(!rar->cstate.switch_multivolume) {-		reset_file_context(rar);-	}--	if(block_flags & HFL_EXTRA_DATA) {-		uint64_t edata_size = 0;-		if(!read_var(a, &edata_size, NULL))-			return ARCHIVE_EOF;--		/* Intentional type cast from unsigned to signed. */-		extra_data_size = (int64_t) edata_size;-	}--	if(block_flags & HFL_DATA) {-		if(!read_var_sized(a, &data_size, NULL))-			return ARCHIVE_EOF;--		if(data_size > SSIZE_MAX) {-			archive_set_error(&a->archive,-			    ARCHIVE_ERRNO_FILE_FORMAT,-			    "File data size is too large");-			return ARCHIVE_FATAL;-		}--		rar->file.bytes_remaining = data_size;-	} else {-		rar->file.bytes_remaining = 0;-	}--	if(!read_var_sized(a, &file_flags, NULL))-		return ARCHIVE_EOF;--	if(!read_var(a, &unpacked_size, NULL))-		return ARCHIVE_EOF;--	if(file_flags & UNKNOWN_UNPACKED_SIZE) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,-		    "Files with unknown unpacked size are not supported");-		return ARCHIVE_FATAL;-	}--	rar->file.dir = (uint8_t) ((file_flags & DIRECTORY) > 0);--	sanity_ret = file_entry_sanity_checks(a, block_flags, rar->file.dir,-		unpacked_size, data_size);--	if (sanity_ret != ARCHIVE_OK) {-		return sanity_ret;-	}--	if(!read_var_sized(a, &file_attr, NULL))-		return ARCHIVE_EOF;--	if(file_flags & UTIME) {-		if(!read_u32(a, &mtime))-			return ARCHIVE_EOF;-	}--	if(file_flags & CRC32) {-		if(!read_u32(a, &crc))-			return ARCHIVE_EOF;-	}--	if(!read_var_sized(a, &compression_info, NULL))-		return ARCHIVE_EOF;--	c_method = (int) (compression_info >> 7) & 0x7;-	c_version = (int) (compression_info & 0x3f);--	/* RAR5 seems to limit the dictionary size to 64MB. */-	window_size = (rar->file.dir > 0) ?-		0 :-		g_unpack_window_size << ((compression_info >> 10) & 15);-	rar->cstate.method = c_method;-	rar->cstate.version = c_version + 50;-	rar->file.solid = (compression_info & SOLID) > 0;--	/* Archives which declare solid files without initializing the window-	 * buffer first are invalid, unless previous data was encrypted, in-	 * which case we may never have had the chance */--	if(rar->file.solid > 0 && rar->cstate.data_encrypted == 0 &&-	    rar->cstate.window_buf == NULL) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-				  "Declared solid file, but no window buffer "-				  "initialized yet");-		return ARCHIVE_FATAL;-	}--	/* Check if window_size is a sane value. Also, if the file is not-	 * declared as a directory, disallow window_size == 0. */-	if(window_size > (64 * 1024 * 1024) ||-	    (rar->file.dir == 0 && window_size == 0))-	{-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Declared dictionary size is not supported");-		return ARCHIVE_FATAL;-	}--	if(rar->file.solid > 0) {-		/* Re-check if current window size is the same as previous-		 * window size (for solid files only). */-		if(rar->file.solid_window_size > 0 &&-		    rar->file.solid_window_size != (ssize_t) window_size)-		{-			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-			    "Window size for this solid file doesn't match "-			    "the window size used in previous solid file");-			return ARCHIVE_FATAL;-		}-	}-	else-		rar->cstate.data_encrypted = 0; /* Reset for new buffer */--	if(rar->cstate.window_size < (ssize_t) window_size &&-	    rar->cstate.window_buf)-	{-		/* The `data_ready` stack contains pointers to the `window_buf` or-		 * `filtered_buf` buffers.  Since we're about to reallocate the first-		 * buffer, some of those pointers could become invalid. Therefore, we-		 * need to dispose of all entries from the stack before attempting the-		 * realloc. */-		clear_data_ready_stack(rar);--		/* If window_buf has been allocated before, reallocate it, so-		 * that its size will match new window_size. */--		uint8_t* new_window_buf =-			realloc(rar->cstate.window_buf, (size_t) window_size);--		if(!new_window_buf) {-			archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,-				"Not enough memory when trying to realloc the window "-				"buffer");-			return ARCHIVE_FATAL;-		}--		rar->cstate.window_buf = new_window_buf;-	}--	/* Values up to 64M should fit into ssize_t on every-	 * architecture. */-	rar->cstate.window_size = (ssize_t) window_size;--	if(rar->file.solid > 0 && rar->file.solid_window_size == 0) {-		/* Solid files have to have the same window_size across-		   whole archive. Remember the window_size parameter-		   for first solid file found. */-		rar->file.solid_window_size = rar->cstate.window_size;-	}--	init_window_mask(rar);--	rar->file.service = 0;--	if(!read_var_sized(a, &host_os, NULL))-		return ARCHIVE_EOF;--	if(host_os == HOST_WINDOWS) {-		/* Host OS is Windows */--		__LA_MODE_T mode;--		if(file_attr & ATTR_DIRECTORY) {-			if (file_attr & ATTR_READONLY) {-				mode = 0555 | AE_IFDIR;-			} else {-				mode = 0755 | AE_IFDIR;-			}-		} else {-			if (file_attr & ATTR_READONLY) {-				mode = 0444 | AE_IFREG;-			} else {-				mode = 0644 | AE_IFREG;-			}-		}--		archive_entry_set_mode(entry, mode);--		if (file_attr & (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM)) {-			char buf[sizeof(",rdonly,hidden,system")];-			char *fflags[3] = { "", "", "" };-			char **flag = fflags;--			if (file_attr & ATTR_READONLY)-				*flag++ = ",rdonly";-			if (file_attr & ATTR_HIDDEN)-				*flag++ = ",hidden";-			if (file_attr & ATTR_SYSTEM)-				*flag++ = ",system";--			snprintf(buf, sizeof(buf), "%s%s%s",-			    fflags[0], fflags[1], fflags[2]);-			archive_entry_copy_fflags_text(entry, buf + 1);-		}-	} else if(host_os == HOST_UNIX) {-		/* Host OS is Unix */-		archive_entry_set_mode(entry, (__LA_MODE_T) file_attr);-	} else {-		/* Unknown host OS */-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-				"Unsupported Host OS: 0x%jx",-				(uintmax_t)host_os);--		return ARCHIVE_FATAL;-	}--	if(!read_var_sized(a, &name_size, NULL))-		return ARCHIVE_EOF;--	if(name_size > (MAX_NAME_IN_CHARS - 1)) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-				"Filename is too long");--		return ARCHIVE_FATAL;-	}--	if(name_size == 0) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-				"No filename specified");--		return ARCHIVE_FATAL;-	}--	if(!read_ahead(a, name_size, &p))-		return ARCHIVE_EOF;--	memcpy(name_utf8_buf, p, name_size);-	name_utf8_buf[name_size] = 0;-	if(ARCHIVE_OK != consume(a, name_size)) {-		return ARCHIVE_EOF;-	}--	archive_entry_update_pathname_utf8(entry, name_utf8_buf);--	if(extra_data_size > 0) {-		int ret = process_head_file_extra(a, entry, rar,-		    extra_data_size);--		/*-		 * TODO: rewrite or remove useless sanity check-		 *       as extra_data_size is not passed as a pointer-		 *-		if(extra_data_size < 0) {-			archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,-			    "File extra data size is not zero");-			return ARCHIVE_FATAL;-		}-		 */--		if(ret != ARCHIVE_OK)-			return ret;-	}--	if((file_flags & UNKNOWN_UNPACKED_SIZE) == 0) {-		rar->file.unpacked_size = (ssize_t) unpacked_size;-		if(rar->file.redir_type == REDIR_TYPE_NONE)-			archive_entry_set_size(entry, unpacked_size);-	}--	if(file_flags & UTIME) {-		archive_entry_set_mtime(entry, (time_t) mtime, 0);-	}--	if(file_flags & CRC32) {-		rar->file.stored_crc32 = crc;-	}--	if(!rar->cstate.switch_multivolume) {-		/* Do not reinitialize unpacking state if we're switching-		 * archives. */-		rar->cstate.block_parsing_finished = 1;-		rar->cstate.all_filters_applied = 1;-		rar->cstate.initialized = 0;-	}--	if(rar->generic.split_before > 0) {-		/* If now we're standing on a header that has a 'split before'-		 * mark, it means we're standing on a 'continuation' file-		 * header. Signal the caller that if it wants to move to-		 * another file, it must call rar5_read_header() function-		 * again. */--		return ARCHIVE_RETRY;-	} else {-		return ARCHIVE_OK;-	}-}--static int process_head_service(struct archive_read* a, struct rar5* rar,-    struct archive_entry* entry, size_t block_flags)-{-	/* Process this SERVICE block the same way as FILE blocks. */-	int ret = process_head_file(a, rar, entry, block_flags);-	if(ret != ARCHIVE_OK)-		return ret;--	rar->file.service = 1;--	/* But skip the data part automatically. It's no use for the user-	 * anyway.  It contains only service data, not even needed to-	 * properly unpack the file. */-	ret = rar5_read_data_skip(a);-	if(ret != ARCHIVE_OK)-		return ret;--	/* After skipping, try parsing another block automatically. */-	return ARCHIVE_RETRY;-}--static int process_head_main(struct archive_read* a, struct rar5* rar,-    struct archive_entry* entry, size_t block_flags)-{-	int ret;-	uint64_t extra_data_size = 0;-	size_t extra_field_size = 0;-	size_t extra_field_id = 0;-	size_t archive_flags = 0;--	enum MAIN_FLAGS {-		VOLUME = 0x0001,         /* multi-volume archive */-		VOLUME_NUMBER = 0x0002,  /* volume number, first vol doesn't-					  * have it */-		SOLID = 0x0004,          /* solid archive */-		PROTECT = 0x0008,        /* contains Recovery info */-		LOCK = 0x0010,           /* readonly flag, not used */-	};--	enum MAIN_EXTRA {-		// Just one attribute here.-		LOCATOR = 0x01,-	};--	(void) entry;--	if(block_flags & HFL_EXTRA_DATA) {-		if(!read_var(a, &extra_data_size, NULL))-			return ARCHIVE_EOF;-	} else {-		extra_data_size = 0;-	}--	if(!read_var_sized(a, &archive_flags, NULL)) {-		return ARCHIVE_EOF;-	}--	rar->main.volume = (archive_flags & VOLUME) > 0;-	rar->main.solid = (archive_flags & SOLID) > 0;--	if(archive_flags & VOLUME_NUMBER) {-		size_t v = 0;-		if(!read_var_sized(a, &v, NULL)) {-			return ARCHIVE_EOF;-		}--		if (v > UINT_MAX) {-			archive_set_error(&a->archive,-			    ARCHIVE_ERRNO_FILE_FORMAT,-			    "Invalid volume number");-			return ARCHIVE_FATAL;-		}--		rar->main.vol_no = (unsigned int) v;-	} else {-		rar->main.vol_no = 0;-	}--	if(rar->vol.expected_vol_no > 0 &&-		rar->main.vol_no != rar->vol.expected_vol_no)-	{-		/* Returning EOF instead of FATAL because of strange-		 * libarchive behavior. When opening multiple files via-		 * archive_read_open_filenames(), after reading up the whole-		 * last file, the __archive_read_ahead function wraps up to-		 * the first archive instead of returning EOF. */-		return ARCHIVE_EOF;-	}--	if(extra_data_size == 0) {-		/* Early return. */-		return ARCHIVE_OK;-	}--	if(!read_var_sized(a, &extra_field_size, NULL)) {-		return ARCHIVE_EOF;-	}--	if(!read_var_sized(a, &extra_field_id, NULL)) {-		return ARCHIVE_EOF;-	}--	if(extra_field_size == 0) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Invalid extra field size");-		return ARCHIVE_FATAL;-	}--	switch(extra_field_id) {-		case LOCATOR:-			ret = process_main_locator_extra_block(a, rar);-			if(ret != ARCHIVE_OK) {-				/* Error while parsing main locator extra-				 * block. */-				return ret;-			}--			break;-		default:-			archive_set_error(&a->archive,-			    ARCHIVE_ERRNO_FILE_FORMAT,-			    "Unsupported extra type (0x%jx)",-			    (uintmax_t)extra_field_id);-			return ARCHIVE_FATAL;-	}--	return ARCHIVE_OK;-}--static int skip_unprocessed_bytes(struct archive_read* a) {-	struct rar5* rar = get_context(a);-	int ret;--	if(rar->file.bytes_remaining) {-		/* Use different skipping method in block merging mode than in-		 * normal mode. If merge mode is active, rar5_read_data_skip-		 * can't be used, because it could allow recursive use of-		 * merge_block() * function, and this function doesn't support-		 * recursive use. */-		if(rar->merge_mode) {-			/* Discard whole merged block. This is valid in solid-			 * mode as well, because the code will discard blocks-			 * only if those blocks are safe to discard (i.e.-			 * they're not FILE blocks).  */-			ret = consume(a, rar->file.bytes_remaining);-			if(ret != ARCHIVE_OK) {-				return ret;-			}-			rar->file.bytes_remaining = 0;-		} else {-			/* If we're not in merge mode, use safe skipping code.-			 * This will ensure we'll handle solid archives-			 * properly. */-			ret = rar5_read_data_skip(a);-			if(ret != ARCHIVE_OK) {-				return ret;-			}-		}-	}--	return ARCHIVE_OK;-}--static int scan_for_signature(struct archive_read* a);--/* Base block processing function. A 'base block' is a RARv5 header block- * that tells the reader what kind of data is stored inside the block.- *- * From the birds-eye view a RAR file looks file this:- *- * <magic><base_block_1><base_block_2>...<base_block_n>- *- * There are a few types of base blocks. Those types are specified inside- * the 'switch' statement in this function. For example purposes, I'll write- * how a standard RARv5 file could look like here:- *- * <magic><MAIN><FILE><FILE><FILE><SERVICE><ENDARC>- *- * The structure above could describe an archive file with 3 files in it,- * one service "QuickOpen" block (that is ignored by this parser), and an- * end of file base block marker.- *- * If the file is stored in multiple archive files ("multiarchive"), it might- * look like this:- *- * .part01.rar: <magic><MAIN><FILE><ENDARC>- * .part02.rar: <magic><MAIN><FILE><ENDARC>- * .part03.rar: <magic><MAIN><FILE><ENDARC>- *- * This example could describe 3 RAR files that contain ONE archived file.- * Or it could describe 3 RAR files that contain 3 different files. Or 3- * RAR files than contain 2 files. It all depends what metadata is stored in- * the headers of <FILE> blocks.- *- * Each <FILE> block contains info about its size, the name of the file it's- * storing inside, and whether this FILE block is a continuation block of- * previous archive ('split before'), and is this FILE block should be- * continued in another archive ('split after'). By parsing the 'split before'- * and 'split after' flags, we're able to tell if multiple <FILE> base blocks- * are describing one file, or multiple files (with the same filename, for- * example).- *- * One thing to note is that if we're parsing the first <FILE> block, and- * we see 'split after' flag, then we need to jump over to another <FILE>- * block to be able to decompress rest of the data. To do this, we need- * to skip the <ENDARC> block, then switch to another file, then skip the- * <magic> block, <MAIN> block, and then we're standing on the proper- * <FILE> block.- */--/*- * A header that carries no file data (HEAD_MAIN, or an unknown block- * flagged HFL_SKIP_IF_UNKNOWN) may leave bytes in its body that the- * sub-parser did not read. Skip them before returning ARCHIVE_RETRY,- * otherwise rar5_read_header() re-parses the same block region O(N)- * times instead of O(1), letting a crafted RAR5 file stall the reader- * (GHSA-9h2c-464f-j3hj).- *- * Safe because read_ahead(a, hdr_size, &p) pre-loaded the whole block- * into one contiguous buffer with no compaction until we return, so- * body_start stays valid and (cur - body_start) is the exact number of- * body bytes consumed so far.- */-static void-rar5_skip_remaining_block(struct archive_read* a,-    const uint8_t* body_start, size_t raw_hdr_size)-{-	const uint8_t* cur;--	if(read_ahead(a, 1, &cur)) {-		size_t body_used = (size_t)(cur - body_start);--		if(body_used < raw_hdr_size)-			(void)consume(a, raw_hdr_size - body_used);-	}-}--static int process_base_block(struct archive_read* a,-    struct archive_entry* entry)-{-	const size_t SMALLEST_RAR5_BLOCK_SIZE = 3;--	struct rar5* rar = get_context(a);-	uint32_t hdr_crc, computed_crc;-	size_t raw_hdr_size = 0, hdr_size_len, hdr_size;-	size_t header_id = 0;-	size_t header_flags = 0;-	const uint8_t* p;-	const uint8_t* body_start;-	int ret;--	enum HEADER_TYPE {-		HEAD_MARK    = 0x00, HEAD_MAIN  = 0x01, HEAD_FILE   = 0x02,-		HEAD_SERVICE = 0x03, HEAD_CRYPT = 0x04, HEAD_ENDARC = 0x05,-		HEAD_UNKNOWN = 0xff,-	};--	/* Skip any unprocessed data for this file. */-	ret = skip_unprocessed_bytes(a);-	if(ret != ARCHIVE_OK)-		return ret;--	/* Read the expected CRC32 checksum. */-	if(!read_u32(a, &hdr_crc)) {-		return ARCHIVE_EOF;-	}--	/* Read header size. */-	if(!read_var_sized(a, &raw_hdr_size, &hdr_size_len)) {-		return ARCHIVE_EOF;-	}--	hdr_size = raw_hdr_size + hdr_size_len;--	/* Sanity check, maximum header size for RAR5 is 2MB. */-	if(hdr_size > (2 * 1024 * 1024)) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Base block header is too large");--		return ARCHIVE_FATAL;-	}--	/* Additional sanity checks to weed out invalid files. */-	if(raw_hdr_size == 0 || hdr_size_len == 0 ||-		hdr_size < SMALLEST_RAR5_BLOCK_SIZE)-	{-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Too small block encountered (%zu bytes)",-		    raw_hdr_size);--		return ARCHIVE_FATAL;-	}--	/* Read the whole header data into memory, maximum memory use here is-	 * 2MB. */-	if(!read_ahead(a, hdr_size, &p)) {-		return ARCHIVE_EOF;-	}--	/* Verify the CRC32 of the header data. */-	computed_crc = (uint32_t) crc32(0, p, (int) hdr_size);-	if(computed_crc != hdr_crc) {-#ifndef DONT_FAIL_ON_CRC_ERROR-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Header CRC error");--		return ARCHIVE_FATAL;-#endif-	}--	/* Remember the first byte of the block body so we can later skip-	 * any bytes the sub-parser leaves unconsumed. */-	body_start = p + hdr_size_len;--	/* If the checksum is OK, we proceed with parsing. */-	if(ARCHIVE_OK != consume(a, hdr_size_len)) {-		return ARCHIVE_EOF;-	}--	if(!read_var_sized(a, &header_id, NULL))-		return ARCHIVE_EOF;--	if(!read_var_sized(a, &header_flags, NULL))-		return ARCHIVE_EOF;--	rar->generic.split_after = (header_flags & HFL_SPLIT_AFTER) > 0;-	rar->generic.split_before = (header_flags & HFL_SPLIT_BEFORE) > 0;-	rar->generic.size = (int)hdr_size;-	rar->generic.last_header_id = (int)header_id;-	rar->main.endarc = 0;--	/* Those are possible header ids in RARv5. */-	switch(header_id) {-		case HEAD_MAIN:-			ret = process_head_main(a, rar, entry, header_flags);--			/* Main header doesn't have any files in it, so it's-			 * pointless to return to the caller. Retry to next-			 * header, which should be HEAD_FILE/HEAD_SERVICE. */-			if(ret == ARCHIVE_OK) {-				rar5_skip_remaining_block(a, body_start,-				    raw_hdr_size);-				return ARCHIVE_RETRY;-			}--			return ret;-		case HEAD_SERVICE:-			ret = process_head_service(a, rar, entry, header_flags);-			return ret;-		case HEAD_FILE:-			ret = process_head_file(a, rar, entry, header_flags);-			return ret;-		case HEAD_CRYPT:-			archive_entry_set_is_metadata_encrypted(entry, 1);-			archive_entry_set_is_data_encrypted(entry, 1);-			rar->has_encrypted_entries = 1;-			rar->headers_are_encrypted = 1;-			archive_set_error(&a->archive,-			    ARCHIVE_ERRNO_FILE_FORMAT,-			    "Encryption is not supported");-			return ARCHIVE_FATAL;-		case HEAD_ENDARC:-			rar->main.endarc = 1;--			/* After encountering an end of file marker, we need-			 * to take into consideration if this archive is-			 * continued in another file (i.e. is it part01.rar:-			 * is there a part02.rar?) */-			if(rar->main.volume) {-				/* In case there is part02.rar, position the-				 * read pointer in a proper place, so we can-				 * resume parsing. */-				ret = scan_for_signature(a);-				if(ret == ARCHIVE_FATAL) {-					return ARCHIVE_EOF;-				} else {-					if(rar->vol.expected_vol_no ==-					    UINT_MAX) {-						archive_set_error(&a->archive,-						    ARCHIVE_ERRNO_FILE_FORMAT,-						    "Header error");-							return ARCHIVE_FATAL;-					}--					rar->vol.expected_vol_no =-					    rar->main.vol_no + 1;-					return ARCHIVE_OK;-				}-			} else {-				return ARCHIVE_EOF;-			}-		case HEAD_MARK:-			return ARCHIVE_EOF;-		default:-			if((header_flags & HFL_SKIP_IF_UNKNOWN) == 0) {-				archive_set_error(&a->archive,-				    ARCHIVE_ERRNO_FILE_FORMAT,-				    "Header type error");-				return ARCHIVE_FATAL;-			} else {-				/* If the block is marked as 'skip if unknown',-				 * do as the flag says: skip the block-				 * instead on failing on it. */-				rar5_skip_remaining_block(a, body_start,-				    raw_hdr_size);-				return ARCHIVE_RETRY;-			}-	}--#if !defined WIN32-	// Not reached.-	archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,-	    "Internal unpacker error");-	return ARCHIVE_FATAL;-#endif-}--static int skip_base_block(struct archive_read* a) {-	int ret;-	struct rar5* rar = get_context(a);--	/* Create a new local archive_entry structure that will be operated on-	 * by header reader; operations on this archive_entry will be discarded.-	 */-	struct archive_entry* entry = archive_entry_new();-	ret = process_base_block(a, entry);--	/* Discard operations on this archive_entry structure. */-	archive_entry_free(entry);-	if(ret == ARCHIVE_FATAL)-		return ret;--	if(rar->generic.last_header_id == 2 && rar->generic.split_before > 0)-		return ARCHIVE_OK;--	if(ret == ARCHIVE_OK)-		return ARCHIVE_RETRY;-	else-		return ret;-}--static int try_skip_sfx(struct archive_read *a)-{-	const char *p;--	if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)-		return ARCHIVE_EOF;--	if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0)-	{-		char signature[sizeof(rar5_signature_xor)];-		const void *h;-		const char *q;-		size_t skip, total = 0;-		ssize_t bytes, window = 4096;--		rar5_signature(signature);--		while (total + window <= (1024 * 512)) {-			h = __archive_read_ahead(a, window, &bytes);-			if (h == NULL) {-				/* Remaining bytes are less than window. */-				window >>= 1;-				if (window < 0x40)-					goto fatal;-				continue;-			}-			if (bytes < 0x40)-				goto fatal;-			p = h;-			q = p + bytes;--			/*-			 * Scan ahead until we find something that looks-			 * like the RAR header.-			 */-			while (p + 8 < q) {-				if (memcmp(p, signature, sizeof(signature)) == 0) {-					skip = p - (const char *)h;-					__archive_read_consume(a, skip);-					return (ARCHIVE_OK);-				}-				p += 0x10;-			}-			skip = p - (const char *)h;-			__archive_read_consume(a, skip);-			total += skip;-		}-	}--	return ARCHIVE_OK;-fatal:-	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-			"Couldn't find out RAR header");-	return (ARCHIVE_FATAL);-}--static int rar5_read_header(struct archive_read *a,-    struct archive_entry *entry)-{-	struct rar5* rar = get_context(a);-	int ret;--	/*-	 * It should be sufficient to call archive_read_next_header() for-	 * a reader to determine if an entry is encrypted or not.-	 */-	if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {-		rar->has_encrypted_entries = 0;-	}--	if(rar->header_initialized == 0) {-		init_header(a);-		if ((ret = try_skip_sfx(a)) < ARCHIVE_WARN)-			return ret;-		rar->header_initialized = 1;-	}--	if(rar->skipped_magic == 0) {-		if(ARCHIVE_OK != consume(a, sizeof(rar5_signature_xor))) {-			return ARCHIVE_EOF;-		}--		rar->skipped_magic = 1;-	}--	do {-		ret = process_base_block(a, entry);-	} while(ret == ARCHIVE_RETRY ||-			(rar->main.endarc > 0 && ret == ARCHIVE_OK));--	return ret;-}--static int init_unpack(struct rar5* rar) {-	rar->file.calculated_crc32 = 0;-	init_window_mask(rar);--	free(rar->cstate.window_buf);-	free(rar->cstate.filtered_buf);--	rar->cstate.window_buf = NULL;-	rar->cstate.filtered_buf = NULL;--	if(rar->cstate.window_size > 0) {-		rar->cstate.window_buf = calloc(1, rar->cstate.window_size);-		if(rar->cstate.window_buf == NULL)-			return ARCHIVE_FATAL;-		rar->cstate.filtered_buf = calloc(1, rar->cstate.window_size);-		if(rar->cstate.filtered_buf == NULL)-			return ARCHIVE_FATAL;-	}--	clear_data_ready_stack(rar);--	rar->cstate.write_ptr = 0;-	rar->cstate.last_write_ptr = 0;--	memset(&rar->cstate.bd, 0, sizeof(rar->cstate.bd));-	memset(&rar->cstate.ld, 0, sizeof(rar->cstate.ld));-	memset(&rar->cstate.dd, 0, sizeof(rar->cstate.dd));-	memset(&rar->cstate.ldd, 0, sizeof(rar->cstate.ldd));-	memset(&rar->cstate.rd, 0, sizeof(rar->cstate.rd));-	return ARCHIVE_OK;-}--static void update_crc(struct rar5* rar, const uint8_t* p, size_t to_read) {-    int verify_crc;--	if(rar->skip_mode) {-#if defined CHECK_CRC_ON_SOLID_SKIP-		verify_crc = 1;-#else-		verify_crc = 0;-#endif-	} else-		verify_crc = 1;--	if(verify_crc) {-		/* Don't update CRC32 if the file doesn't have the-		 * `stored_crc32` info filled in. */-		if(rar->file.stored_crc32 > 0) {-			rar->file.calculated_crc32 =-				crc32(rar->file.calculated_crc32, p, (unsigned int)to_read);-		}--		/* Check if the file uses an optional BLAKE2sp checksum-		 * algorithm. */-		if(rar->file.has_blake2 > 0) {-			/* Return value of the `update` function is always 0,-			 * so we can explicitly ignore it here. */-			(void) blake2sp_update(&rar->file.b2state, p, to_read);-		}-	}-}--static int create_decode_tables(uint8_t* bit_length,-    struct decode_table* table, int size)-{-	int code, upper_limit = 0, i, lc[16];-	uint32_t decode_pos_clone[rar5_countof(table->decode_pos)];-	ssize_t cur_len, quick_data_size;--	memset(&lc, 0, sizeof(lc));-	memset(table->decode_num, 0, sizeof(table->decode_num));-	table->size = size;-	table->quick_bits = size == HUFF_NC ? 10 : 7;--	for(i = 0; i < size; i++) {-		lc[bit_length[i] & 15]++;-	}--	lc[0] = 0;-	table->decode_pos[0] = 0;-	table->decode_len[0] = 0;--	for(i = 1; i < 16; i++) {-		upper_limit += lc[i];--		table->decode_len[i] = upper_limit << (16 - i);-		table->decode_pos[i] = table->decode_pos[i - 1] + lc[i - 1];--		upper_limit <<= 1;-	}--	/* Verify the code-length distribution is not over-subscribed.-	 * After the loop above, upper_limit == sum(lc[i] * 2^(16-i)).-	 * For a valid prefix-free code this must be <= 2^16 = 65536.-	 * An over-subscribed table (> 65536) cannot produce a valid-	 * decode table and must be rejected. */-	if(upper_limit > 65536) {-		return ARCHIVE_FAILED;-	}--	memcpy(decode_pos_clone, table->decode_pos, sizeof(decode_pos_clone));--	for(i = 0; i < size; i++) {-		uint8_t clen = bit_length[i] & 15;-		if(clen > 0) {-			int last_pos = decode_pos_clone[clen];-			table->decode_num[last_pos] = i;-			decode_pos_clone[clen]++;-		}-	}--	quick_data_size = (int64_t)1 << table->quick_bits;-	cur_len = 1;-	for(code = 0; code < quick_data_size; code++) {-		int bit_field = code << (16 - table->quick_bits);-		int dist, pos;--		while(cur_len < rar5_countof(table->decode_len) &&-				bit_field >= table->decode_len[cur_len]) {-			cur_len++;-		}--		table->quick_len[code] = (uint8_t) cur_len;--		dist = bit_field - table->decode_len[cur_len - 1];-		dist >>= (16 - cur_len);--		pos = table->decode_pos[cur_len & 15] + dist;-		if(cur_len < rar5_countof(table->decode_pos) && pos < size) {-			table->quick_num[code] = table->decode_num[pos];-		} else {-			table->quick_num[code] = 0;-		}-	}--	return ARCHIVE_OK;-}--static int decode_number(struct archive_read* a, struct decode_table* table,-    const uint8_t* p, uint16_t* num)-{-	int i, bits, dist, ret;-	uint16_t bitfield;-	uint32_t pos;-	struct rar5* rar = get_context(a);--	if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &bitfield))) {-		return ret;-	}--	bitfield &= 0xfffe;--	if(bitfield < table->decode_len[table->quick_bits]) {-		int code = bitfield >> (16 - table->quick_bits);-		skip_bits(rar, table->quick_len[code]);-		*num = table->quick_num[code];-		return ARCHIVE_OK;-	}--	bits = 15;--	for(i = table->quick_bits + 1; i < 15; i++) {-		if(bitfield < table->decode_len[i]) {-			bits = i;-			break;-		}-	}--	skip_bits(rar, bits);--	dist = bitfield - table->decode_len[bits - 1];-	dist >>= (16 - bits);-	pos = table->decode_pos[bits] + dist;--	if(pos >= table->size)-		pos = 0;--	*num = table->decode_num[pos];-	return ARCHIVE_OK;-}--/* Reads and parses Huffman tables from the beginning of the block. */-static int parse_tables(struct archive_read* a, struct rar5* rar,-    const uint8_t* p)-{-	int ret, value, i, w, idx = 0;-	uint8_t bit_length[HUFF_BC],-		table[HUFF_TABLE_SIZE],-		nibble_mask = 0xF0,-		nibble_shift = 4;--	enum { ESCAPE = 15 };--	/* The data for table generation is compressed using a simple RLE-like-	 * algorithm when storing zeroes, so we need to unpack it first. */-	for(w = 0, i = 0; w < HUFF_BC;) {-		if(i >= rar->cstate.cur_block_size) {-			/* Truncated data, can't continue. */-			archive_set_error(&a->archive,-			    ARCHIVE_ERRNO_FILE_FORMAT,-			    "Truncated data in huffman tables");-			return ARCHIVE_FAILED;-		}--		value = (p[i] & nibble_mask) >> nibble_shift;--		if(nibble_mask == 0x0F)-			++i;--		nibble_mask ^= 0xFF;-		nibble_shift ^= 4;--		/* Values smaller than 15 is data, so we write it directly.-		 * Value 15 is a flag telling us that we need to unpack more-		 * bytes. */-		if(value == ESCAPE) {-			value = (p[i] & nibble_mask) >> nibble_shift;-			if(nibble_mask == 0x0F)-				++i;-			nibble_mask ^= 0xFF;-			nibble_shift ^= 4;--			if(value == 0) {-				/* We sometimes need to write the actual value-				 * of 15, so this case handles that. */-				bit_length[w++] = ESCAPE;-			} else {-				int k;--				/* Fill zeroes. */-				for(k = 0; (k < value + 2) && (w < HUFF_BC);-				    k++) {-					bit_length[w++] = 0;-				}-			}-		} else {-			bit_length[w++] = value;-		}-	}--	rar->bits.in_addr = i;-	rar->bits.bit_addr = nibble_shift ^ 4;--	ret = create_decode_tables(bit_length, &rar->cstate.bd, HUFF_BC);-	if(ret != ARCHIVE_OK) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Decoding huffman tables failed");-		return ARCHIVE_FAILED;-	}--	for(i = 0; i < HUFF_TABLE_SIZE;) {-		uint16_t num;--		ret = decode_number(a, &rar->cstate.bd, p, &num);-		if(ret != ARCHIVE_OK) {-			archive_set_error(&a->archive,-			    ARCHIVE_ERRNO_FILE_FORMAT,-			    "Decoding huffman tables failed");-			return ARCHIVE_FAILED;-		}--		if(num < 16) {-			/* 0..15: store directly */-			table[i] = (uint8_t) num;-			i++;-		} else if(num < 18) {-			/* 16..17: repeat previous code */-			uint16_t n;--			if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))-				return ret;--			if(num == 16) {-				n >>= 13;-				n += 3;-				skip_bits(rar, 3);-			} else {-				n >>= 9;-				n += 11;-				skip_bits(rar, 7);-			}--			if(i > 0) {-				while(n-- > 0 && i < HUFF_TABLE_SIZE) {-					table[i] = table[i - 1];-					i++;-				}-			} else {-				archive_set_error(&a->archive,-				    ARCHIVE_ERRNO_FILE_FORMAT,-				    "Unexpected error when decoding "-				    "huffman tables");-				return ARCHIVE_FAILED;-			}-		} else {-			/* other codes: fill with zeroes `n` times */-			uint16_t n;--			if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))-				return ret;--			if(num == 18) {-				n >>= 13;-				n += 3;-				skip_bits(rar, 3);-			} else {-				n >>= 9;-				n += 11;-				skip_bits(rar, 7);-			}--			while(n-- > 0 && i < HUFF_TABLE_SIZE)-				table[i++] = 0;-		}-	}--	ret = create_decode_tables(&table[idx], &rar->cstate.ld, HUFF_NC);-	if(ret != ARCHIVE_OK) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		     "Failed to create literal table");-		return ARCHIVE_FAILED;-	}--	idx += HUFF_NC;--	ret = create_decode_tables(&table[idx], &rar->cstate.dd, HUFF_DC);-	if(ret != ARCHIVE_OK) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Failed to create distance table");-		return ARCHIVE_FAILED;-	}--	idx += HUFF_DC;--	ret = create_decode_tables(&table[idx], &rar->cstate.ldd, HUFF_LDC);-	if(ret != ARCHIVE_OK) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Failed to create lower bits of distances table");-		return ARCHIVE_FAILED;-	}--	idx += HUFF_LDC;--	ret = create_decode_tables(&table[idx], &rar->cstate.rd, HUFF_RC);-	if(ret != ARCHIVE_OK) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Failed to create repeating distances table");-		return ARCHIVE_FAILED;-	}--	return ARCHIVE_OK;-}--/* Parses the block header, verifies its CRC byte, and saves the header- * fields inside the `hdr` pointer. */-static int parse_block_header(struct archive_read* a, const uint8_t* p,-    ssize_t* block_size, struct compressed_block_header* hdr)-{-	uint8_t calculated_cksum;-	memcpy(hdr, p, sizeof(struct compressed_block_header));--	if(bf_byte_count(hdr) > 2) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Unsupported block header size (was %d, max is 2)",-		    bf_byte_count(hdr));-		return ARCHIVE_FAILED;-	}--	/* This should probably use bit reader interface in order to be more-	 * future-proof. */-	*block_size = 0;-	switch(bf_byte_count(hdr)) {-		/* 1-byte block size */-		case 0:-			*block_size = *(const uint8_t*) &p[2];-			break;--		/* 2-byte block size */-		case 1:-			*block_size = archive_le16dec(&p[2]);-			break;--		/* 3-byte block size */-		case 2:-			*block_size = archive_le32dec(&p[2]);-			*block_size &= 0x00FFFFFF;-			break;--		/* Other block sizes are not supported. This case is not-		 * reached, because we have an 'if' guard before the switch-		 * that makes sure of it. */-		default:-			return ARCHIVE_FATAL;-	}--	/* Verify the block header checksum. 0x5A is a magic value and is-	 * always * constant. */-	calculated_cksum = 0x5A-	    ^ (uint8_t) hdr->block_flags_u8-	    ^ (uint8_t) *block_size-	    ^ (uint8_t) (*block_size >> 8)-	    ^ (uint8_t) (*block_size >> 16);--	if(calculated_cksum != hdr->block_cksum) {-#ifndef DONT_FAIL_ON_CRC_ERROR-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Block checksum error: got 0x%x, expected 0x%x",-		    hdr->block_cksum, calculated_cksum);--		return ARCHIVE_FAILED;-#endif-	}--	return ARCHIVE_OK;-}--/* Convenience function used during filter processing. */-static int parse_filter_data(struct archive_read* a, struct rar5* rar,-	const uint8_t* p, uint32_t* filter_data)-{-	int i, bytes, ret;-	uint32_t data = 0;--	if(ARCHIVE_OK != (ret = read_consume_bits(a, rar, p, 2, &bytes)))-		return ret;--	bytes++;--	for(i = 0; i < bytes; i++) {-		uint16_t byte;--		if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &byte))) {-			return ret;-		}--		/* Cast to uint32_t will ensure the shift operation will not-		 * produce undefined result. */-		data += ((uint32_t) byte >> 8) << (i * 8);-		skip_bits(rar, 8);-	}--	*filter_data = data;-	return ARCHIVE_OK;-}--/* Function is used during sanity checking. */-static int is_valid_filter_block_start(struct rar5* rar,-    uint32_t start)-{-	const int64_t block_start = (ssize_t) start + rar->cstate.write_ptr;-	const int64_t last_bs = rar->cstate.last_block_start;-	const ssize_t last_bl = rar->cstate.last_block_length;--	if(last_bs == 0 || last_bl == 0) {-		/* We didn't have any filters yet, so accept this offset. */-		return 1;-	}--	if(block_start >= last_bs + last_bl) {-		/* Current offset is bigger than last block's end offset, so-		 * accept current offset. */-		return 1;-	}--	/* Any other case is not a normal situation and we should fail. */-	return 0;-}--/* The function will create a new filter, read its parameters from the input- * stream and add it to the filter collection. */-static int parse_filter(struct archive_read* ar, const uint8_t* p) {-	uint32_t block_start, block_length;-	uint16_t filter_type;-	struct filter_info* filt = NULL;-	struct rar5* rar = get_context(ar);-	int ret;--	/* Read the parameters from the input stream. */-	if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_start)))-		return ret;--	if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_length)))-		return ret;--	if(ARCHIVE_OK != (ret = read_bits_16(ar, rar, p, &filter_type)))-		return ret;--	filter_type >>= 13;-	skip_bits(rar, 3);--	/* Perform some sanity checks on this filter parameters. */--	if(block_length < 4 ||-	    block_length > 0x400000 ||-	    !is_valid_filter_block_start(rar, block_start) ||-	    (rar->cstate.window_size > 0 &&-	     (ssize_t)block_length > rar->cstate.window_size >> 1))-	{-		archive_set_error(&ar->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Invalid filter encountered");-		return ARCHIVE_FAILED;-	}--	/* Allocate a new filter. */-	filt = add_new_filter(rar);-	if(filt == NULL) {-		archive_set_error(&ar->archive, ENOMEM,-		    "Can't allocate memory for a filter descriptor");-		return ARCHIVE_FATAL;-	}--	filt->type = filter_type;-	filt->block_start = rar->cstate.write_ptr + block_start;-	filt->block_length = block_length;--	rar->cstate.last_block_start = filt->block_start;-	rar->cstate.last_block_length = filt->block_length;--	/* Read some more data in case this is a DELTA filter. Other filter-	 * types don't require any additional data over what was already-	 * read. */-	if(filter_type == FILTER_DELTA) {-		int channels;--		if(ARCHIVE_OK != (ret = read_consume_bits(ar, rar, p, 5, &channels)))-			return ret;--		filt->channels = channels + 1;-	}--	return ARCHIVE_OK;-}--static int decode_code_length(struct archive_read* a, struct rar5* rar,-	const uint8_t* p, uint16_t code)-{-	int lbits, length = 2;--	if(code < 8) {-		lbits = 0;-		length += code;-	} else {-		lbits = code / 4 - 1;-		length += (4 | (code & 3)) << lbits;-	}--	if(lbits > 0) {-		int add;--		if(ARCHIVE_OK != read_consume_bits(a, rar, p, lbits, &add))-			return -1;--		length += add;-	}--	return length;-}--static int copy_string(struct archive_read* a, int len, int dist) {-	struct rar5* rar = get_context(a);-	const ssize_t cmask = rar->cstate.window_mask;-	const uint64_t write_ptr = rar->cstate.write_ptr +-	    rar->cstate.solid_offset;-	int i;--	if (rar->cstate.window_buf == NULL)-		return ARCHIVE_FATAL;--	/* The unpacker spends most of the time in this function. It would be-	 * a good idea to introduce some optimizations here.-	 *-	 * Just remember that this loop treats buffers that overlap differently-	 * than buffers that do not overlap. This is why a simple memcpy(3)-	 * call will not be enough. */--	for(i = 0; i < len; i++) {-		const ssize_t write_idx = (write_ptr + i) & cmask;-		const ssize_t read_idx = (write_ptr + i - dist) & cmask;-		rar->cstate.window_buf[write_idx] =-		    rar->cstate.window_buf[read_idx];-	}--	rar->cstate.write_ptr += len;-	return ARCHIVE_OK;-}--static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {-	struct rar5* rar = get_context(a);-	uint16_t num;-	int ret;--	const uint64_t cmask = rar->cstate.window_mask;-	const struct compressed_block_header* hdr = &rar->last_block_hdr;-	const uint8_t bit_size = 1 + bf_bit_size(hdr);--	while(1) {-		if(rar->cstate.write_ptr - rar->cstate.last_write_ptr >-		    (rar->cstate.window_size >> 1)) {-			/* Don't allow growing data by more than half of the-			 * window size at a time. In such case, break the loop;-			 *  next call to this function will continue processing-			 *  from this moment. */-			break;-		}--		if(rar->bits.in_addr > rar->cstate.cur_block_size - 1 ||-		    (rar->bits.in_addr == rar->cstate.cur_block_size - 1 &&-		    rar->bits.bit_addr >= bit_size))-		{-			/* If the program counter is here, it means the-			 * function has finished processing the block. */-			rar->cstate.block_parsing_finished = 1;-			break;-		}--		/* Decode the next literal. */-		if(ARCHIVE_OK != decode_number(a, &rar->cstate.ld, p, &num)) {-			return ARCHIVE_EOF;-		}--		/* Num holds a decompression literal, or 'command code'.-		 *-		 * - Values lower than 256 are just bytes. Those codes-		 *   can be stored in the output buffer directly.-		 *-		 * - Code 256 defines a new filter, which is later used to-		 *   transform the data block accordingly to the filter type.-		 *   The data block needs to be fully uncompressed first.-		 *-		 * - Code bigger than 257 and smaller than 262 define-		 *   a repetition pattern that should be copied from-		 *   an already uncompressed chunk of data.-		 */--		if(num < 256) {-			/* Directly store the byte. */-			int64_t write_idx = rar->cstate.solid_offset +-			    rar->cstate.write_ptr++;--			rar->cstate.window_buf[write_idx & cmask] =-			    (uint8_t) num;-			continue;-		} else if(num >= 262) {-			uint16_t dist_slot;-			int len = decode_code_length(a, rar, p, num - 262),-				dbits,-				dist = 1;--			if(len == -1) {-				archive_set_error(&a->archive,-				    ARCHIVE_ERRNO_PROGRAMMER,-				    "Failed to decode the code length");--				return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;-			}--			if(ARCHIVE_OK != decode_number(a, &rar->cstate.dd, p,-			    &dist_slot))-			{-				archive_set_error(&a->archive,-				    ARCHIVE_ERRNO_PROGRAMMER,-				    "Failed to decode the distance slot");--				return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;-			}--			if(dist_slot < 4) {-				dbits = 0;-				dist += dist_slot;-			} else {-				dbits = dist_slot / 2 - 1;--				/* Cast to uint32_t will make sure the shift-				 * left operation won't produce undefined-				 * result. Then, the uint32_t type will-				 * be implicitly casted to int. */-				dist += (uint32_t) (2 |-				    (dist_slot & 1)) << dbits;-			}--			if(dbits > 0) {-				if(dbits >= 4) {-					uint32_t add = 0;-					uint16_t low_dist;--					if(dbits > 4) {-						if(ARCHIVE_OK != (ret = read_bits_32(-						    a, rar, p, &add))) {-							/* Return EOF if we-							 * can't read more-							 * data. */-							return ret;-						}--						skip_bits(rar, dbits - 4);-						add = (add >> (-						    36 - dbits)) << 4;-						dist += add;-					}--					if(ARCHIVE_OK != decode_number(a,-					    &rar->cstate.ldd, p, &low_dist))-					{-						archive_set_error(&a->archive,-						    ARCHIVE_ERRNO_PROGRAMMER,-						    "Failed to decode the "-						    "distance slot");--						return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;-					}--					if(dist >= INT_MAX - low_dist - 1) {-						/* This only happens in-						 * invalid archives. */-						archive_set_error(&a->archive,-						    ARCHIVE_ERRNO_FILE_FORMAT,-						    "Distance pointer "-						    "overflow");-						return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;-					}--					dist += low_dist;-				} else {-					/* dbits is one of [0,1,2,3] */-					int add;--					if(ARCHIVE_OK != (ret = read_consume_bits(a, rar,-					     p, dbits, &add))) {-						/* Return EOF if we can't read-						 * more data. */-						return ret;-					}--					dist += add;-				}-			}--			if(dist > 0x100) {-				len++;--				if(dist > 0x2000) {-					len++;--					if(dist > 0x40000) {-						len++;-					}-				}-			}--			dist_cache_push(rar, dist);-			rar->cstate.last_len = len;--			if(ARCHIVE_OK != copy_string(a, len, dist))-				return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;--			continue;-		} else if(num == 256) {-			/* Create a filter. */-			ret = parse_filter(a, p);-			if(ret != ARCHIVE_OK)-				return ret;--			continue;-		} else if(num == 257) {-			if(rar->cstate.last_len != 0) {-				if(ARCHIVE_OK != copy_string(a,-				    rar->cstate.last_len,-				    rar->cstate.dist_cache[0]))-				{-					return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;-				}-			}--			continue;-		} else {-			/* num < 262 */-			const int idx = num - 258;-			const int dist = dist_cache_touch(rar, idx);--			uint16_t len_slot;-			int len;--			if(ARCHIVE_OK != decode_number(a, &rar->cstate.rd, p,-			    &len_slot)) {-				return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;-			}--			len = decode_code_length(a, rar, p, len_slot);-			if (len == -1) {-				return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;-			}--			rar->cstate.last_len = len;--			if(ARCHIVE_OK != copy_string(a, len, dist))-				return rar->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;--			continue;-		}-	}--	return ARCHIVE_OK;-}--/* Binary search for the RARv5 signature. */-static int scan_for_signature(struct archive_read* a) {-	const uint8_t* p;-	const int chunk_size = 512;-	ssize_t i;-	char signature[sizeof(rar5_signature_xor)];--	/* If we're here, it means we're on an 'unknown territory' data.-	 * There's no indication what kind of data we're reading here.-	 * It could be some text comment, any kind of binary data,-	 * digital sign, dragons, etc.-	 *-	 * We want to find a valid RARv5 magic header inside this unknown-	 * data. */--	/* Is it possible in libarchive to just skip everything until the-	 * end of the file? If so, it would be a better approach than the-	 * current implementation of this function. */--	rar5_signature(signature);--	while(1) {-		if(!read_ahead(a, chunk_size, &p))-			return ARCHIVE_EOF;--		for(i = 0; i < chunk_size - (int)sizeof(rar5_signature_xor);-		    i++) {-			if(memcmp(&p[i], signature,-			    sizeof(rar5_signature_xor)) == 0) {-				/* Consume the number of bytes we've used to-				 * search for the signature, as well as the-				 * number of bytes used by the signature-				 * itself. After this we should be standing-				 * on a valid base block header. */-				(void) consume(a,-				    i + sizeof(rar5_signature_xor));-				return ARCHIVE_OK;-			}-		}--		consume(a, chunk_size);-	}--	return ARCHIVE_FATAL;-}--/* This function will switch the multivolume archive file to another file,- * i.e. from part03 to part 04. */-static int advance_multivolume(struct archive_read* a) {-	int lret;-	struct rar5* rar = get_context(a);--	/* A small state machine that will skip unnecessary data, needed to-	 * switch from one multivolume to another. Such skipping is needed if-	 * we want to be an stream-oriented (instead of file-oriented)-	 * unpacker.-	 *-	 * The state machine starts with `rar->main.endarc` == 0. It also-	 * assumes that current stream pointer points to some base block-	 * header.-	 *-	 * The `endarc` field is being set when the base block parsing-	 * function encounters the 'end of archive' marker.-	 */--	while(1) {-		if(rar->main.endarc == 1) {-			int looping = 1;--			rar->main.endarc = 0;--			while(looping) {-				lret = skip_base_block(a);-				switch(lret) {-					case ARCHIVE_RETRY:-						/* Continue looping. */-						break;-					case ARCHIVE_OK:-						/* Break loop. */-						looping = 0;-						break;-					default:-						/* Forward any errors to the-						 * caller. */-						return lret;-				}-			}--			break;-		} else {-			/* Skip current base block. In order to properly skip-			 * it, we really need to simply parse it and discard-			 * the results. */--			lret = skip_base_block(a);-			if(lret == ARCHIVE_FATAL || lret == ARCHIVE_FAILED)-				return lret;--			/* The `skip_base_block` function tells us if we-			 * should continue with skipping, or we should stop-			 * skipping. We're trying to skip everything up to-			 * a base FILE block. */--			if(lret != ARCHIVE_RETRY) {-				/* If there was an error during skipping, or we-				 * have just skipped a FILE base block... */--				if(rar->main.endarc == 0) {-					return lret;-				} else {-					continue;-				}-			}-		}-	}--	return ARCHIVE_OK;-}--/* Merges the partial block from the first multivolume archive file, and- * partial block from the second multivolume archive file. The result is- * a chunk of memory containing the whole block, and the stream pointer- * is advanced to the next block in the second multivolume archive file. */-static int merge_block(struct archive_read* a, ssize_t block_size,-    const uint8_t** p)-{-	struct rar5* rar = get_context(a);-	ssize_t cur_block_size, partial_offset = 0;-	const uint8_t* lp;-	int ret;--	if(rar->merge_mode) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,-		    "Recursive merge is not allowed");--		return ARCHIVE_FATAL;-	}--	/* Set a flag that we're in the switching mode. */-	rar->cstate.switch_multivolume = 1;--	/* Reallocate the memory which will hold the whole block. */-	if(rar->vol.push_buf)-		free((void*) rar->vol.push_buf);--	/* Increasing the allocation block by 8 is due to bit reading functions,-	 * which are using additional 2 or 4 bytes. Allocating the block size-	 * by exact value would make bit reader perform reads from invalid-	 * memory block when reading the last byte from the buffer. */-	rar->vol.push_buf = malloc(block_size + 8);-	if(!rar->vol.push_buf) {-		archive_set_error(&a->archive, ENOMEM,-		    "Can't allocate memory for a merge block buffer");-		rar->cstate.switch_multivolume = 0;-		return ARCHIVE_FATAL;-	}--	/* Valgrind complains if the extension block for bit reader is not-	 * initialized, so initialize it. */-	memset(&rar->vol.push_buf[block_size], 0, 8);--	/* A single block can span across multiple multivolume archive files,-	 * so we use a loop here. This loop will consume enough multivolume-	 * archive files until the whole block is read. */--	while(1) {-		/* Get the size of current block chunk in this multivolume-		 * archive file and read it. */-		cur_block_size = rar5_min(rar->file.bytes_remaining,-		    block_size - partial_offset);--		if(cur_block_size < 1) {-			/* bytes_remaining is less than 1 at the wrong point in-			 * the merge loop, indicating corrupt volume-			 * accounting. */-			archive_set_error(&a->archive,-			    ARCHIVE_ERRNO_FILE_FORMAT,-			    "Encountered invalid block size during block merge");-			rar->cstate.switch_multivolume = 0;-			return ARCHIVE_FATAL;-		}--		if(!read_ahead(a, cur_block_size, &lp)) {-			rar->cstate.switch_multivolume = 0;-			return ARCHIVE_EOF;-		}--		/* Sanity check; there should never be a situation where this-		 * function reads more data than the block's size. */-		if(partial_offset + cur_block_size > block_size) {-			archive_set_error(&a->archive,-			    ARCHIVE_ERRNO_PROGRAMMER,-			    "Consumed too much data when merging blocks");-			rar->cstate.switch_multivolume = 0;-			return ARCHIVE_FATAL;-		}--		/* Merge previous block chunk with current block chunk,-		 * or create first block chunk if this is our first-		 * iteration. */-		memcpy(&rar->vol.push_buf[partial_offset], lp, cur_block_size);--		/* Advance the stream read pointer by this block chunk size. */-		if(ARCHIVE_OK != consume(a, cur_block_size)) {-			/* Data was copied but stream pointer didn't advance;-			 * stream position is unrecoverable. */-			rar->cstate.switch_multivolume = 0;-			return ARCHIVE_FATAL;-		}--		/* Update the pointers. `partial_offset` contains information-		 * about the sum of merged block chunks. */-		partial_offset += cur_block_size;-		rar->file.bytes_remaining -= cur_block_size;--		/* If `partial_offset` is the same as `block_size`, this means-		 * we've merged all block chunks and we have a valid full-		 * block. */-		if(partial_offset == block_size) {-			break;-		}--		/* If we don't have any bytes to read, this means we should-		 * switch to another multivolume archive file. */-		if(rar->file.bytes_remaining == 0) {-			rar->merge_mode++;-			ret = advance_multivolume(a);-			rar->merge_mode--;-			if(ret != ARCHIVE_OK) {-				rar->cstate.switch_multivolume = 0;-				return ret;-			}-		}-	}--	*p = rar->vol.push_buf;--	/* If we're here, we can resume unpacking by processing the block-	 * pointed to by the `*p` memory pointer. */--	return ARCHIVE_OK;-}--static int process_block(struct archive_read* a) {-	const uint8_t* p;-	struct rar5* rar = get_context(a);-	int ret;--	/* If we don't have any data to be processed, this most probably means-	 * we need to switch to the next volume. */-	if(rar->main.volume && rar->file.bytes_remaining == 0) {-		ret = advance_multivolume(a);-		if(ret != ARCHIVE_OK)-			return ret;-	}--	if(rar->cstate.block_parsing_finished) {-		ssize_t block_size;-		ssize_t to_skip;-		ssize_t cur_block_size;--		/* The header size won't be bigger than 6 bytes. */-		if(!read_ahead(a, 6, &p)) {-			/* Failed to prefetch data block header. */-			return ARCHIVE_EOF;-		}--		/*-		 * Read block_size by parsing block header. Validate the header-		 * by calculating CRC byte stored inside the header. Size of-		 * the header is not constant (block size can be stored either-		 * in 1 or 2 bytes), that's why block size is left out from the-		 * `compressed_block_header` structure and returned by-		 * `parse_block_header` as the second argument. */--		ret = parse_block_header(a, p, &block_size,-		    &rar->last_block_hdr);-		if(ret != ARCHIVE_OK) {-			return ret;-		}--		/* Skip block header. Next data is huffman tables,-		 * if present. */-		to_skip = sizeof(struct compressed_block_header) +-			bf_byte_count(&rar->last_block_hdr) + 1;--		/* If the block header's to_skip value exceeds the declared-		 * remaining data, the archive is malformed. */-		if(to_skip > rar->file.bytes_remaining) {-			archive_set_error(&a->archive,-			    ARCHIVE_ERRNO_FILE_FORMAT,-			    "Block header size exceeds remaining file data");-			return ARCHIVE_FATAL;-		}--		if(ARCHIVE_OK != consume(a, to_skip))-			return ARCHIVE_EOF;--		rar->file.bytes_remaining -= to_skip;--		/* The block size gives information about the whole block size,-		 * but the block could be stored in split form when using-		 * multi-volume archives. In this case, the block size will be-		 * bigger than the actual data stored in this file. Remaining-		 * part of the data will be in another file. */--		cur_block_size =-			rar5_min(rar->file.bytes_remaining, block_size);--		if(block_size > rar->file.bytes_remaining) {-			/* If current blocks' size is bigger than our data-			 * size, this means we have a multivolume archive.-			 * In this case, skip all base headers until the end-			 * of the file, proceed to next "partXXX.rar" volume,-			 * find its signature, skip all headers up to the first-			 * FILE base header, and continue from there.-			 *-			 * Note that `merge_block` will update the `rar`-			 * context structure quite extensively. */--			ret = merge_block(a, block_size, &p);-			if(ret != ARCHIVE_OK) {-				return ret;-			}--			cur_block_size = block_size;--			/* Current stream pointer should be now directly-			 * *after* the block that spanned through multiple-			 * archive files. `p` pointer should have the data of-			 * the *whole* block (merged from partial blocks-			 * stored in multiple archives files). */-		} else {-			rar->cstate.switch_multivolume = 0;--			/* Read the whole block size into memory. This can take-			 * up to  8 megabytes of memory in theoretical cases.-			 * Might be worth to optimize this and use a standard-			 * chunk of 4kb's. */-			if(!read_ahead(a, 4 + cur_block_size, &p)) {-				/* Failed to prefetch block data. */-				return ARCHIVE_EOF;-			}-		}--		rar->cstate.block_buf = p;-		rar->cstate.cur_block_size = cur_block_size;-		rar->cstate.block_parsing_finished = 0;--		rar->bits.in_addr = 0;-		rar->bits.bit_addr = 0;--		if(bf_is_table_present(&rar->last_block_hdr)) {-			/* Load Huffman tables. */-			ret = parse_tables(a, rar, p);-			if(ret != ARCHIVE_OK) {-				/* Error during decompression of Huffman-				 * tables. */-				return ret;-			}-		}-	} else {-		/* Block parsing not finished, reuse previous memory buffer. */-		p = rar->cstate.block_buf;-	}--	/* Uncompress the block, or a part of it, depending on how many bytes-	 * will be generated by uncompressing the block.-	 *-	 * In case too many bytes will be generated, calling this function-	 * again will resume the uncompression operation. */-	ret = do_uncompress_block(a, p);-	if(ret != ARCHIVE_OK) {-		return ret;-	}--	if(rar->cstate.block_parsing_finished &&-	    rar->cstate.switch_multivolume == 0 &&-	    rar->cstate.cur_block_size > 0)-	{-		/* If we're processing a normal block, consume the whole-		 * block. We can do this because we've already read the whole-		 * block to memory. */-		if(ARCHIVE_OK != consume(a, rar->cstate.cur_block_size))-			return ARCHIVE_FATAL;--		rar->file.bytes_remaining -= rar->cstate.cur_block_size;-	} else if(rar->cstate.switch_multivolume) {-		/* Don't consume the block if we're doing multivolume-		 * processing. The volume switching function will consume-		 * the proper count of bytes instead. */-		rar->cstate.switch_multivolume = 0;-	}--	return ARCHIVE_OK;-}--/* Pops the `buf`, `size` and `offset` from the "data ready" stack.- *- * Returns ARCHIVE_OK when those arguments can be used, ARCHIVE_RETRY- * when there is no data on the stack. */-static int use_data(struct rar5* rar, const void** buf, size_t* size,-    int64_t* offset)-{-	int i;--	for(i = 0; i < rar5_countof(rar->cstate.dready); i++) {-		struct data_ready *d = &rar->cstate.dready[i];--		if(d->used) {-			if(buf)    *buf = d->buf;-			if(size)   *size = d->size;-			if(offset) *offset = d->offset;--			d->used = 0;-			return ARCHIVE_OK;-		}-	}--	return ARCHIVE_RETRY;-}--static void clear_data_ready_stack(struct rar5* rar) {-	memset(&rar->cstate.dready, 0, sizeof(rar->cstate.dready));-}--/* Pushes the `buf`, `size` and `offset` arguments to the rar->cstate.dready- * FIFO stack. Those values will be popped from this stack by the `use_data`- * function. */-static int push_data_ready(struct archive_read* a, struct rar5* rar,-    const uint8_t* buf, size_t size, int64_t offset)-{-	int i;--	/* Don't push if we're in skip mode. This is needed because solid-	 * streams need full processing even if we're skipping data. After-	 * fully processing the stream, we need to discard the generated bytes,-	 * because we're interested only in the side effect: building up the-	 * internal window circular buffer. This window buffer will be used-	 * later during unpacking of requested data. */-	if(rar->skip_mode)-		return ARCHIVE_OK;--	/* Sanity check. */-	if(offset != rar->file.last_offset + rar->file.last_size) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,-		    "Sanity check error: output stream is not continuous");-		return ARCHIVE_FATAL;-	}--	for(i = 0; i < rar5_countof(rar->cstate.dready); i++) {-		struct data_ready* d = &rar->cstate.dready[i];-		if(!d->used) {-			d->used = 1;-			d->buf = buf;-			d->size = size;-			d->offset = offset;--			/* These fields are used only in sanity checking. */-			rar->file.last_offset = offset;-			rar->file.last_size = size;--			/* Calculate the checksum of this new block before-			 * submitting data to libarchive's engine. */-			update_crc(rar, d->buf, d->size);--			return ARCHIVE_OK;-		}-	}--	/* Program counter will reach this code if the `rar->cstate.data_ready`-	 * stack will be filled up so that no new entries will be allowed. The-	 * code shouldn't allow such situation to occur. So we treat this case-	 * as an internal error. */--	archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,-	    "Premature end of data_ready stack");-	return ARCHIVE_FATAL;-}--/* This function uncompresses the data that is stored in the <FILE> base- * block.- *- * The FILE base block looks like this:- *- * <header><huffman tables><block_1><block_2>...<block_n>- *- * The <header> is a block header, that is parsed in parse_block_header().- * It's a "compressed_block_header" structure, containing metadata needed- * to know when we should stop looking for more <block_n> blocks.- *- * <huffman tables> contain data needed to set up the huffman tables, needed- * for the actual decompression.- *- * Each <block_n> consists of series of literals:- *- * <literal><literal><literal>...<literal>- *- * Those literals generate the uncompression data. They operate on a circular- * buffer, sometimes writing raw data into it, sometimes referencing- * some previous data inside this buffer, and sometimes declaring a filter- * that will need to be executed on the data stored in the circular buffer.- * It all depends on the literal that is used.- *- * Sometimes blocks produce output data, sometimes they don't. For example, for- * some huge files that use lots of filters, sometimes a block is filled with- * only filter declaration literals. Such blocks won't produce any data in the- * circular buffer.- *- * Sometimes blocks will produce 4 bytes of data, and sometimes 1 megabyte,- * because a literal can reference previously decompressed data. For example,- * there can be a literal that says: 'append a byte 0xFE here', and after- * it another literal can say 'append 1 megabyte of data from circular buffer- * offset 0x12345'. This is how RAR format handles compressing repeated- * patterns.- *- * The RAR compressor creates those literals and the actual efficiency of- * compression depends on what those literals are. The literals can also- * be seen as a kind of a non-turing-complete virtual machine that simply- * tells the decompressor what it should do.- * */--static int do_uncompress_file(struct archive_read* a) {-	struct rar5* rar = get_context(a);-	int ret;-	int64_t max_end_pos;--	if(!rar->cstate.initialized) {-		/* Don't perform full context reinitialization if we're-		 * processing a solid archive. */-		if(!rar->main.solid || !rar->cstate.window_buf) {-			if((ret = init_unpack(rar)) != ARCHIVE_OK)-				return ret;-		}--		rar->cstate.initialized = 1;-	}--	/* Don't allow extraction if window_size is invalid. */-	if(rar->cstate.window_size == 0) {-		archive_set_error(&a->archive,-			ARCHIVE_ERRNO_FILE_FORMAT,-			"Invalid window size declaration in this file");--		/* This should never happen in valid files. */-		return ARCHIVE_FAILED;-	}--	if(rar->cstate.all_filters_applied == 1) {-		/* We use while(1) here, but standard case allows for just 1-		 * iteration. The loop will iterate if process_block() didn't-		 * generate any data at all. This can happen if the block-		 * contains only filter definitions (this is common in big-		 * files). */-		while(1) {-			ret = process_block(a);-			if(ret != ARCHIVE_OK)-				return ret;--			if(rar->cstate.last_write_ptr ==-			    rar->cstate.write_ptr) {-				/* The block didn't generate any new data,-				 * so just process a new block if this one-				 * wasn't the last block in the file. */-				if (bf_is_last_block(&rar->last_block_hdr)) {-					return ARCHIVE_EOF;-				}--				continue;-			}--			/* The block has generated some new data, so break-			 * the loop. */-			break;-		}-	}--	/* Try to run filters. If filters won't be applied, it means that-	 * insufficient data was generated. */-	ret = apply_filters(a);-	if(ret == ARCHIVE_RETRY) {-		return ARCHIVE_OK;-	} else if(ret != ARCHIVE_OK) {-		return ret;-	}--	if(cdeque_size(&rar->cstate.filters) > 0) {-		/* Check if we can write something before hitting first-		 * filter. */-		struct filter_info* flt;--		/* Get the block_start offset from the first filter. */-		if(CDE_OK != cdeque_front(&rar->cstate.filters,-		    cdeque_filter_p(&flt)))-		{-			archive_set_error(&a->archive,-			    ARCHIVE_ERRNO_PROGRAMMER,-			    "Can't read first filter");-			return ARCHIVE_FATAL;-		}--		max_end_pos = rar5_min(flt->block_start,-		    rar->cstate.write_ptr);-	} else {-		/* There are no filters defined, or all filters were applied.-		 * This means we can just store the data without any-		 * postprocessing. */-		max_end_pos = rar->cstate.write_ptr;-	}--	if(max_end_pos == rar->cstate.last_write_ptr) {-		/* We can't write anything yet. The block uncompression-		 * function did not generate enough data, and no filter can be-		 * applied. At the same time we don't have any data that can be-		 *  stored without filter postprocessing. This means we need to-		 *  wait for more data to be generated, so we can apply the-		 * filters.-		 *-		 * Signal the caller that we need more data to be able to do-		 * anything.-		 */-		return ARCHIVE_RETRY;-	} else {-		/* We can write the data before hitting the first filter.-		 * So let's do it. The push_window_data() function will-		 * effectively return the selected data block to the user-		 * application. */-		push_window_data(a, rar, rar->cstate.last_write_ptr,-		    max_end_pos);-		rar->cstate.last_write_ptr = max_end_pos;-	}--	return ARCHIVE_OK;-}--static int uncompress_file(struct archive_read* a) {-	int ret;--	while(1) {-		/* Sometimes the uncompression function will return a-		 * 'retry' signal. If this will happen, we have to retry-		 * the function. */-		ret = do_uncompress_file(a);-		if(ret != ARCHIVE_RETRY)-			return ret;-	}-}---static int do_unstore_file(struct archive_read* a,-    struct rar5* rar, const void** buf, size_t* size, int64_t* offset)-{-	size_t to_read;-	const uint8_t* p;--	if(rar->file.bytes_remaining == 0 && rar->main.volume > 0 &&-	    rar->generic.split_after > 0)-	{-		int ret;--		rar->cstate.switch_multivolume = 1;-		ret = advance_multivolume(a);-		rar->cstate.switch_multivolume = 0;--		if(ret != ARCHIVE_OK) {-			/* Failed to advance to next multivolume archive-			 * file. */-			return ret;-		}-	}--	to_read = rar5_min(rar->file.bytes_remaining, 64 * 1024);-	if(to_read == 0) {-		return ARCHIVE_EOF;-	}--	if(!read_ahead(a, to_read, &p)) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "I/O error when unstoring file");-		return ARCHIVE_FATAL;-	}--	if(ARCHIVE_OK != consume(a, to_read)) {-		return ARCHIVE_EOF;-	}--	if(buf)    *buf = p;-	if(size)   *size = to_read;-	if(offset) *offset = rar->cstate.last_unstore_ptr;--	rar->file.bytes_remaining -= to_read;-	rar->cstate.last_unstore_ptr += to_read;--	update_crc(rar, p, to_read);-	return ARCHIVE_OK;-}--static int do_unpack(struct archive_read* a, struct rar5* rar,-    const void** buf, size_t* size, int64_t* offset)-{-	enum COMPRESSION_METHOD {-		STORE = 0, FASTEST = 1, FAST = 2, NORMAL = 3, GOOD = 4,-		BEST = 5-	};--	if(rar->file.service > 0) {-		return do_unstore_file(a, rar, buf, size, offset);-	} else {-		switch(rar->cstate.method) {-			case STORE:-				return do_unstore_file(a, rar, buf, size,-				    offset);-			case FASTEST:-				/* fallthrough */-			case FAST:-				/* fallthrough */-			case NORMAL:-				/* fallthrough */-			case GOOD:-				/* fallthrough */-			case BEST:-				/* No data is returned here. But because a sparse-file aware-				 * caller (like archive_read_data_into_fd) may treat zero-size-				 * as a sparse file block, we need to update the offset-				 * accordingly. At this point the decoder doesn't have any-				 * pending uncompressed data blocks, so the current position in-				 * the output file should be last_write_ptr. */-				if (offset) *offset = rar->cstate.last_write_ptr;-				return uncompress_file(a);-			default:-				archive_set_error(&a->archive,-				    ARCHIVE_ERRNO_FILE_FORMAT,-				    "Compression method not supported: 0x%x",-				    (unsigned int)rar->cstate.method);--				return ARCHIVE_FATAL;-		}-	}--#if !defined WIN32-	/* Not reached. */-	return ARCHIVE_OK;-#endif-}--static int verify_checksums(struct archive_read* a) {-	int verify_crc;-	struct rar5* rar = get_context(a);--	/* Check checksums only when actually unpacking the data. There's no-	 * need to calculate checksum when we're skipping data in solid archives-	 * (skipping in solid archives is the same thing as unpacking compressed-	 * data and discarding the result). */--	if(!rar->skip_mode) {-		/* Always check checksums if we're not in skip mode */-		verify_crc = 1;-	} else {-		/* We can override the logic above with a compile-time option-		 * NO_CRC_ON_SOLID_SKIP. This option is used during debugging,-		 * and it will check checksums of unpacked data even when-		 * we're skipping it. */--#if defined CHECK_CRC_ON_SOLID_SKIP-		/* Debug case */-		verify_crc = 1;-#else-		/* Normal case */-		verify_crc = 0;-#endif-	}--	if(verify_crc) {-		/* During unpacking, on each unpacked block we're calling the-		 * update_crc() function. Since we are here, the unpacking-		 * process is already over and we can check if calculated-		 * checksum (CRC32 or BLAKE2sp) is the same as what is stored-		 * in the archive. */-		if(rar->file.stored_crc32 > 0) {-			/* Check CRC32 only when the file contains a CRC32-			 * value for this file. */--			if(rar->file.calculated_crc32 !=-			    rar->file.stored_crc32) {-				/* Checksums do not match; the unpacked file-				 * is corrupted. */--				DEBUG_CODE {-					printf("Checksum error: CRC32 "-					    "(was: %08" PRIx32 ", expected: %08" PRIx32 ")\n",-					    rar->file.calculated_crc32,-					    rar->file.stored_crc32);-				}--#ifndef DONT_FAIL_ON_CRC_ERROR-				archive_set_error(&a->archive,-				    ARCHIVE_ERRNO_FILE_FORMAT,-				    "Checksum error: CRC32");-				return ARCHIVE_FAILED;-#endif-			} else {-				DEBUG_CODE {-					printf("Checksum OK: CRC32 "-					    "(%08" PRIx32 "/%08" PRIx32 ")\n",-					    rar->file.stored_crc32,-					    rar->file.calculated_crc32);-				}-			}-		}--		if(rar->file.has_blake2 > 0) {-			/* BLAKE2sp is an optional checksum algorithm that is-			 * added to RARv5 archives when using the `-htb` switch-			 *  during creation of archive.-			 *-			 * We now finalize the hash calculation by calling the-			 * `final` function. This will generate the final hash-			 * value we can use to compare it with the BLAKE2sp-			 * checksum that is stored in the archive.-			 *-			 * The return value of this `final` function is not-			 * very helpful, as it guards only against improper use.- 			 * This is why we're explicitly ignoring it. */--			uint8_t b2_buf[32];-			(void) blake2sp_final(&rar->file.b2state, b2_buf, 32);--			if(memcmp(&rar->file.blake2sp, b2_buf, 32) != 0) {-#ifndef DONT_FAIL_ON_CRC_ERROR-				archive_set_error(&a->archive,-				    ARCHIVE_ERRNO_FILE_FORMAT,-				    "Checksum error: BLAKE2");--				return ARCHIVE_FAILED;-#endif-			}-		}-	}--	/* Finalization for this file has been successfully completed. */-	return ARCHIVE_OK;-}--static int verify_global_checksums(struct archive_read* a) {-	return verify_checksums(a);-}--/*- * Decryption function for the magic signature pattern. Check the comment near- * the `rar5_signature_xor` symbol to read the rationale behind this.- */-static void rar5_signature(char *buf) {-		size_t i;--		for(i = 0; i < sizeof(rar5_signature_xor); i++) {-			buf[i] = rar5_signature_xor[i] ^ 0xA1;-		}-}--static int rar5_read_data(struct archive_read *a, const void **buff,-    size_t *size, int64_t *offset) {-	int ret;-	struct rar5* rar = get_context(a);--	if (size)-		*size = 0;--	if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {-		rar->has_encrypted_entries = 0;-	}--	if (rar->headers_are_encrypted || rar->cstate.data_encrypted) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Reading encrypted data is not currently supported");-		return ARCHIVE_FAILED;-	}--	if(rar->file.dir > 0) {-		/* Don't process any data if this file entry was declared-		 * as a directory. This is needed, because entries marked as-		 * directory doesn't have any dictionary buffer allocated, so-		 * it's impossible to perform any decompression. */-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Can't decompress an entry marked as a directory");-		return ARCHIVE_FATAL;-	}--	if(!rar->skip_mode && (rar->cstate.last_write_ptr > rar->file.unpacked_size)) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,-		    "Unpacker has written too many bytes");-		return ARCHIVE_FATAL;-	}--	ret = use_data(rar, buff, size, offset);-	if(ret == ARCHIVE_OK) {-		return ret;-	}--	if(rar->file.eof == 1) {-		return ARCHIVE_EOF;-	}--	ret = do_unpack(a, rar, buff, size, offset);-	if(ret != ARCHIVE_OK) {-		return ret;-	}--	if(rar->file.bytes_remaining == 0 &&-			rar->cstate.last_write_ptr == rar->file.unpacked_size)-	{-		/* If all bytes of current file were processed, run-		 * finalization.-		 *-		 * Finalization will check checksum against proper values. If-		 * some of the checksums will not match, we'll return an error-		 * value in the last `archive_read_data` call to signal an error-		 * to the user. */--		rar->file.eof = 1;-		return verify_global_checksums(a);-	}--	return ARCHIVE_OK;-}--static int rar5_read_data_skip(struct archive_read *a) {-	struct rar5* rar = get_context(a);--	if(rar->main.solid && (rar->cstate.data_encrypted == 0)) {-		/* In solid archives, instead of skipping the data, we need to-		 * extract it, and dispose the result. The side effect of this-		 * operation will be setting up the initial window buffer state-		 * needed to be able to extract the selected file. Note that-		 * this is only possible when data withing this solid block is-		 * not encrypted, in which case we'll skip and fail if the user-		 * tries to read data. */--		int ret;--		/* Make sure to process all blocks in the compressed stream. */-		while(rar->file.bytes_remaining > 0) {-			/* Setting the "skip mode" will allow us to skip-			 * checksum checks during data skipping. Checking the-			 * checksum of skipped data isn't really necessary and-			 * it's only slowing things down.-			 *-			 * This is incremented instead of setting to 1 because-			 * this data skipping function can be called-			 * recursively. */-			rar->skip_mode++;--			/* We're disposing 1 block of data, so we use triple-			 * NULLs in arguments. */-			ret = rar5_read_data(a, NULL, NULL, NULL);--			/* Turn off "skip mode". */-			rar->skip_mode--;--			if(ret < 0 || ret == ARCHIVE_EOF) {-				/* Propagate any potential error conditions-				 * to the caller. */-				return ret;-			}-		}-	} else {-		/* In standard archives, we can just jump over the compressed-		 * stream. Each file in non-solid archives starts from an empty-		 * window buffer. */--		if(ARCHIVE_OK != consume(a, rar->file.bytes_remaining)) {-			return ARCHIVE_FATAL;-		}--		rar->file.bytes_remaining = 0;-	}--	return ARCHIVE_OK;-}--static int64_t rar5_seek_data(struct archive_read *a, int64_t offset,-    int whence)-{-	(void) a;-	(void) offset;-	(void) whence;--	/* We're a streaming unpacker, and we don't support seeking. */--	return ARCHIVE_FATAL;-}--static int rar5_cleanup(struct archive_read *a) {-	struct rar5* rar = get_context(a);--	free(rar->cstate.window_buf);-	free(rar->cstate.filtered_buf);-	clear_data_ready_stack(rar);--	free(rar->vol.push_buf);--	free_filters(rar);-	rar5_deinit(rar);--	free(rar);-	a->format->data = NULL;--	return ARCHIVE_OK;-}--static int rar5_capabilities(struct archive_read * a) {-	(void) a;-	return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA-			| ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);-}--static int rar5_has_encrypted_entries(struct archive_read *_a) {-	if (_a && _a->format) {-		struct rar5 *rar = (struct rar5 *)_a->format->data;-		if (rar) {-			return rar->has_encrypted_entries;-		}-	}--	return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;-}--/* Must match deallocations in rar5_deinit */-static int rar5_init(struct rar5* rar) {-	memset(rar, 0, sizeof(struct rar5));--	if(CDE_OK != cdeque_init(&rar->cstate.filters, 8192))-		return ARCHIVE_FATAL;--	/*-	 * Until enough data has been read, we cannot tell about-	 * any encrypted entries yet.-	 */-	rar->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;--	return ARCHIVE_OK;-}--/* Must match allocations in rar5_init */-static void rar5_deinit(struct rar5* rar) {-	cdeque_free(&rar->cstate.filters);-}--int archive_read_support_format_rar5(struct archive *_a) {-	struct archive_read* ar;-	int ret;-	struct rar5* rar;--	if(ARCHIVE_OK != (ret = get_archive_read(_a, &ar)))-		return ret;--	rar = malloc(sizeof(*rar));-	if(rar == NULL) {-		archive_set_error(&ar->archive, ENOMEM,-		    "Can't allocate rar5 data");-		return ARCHIVE_FATAL;-	}--	if(ARCHIVE_OK != rar5_init(rar)) {-		archive_set_error(&ar->archive, ENOMEM,-		    "Can't allocate rar5 filter buffer");-		free(rar);-		return ARCHIVE_FATAL;-	}--	ret = __archive_read_register_format(ar,-	    rar,-	    "rar5",-	    rar5_bid,-	    rar5_options,-	    rar5_read_header,-	    rar5_read_data,-	    rar5_read_data_skip,-	    rar5_seek_data,-	    rar5_cleanup,-	    rar5_capabilities,-	    rar5_has_encrypted_entries);--	if(ret != ARCHIVE_OK) {-		rar5_deinit(rar);-		free(rar);+#include "archive_integer.h"+#include "archive_ppmd7_private.h"+#include "archive_entry_private.h"+#include "archive_time_private.h"++#ifdef HAVE_BLAKE2_H+#include <blake2.h>+#else+#include "archive_blake2.h"+#endif++/*#define CHECK_CRC_ON_SOLID_SKIP*/+/*#define DONT_FAIL_ON_CRC_ERROR*/+/*#define DEBUG*/++#define rar5_min(a, b) (((a) > (b)) ? (b) : (a))+#define rar5_max(a, b) (((a) > (b)) ? (a) : (b))+#define rar5_countof(X) ((const ssize_t) (sizeof(X) / sizeof(*X)))++#if defined DEBUG+#define DEBUG_CODE if(1)+#define LOG(...) do { printf("rar5: " __VA_ARGS__); puts(""); } while(0)+#else+#define DEBUG_CODE if(0)+#endif++/* Real RAR5 magic number is:+ *+ * 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00+ * "Rar!→•☺·\x00"+ *+ * Retrieved with `rar5_signature()` by XOR'ing it with 0xA1, because I don't+ * want to put this magic sequence in each binary that uses libarchive, so+ * applications that scan through the file for this marker won't trigger on+ * this "false" one.+ *+ * The array itself is decrypted in `rar5_init` function. */++static const unsigned char rar5_signature_xor[] = {+	243, 192, 211, 128, 187, 166, 160, 161+};+static const size_t g_unpack_window_size = 0x20000;++/* These could have been static const's, but they aren't, because of+ * Visual Studio. */+#define MAX_NAME_IN_CHARS 2048+#define MAX_NAME_IN_BYTES (4 * MAX_NAME_IN_CHARS)++struct file_header {+	ssize_t bytes_remaining;+	ssize_t unpacked_size;+	int64_t last_offset;         /* Used in sanity checks. */+	int64_t last_size;           /* Used in sanity checks. */++	uint8_t solid : 1;           /* Is this a solid stream? */+	uint8_t service : 1;         /* Is this file a service data? */+	uint8_t eof : 1;             /* Did we finish unpacking the file? */+	uint8_t dir : 1;             /* Is this file entry a directory? */++	/* Optional time fields. */+	int64_t e_mtime;+	int64_t e_ctime;+	int64_t e_atime;+	uint32_t e_mtime_ns;+	uint32_t e_ctime_ns;+	uint32_t e_atime_ns;++	/* Optional hash fields. */+	uint32_t stored_crc32;+	uint32_t calculated_crc32;+	uint8_t blake2sp[32];+	blake2sp_state b2state;+	char has_blake2;++	/* Optional redir fields */+	uint64_t redir_type;+	uint64_t redir_flags;++	ssize_t solid_window_size; /* Used in file format check. */+};++enum EXTRA {+	EX_CRYPT = 0x01,+	EX_HASH = 0x02,+	EX_HTIME = 0x03,+	EX_VERSION = 0x04,+	EX_REDIR = 0x05,+	EX_UOWNER = 0x06,+	EX_SUBDATA = 0x07+};++#define REDIR_SYMLINK_IS_DIR	1++enum REDIR_TYPE {+	REDIR_TYPE_NONE = 0,+	REDIR_TYPE_UNIXSYMLINK = 1,+	REDIR_TYPE_WINSYMLINK = 2,+	REDIR_TYPE_JUNCTION = 3,+	REDIR_TYPE_HARDLINK = 4,+	REDIR_TYPE_FILECOPY = 5,+};++#define	OWNER_USER_NAME		0x01+#define	OWNER_GROUP_NAME	0x02+#define	OWNER_USER_UID		0x04+#define	OWNER_GROUP_GID		0x08+#define	OWNER_MAXNAMELEN	256++enum FILTER_TYPE {+	FILTER_DELTA = 0,   /* Generic pattern. */+	FILTER_E8    = 1,   /* Intel x86 code. */+	FILTER_E8E9  = 2,   /* Intel x86 code. */+	FILTER_ARM   = 3,   /* ARM code. */+	FILTER_AUDIO = 4,   /* Audio filter, not used in RARv5. */+	FILTER_RGB   = 5,   /* Color palette, not used in RARv5. */+	FILTER_ITANIUM = 6, /* Intel's Itanium, not used in RARv5. */+	FILTER_PPM   = 7,   /* Predictive pattern matching, not used in+			       RARv5. */+	FILTER_NONE  = 8,+};++struct filter_info {+	int type;+	int channels;++	int64_t block_start;+	ssize_t block_length;+};++struct data_ready {+	char used;+	const uint8_t* buf;+	size_t size;+	int64_t offset;+};++struct cdeque {+	uint16_t beg_pos;+	uint16_t end_pos;+	uint16_t cap_mask;+	uint16_t size;+	size_t* arr;+};++struct decode_table {+	uint32_t size;+	int32_t decode_len[16];+	uint32_t decode_pos[16];+	uint32_t quick_bits;+	uint8_t quick_len[1 << 10];+	uint16_t quick_num[1 << 10];+	uint16_t decode_num[306];+};++struct comp_state {+	/* Flag used to specify if unpacker needs to reinitialize the+	   uncompression context. */+	uint8_t initialized : 1;++	/* Flag used when applying filters. */+	uint8_t all_filters_applied : 1;++	/* Flag used to skip file context reinitialization, used when unpacker+	   is skipping through different multivolume archives. */+	uint8_t switch_multivolume : 1;++	/* Flag used to specify if unpacker has processed the whole data block+	   or just a part of it. */+	uint8_t block_parsing_finished : 1;++	/* Flag used to indicate that a previous file using this buffer was+	   encrypted, meaning no data in the buffer can be trusted */+	uint8_t data_encrypted : 1;++	signed int notused : 3;++	int flags;                   /* Uncompression flags. */+	int method;                  /* Uncompression algorithm method. */+	int version;                 /* Uncompression algorithm version. */+	ssize_t window_size;         /* Size of window_buf. */+	uint8_t* window_buf;         /* Circular buffer used during+	                                decompression. */+	uint8_t* filtered_buf;       /* Buffer used when applying filters. */+	const uint8_t* block_buf;    /* Buffer used when merging blocks. */+	ssize_t window_mask;         /* Convenience field; window_size - 1. */+	int64_t write_ptr;           /* This amount of data has been unpacked+					in the window buffer. */+	int64_t last_write_ptr;      /* This amount of data has been stored in+	                                the output file. */+	int64_t last_unstore_ptr;    /* Counter of bytes extracted during+	                                unstoring. This is separate from+	                                last_write_ptr because of how SERVICE+	                                base blocks are handled during skipping+	                                in solid multiarchive archives. */+	int64_t solid_offset;        /* Additional offset inside the window+	                                buffer, used in unpacking solid+	                                archives. */+	ssize_t cur_block_size;      /* Size of current data block. */+	int last_len;                /* Flag used in lzss decompression. */++	/* Decode tables used during lzss uncompression. */++#define HUFF_BC 20+	struct decode_table bd;      /* huffman bit lengths */+#define HUFF_NC 306+	struct decode_table ld;      /* literals */+#define HUFF_DC 64+	struct decode_table dd;      /* distances */+#define HUFF_LDC 16+	struct decode_table ldd;     /* lower bits of distances */+#define HUFF_RC 44+	struct decode_table rd;      /* repeating distances */+#define HUFF_TABLE_SIZE (HUFF_NC + HUFF_DC + HUFF_RC + HUFF_LDC)++	/* Circular deque for storing filters. */+	struct cdeque filters;+	int64_t last_block_start;    /* Used for sanity checking. */+	ssize_t last_block_length;   /* Used for sanity checking. */++	/* Distance cache used during lzss uncompression. */+	int dist_cache[4];++	/* Data buffer stack. */+	struct data_ready dready[2];+};++/* Bit reader state. */+struct bit_reader {+	int8_t bit_addr;    /* Current bit pointer inside current byte. */+	int in_addr;        /* Current byte pointer. */+};++/* RARv5 block header structure. Use bf_* functions to get values from+ * block_flags_u8 field. I.e. bf_byte_count, etc. */+struct compressed_block_header {+	/* block_flags_u8 contain fields encoded in little-endian bitfield:+	 *+	 * - table present flag (shr 7, and 1),+	 * - last block flag    (shr 6, and 1),+	 * - byte_count         (shr 3, and 7),+	 * - bit_size           (shr 0, and 7).+	 */+	uint8_t block_flags_u8;+	uint8_t block_cksum;+};++/* RARv5 main header structure. */+struct main_header {+	/* Does the archive contain solid streams? */+	uint8_t solid : 1;++	/* If this a multi-file archive? */+	uint8_t volume : 1;+	uint8_t endarc : 1;+	uint8_t notused : 5;++	unsigned int vol_no;+};++struct generic_header {+	uint8_t split_after : 1;+	uint8_t split_before : 1;+	uint8_t padding : 6;+	int size;+	int last_header_id;+};++struct multivolume {+	unsigned int expected_vol_no;+	uint8_t* push_buf;+};++/* Main context structure. */+struct rar5 {+	int header_initialized;++	/* Set to 1 if current file is positioned AFTER the magic value+	 * of the archive file. This is used in header reading functions. */+	int skipped_magic;++	/* Set to not zero if we're in skip mode (either by calling+	 * rar5_data_skip function or when skipping over solid streams).+	 * Set to 0 when in * extraction mode. This is used during checksum+	 * calculation functions. */+	int skip_mode;++	/* Set to not zero if we're in block merging mode (i.e. when switching+	 * to another file in multivolume archive, last block from 1st archive+	 * needs to be merged with 1st block from 2nd archive). This flag+	 * guards against recursive use of the merging function, which doesn't+	 * support recursive calls. */+	int merge_mode;++	/* An offset to QuickOpen list. This is not supported by this unpacker,+	 * because we're focusing on streaming interface. QuickOpen is designed+	 * to make things quicker for non-stream interfaces, so it's not our+	 * use case. */+	uint64_t qlist_offset;++	/* An offset to additional Recovery data. This is not supported by this+	 * unpacker. Recovery data are additional Reed-Solomon codes that could+	 * be used to calculate bytes that are missing in archive or are+	 * corrupted. */+	uint64_t rr_offset;++	/* Various context variables grouped to different structures. */+	struct generic_header generic;+	struct main_header main;+	struct comp_state cstate;+	struct file_header file;+	struct bit_reader bits;+	struct multivolume vol;++	/* The header of currently processed RARv5 block. Used in main+	 * decompression logic loop. */+	struct compressed_block_header last_block_hdr;++	/*+	 * Custom field to denote that this archive contains encrypted entries+	 */+	int has_encrypted_entries;+	int headers_are_encrypted;+};++/* Forward function declarations. */++static void rar5_signature(char *buf);+static int verify_global_checksums(struct archive_read* a);+static int rar5_read_data_skip(struct archive_read *a);+static int push_data_ready(struct archive_read* a, struct rar5 *rar5,+	const uint8_t* buf, size_t size, int64_t offset);+static void clear_data_ready_stack(struct rar5 *rar5);+static void rar5_deinit(struct rar5 *rar5);++/* CDE_xxx = Circular Double Ended (Queue) return values. */+enum CDE_RETURN_VALUES {+	CDE_OK, CDE_ALLOC, CDE_PARAM, CDE_OUT_OF_BOUNDS,+};++/* Clears the contents of this circular deque. */+static void cdeque_clear(struct cdeque* d) {+	d->size = 0;+	d->beg_pos = 0;+	d->end_pos = 0;+}++/* Creates a new circular deque object. Capacity must be power of 2: 8, 16, 32,+ * 64, 256, etc. When the user will add another item above current capacity,+ * the circular deque will overwrite the oldest entry. */+static int cdeque_init(struct cdeque* d, int max_capacity_power_of_2) {+	if(d == NULL || max_capacity_power_of_2 == 0)+		return CDE_PARAM;++	d->cap_mask = max_capacity_power_of_2 - 1;+	d->arr = NULL;++	if((max_capacity_power_of_2 & d->cap_mask) != 0)+		return CDE_PARAM;++	cdeque_clear(d);+	d->arr = malloc(sizeof(void*) * max_capacity_power_of_2);++	return d->arr ? CDE_OK : CDE_ALLOC;+}++/* Return the current size (not capacity) of circular deque `d`. */+static size_t cdeque_size(struct cdeque* d) {+	return d->size;+}++/* Returns the first element of current circular deque. Note that this function+ * doesn't perform any bounds checking. If you need bounds checking, use+ * `cdeque_front()` function instead. */+static void cdeque_front_fast(struct cdeque* d, void** value) {+	*value = (void*) d->arr[d->beg_pos];+}++/* Returns the first element of current circular deque. This function+ * performs bounds checking. */+static int cdeque_front(struct cdeque* d, void** value) {+	if(d->size > 0) {+		cdeque_front_fast(d, value);+		return CDE_OK;+	} else+		return CDE_OUT_OF_BOUNDS;+}++/* Pushes a new element into the end of this circular deque object. */+static int cdeque_push_back(struct cdeque* d, void* item) {+	if(d == NULL)+		return CDE_PARAM;++	if(d->size == d->cap_mask + 1)+		return CDE_OUT_OF_BOUNDS;++	d->arr[d->end_pos] = (size_t) item;+	d->end_pos = (d->end_pos + 1) & d->cap_mask;+	d->size++;++	return CDE_OK;+}++/* Pops a front element of this circular deque object and returns its value.+ * This function doesn't perform any bounds checking. */+static void cdeque_pop_front_fast(struct cdeque* d, void** value) {+	*value = (void*) d->arr[d->beg_pos];+	d->beg_pos = (d->beg_pos + 1) & d->cap_mask;+	d->size--;+}++/* Pops a front element of this circular deque object and returns its value.+ * This function performs bounds checking. */+static int cdeque_pop_front(struct cdeque* d, void** value) {+	if(!d || !value)+		return CDE_PARAM;++	if(d->size == 0)+		return CDE_OUT_OF_BOUNDS;++	cdeque_pop_front_fast(d, value);+	return CDE_OK;+}++/* Convenience function to cast filter_info** to void **. */+static void** cdeque_filter_p(struct filter_info** f) {+	return (void**) (size_t) f;+}++/* Convenience function to cast filter_info* to void *. */+static void* cdeque_filter(struct filter_info* f) {+	return (void**) (size_t) f;+}++/* Destroys this circular deque object. Deallocates the memory of the+ * collection buffer, but doesn't deallocate the memory of any pointer passed+ * to this deque as a value. */+static void cdeque_free(struct cdeque* d) {+	if(!d)+		return;++	if(!d->arr)+		return;++	free(d->arr);++	d->arr = NULL;+	d->beg_pos = -1;+	d->end_pos = -1;+	d->cap_mask = 0;+}++static inline+uint8_t bf_bit_size(const struct compressed_block_header* hdr) {+	return hdr->block_flags_u8 & 7;+}++static inline+uint8_t bf_byte_count(const struct compressed_block_header* hdr) {+	return (hdr->block_flags_u8 >> 3) & 7;+}++static inline+uint8_t bf_is_table_present(const struct compressed_block_header* hdr) {+	return (hdr->block_flags_u8 >> 7) & 1;+}++static inline+uint8_t bf_is_last_block(const struct compressed_block_header* hdr) {+	return (hdr->block_flags_u8 >> 6) & 1;+}++/* Convenience functions used by filter implementations. */+static void circular_memcpy(uint8_t* dst, uint8_t* window, const ssize_t mask,+    int64_t start, int64_t end)+{+	if((start & mask) > (end & mask)) {+		ssize_t len1 = mask + 1 - (start & mask);+		ssize_t len2 = end & mask;++		memcpy(dst, &window[start & mask], len1);+		memcpy(dst + len1, window, len2);+	} else {+		memcpy(dst, &window[start & mask], (size_t) (end - start));+	}+}++static uint32_t read_filter_data(struct rar5 *rar5, uint32_t offset) {+	uint8_t linear_buf[4];+	circular_memcpy(linear_buf, rar5->cstate.window_buf,+	    rar5->cstate.window_mask, offset, offset + 4);+	return archive_le32dec(linear_buf);+}++static void write_filter_data(struct rar5 *rar5, uint32_t offset,+    uint32_t value)+{+	archive_le32enc(&rar5->cstate.filtered_buf[offset], value);+}++/* Allocates a new filter descriptor and adds it to the filter array. */+static struct filter_info* add_new_filter(struct rar5 *rar5) {+	struct filter_info* f = calloc(1, sizeof(*f));++	if(!f) {+		return NULL;+	}++	if (CDE_OK != cdeque_push_back(&rar5->cstate.filters, cdeque_filter(f))) {+		free(f);+		return NULL;+	}++	return f;+}++static int run_delta_filter(struct rar5 *rar5, struct filter_info* flt) {+	int i;+	ssize_t dest_pos, src_pos = 0;++	for(i = 0; i < flt->channels; i++) {+		uint8_t prev_byte = 0;+		for(dest_pos = i;+				dest_pos < flt->block_length;+				dest_pos += flt->channels)+		{+			uint8_t byte;++			byte = rar5->cstate.window_buf[+			    (rar5->cstate.solid_offset + flt->block_start ++			    src_pos) & rar5->cstate.window_mask];++			prev_byte -= byte;+			rar5->cstate.filtered_buf[dest_pos] = prev_byte;+			src_pos++;+		}+	}++	return ARCHIVE_OK;+}++static int run_e8e9_filter(struct rar5 *rar5, struct filter_info* flt,+		int extended)+{+	const uint32_t file_size = 0x1000000;+	ssize_t i;++	circular_memcpy(rar5->cstate.filtered_buf,+	    rar5->cstate.window_buf, rar5->cstate.window_mask,+	    rar5->cstate.solid_offset + flt->block_start,+	    rar5->cstate.solid_offset + flt->block_start + flt->block_length);++	for(i = 0; i < flt->block_length - 4;) {+		uint8_t b = rar5->cstate.window_buf[+		    (rar5->cstate.solid_offset + flt->block_start ++		    i++) & rar5->cstate.window_mask];++		/*+		 * 0xE8 = x86's call <relative_addr_uint32> (function call)+		 * 0xE9 = x86's jmp <relative_addr_uint32> (unconditional jump)+		 */+		if(b == 0xE8 || (extended && b == 0xE9)) {++			uint32_t addr;+			uint32_t offset = (i + flt->block_start) % file_size;++			addr = read_filter_data(rar5,+			    (uint32_t)(rar5->cstate.solid_offset ++			    flt->block_start + i) & rar5->cstate.window_mask);++			if(addr & 0x80000000) {+				if(((addr + offset) & 0x80000000) == 0) {+					write_filter_data(rar5, (uint32_t)i,+					    addr + file_size);+				}+			} else {+				if((addr - file_size) & 0x80000000) {+					uint32_t naddr = addr - offset;+					write_filter_data(rar5, (uint32_t)i,+					    naddr);+				}+			}++			i += 4;+		}+	}++	return ARCHIVE_OK;+}++static int run_arm_filter(struct rar5 *rar5, struct filter_info* flt) {+	ssize_t i = 0;+	uint32_t offset;++	circular_memcpy(rar5->cstate.filtered_buf,+	    rar5->cstate.window_buf, rar5->cstate.window_mask,+	    rar5->cstate.solid_offset + flt->block_start,+	    rar5->cstate.solid_offset + flt->block_start + flt->block_length);++	for(i = 0; i < flt->block_length - 3; i += 4) {+		uint8_t* b = &rar5->cstate.window_buf[+		    (rar5->cstate.solid_offset ++		    flt->block_start + i + 3) & rar5->cstate.window_mask];++		if(*b == 0xEB) {+			/* 0xEB = ARM's BL (branch + link) instruction. */+			offset = read_filter_data(rar5,+			    (rar5->cstate.solid_offset + flt->block_start + i) &+			     (uint32_t)rar5->cstate.window_mask) & 0x00ffffff;++			offset -= (uint32_t) ((i + flt->block_start) / 4);+			offset = (offset & 0x00ffffff) | 0xeb000000;+			write_filter_data(rar5, (uint32_t)i, offset);+		}+	}++	return ARCHIVE_OK;+}++static int run_filter(struct archive_read* a, struct filter_info* flt) {+	struct rar5 *rar5 = a->format->data;+	int ret;++	clear_data_ready_stack(rar5);+	free(rar5->cstate.filtered_buf);++	rar5->cstate.filtered_buf = malloc(flt->block_length);+	if(!rar5->cstate.filtered_buf) {+		archive_set_error(&a->archive, ENOMEM,+		    "Can't allocate memory for filter data");+		return ARCHIVE_FATAL;+	}++	switch(flt->type) {+		case FILTER_DELTA:+			ret = run_delta_filter(rar5, flt);+			break;++		case FILTER_E8:+			/* fallthrough */+		case FILTER_E8E9:+			ret = run_e8e9_filter(rar5, flt,+			    flt->type == FILTER_E8E9);+			break;++		case FILTER_ARM:+			ret = run_arm_filter(rar5, flt);+			break;++		default:+			archive_set_error(&a->archive,+			    ARCHIVE_ERRNO_FILE_FORMAT,+			    "Unsupported filter type: 0x%x",+			    (unsigned int)flt->type);+			return ARCHIVE_FAILED;+	}++	if(ret != ARCHIVE_OK) {+		/* Filter has failed. */+		return ret;+	}++	if(ARCHIVE_OK != push_data_ready(a, rar5, rar5->cstate.filtered_buf,+	    flt->block_length, rar5->cstate.last_write_ptr))+	{+		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+		    "Stack overflow when submitting unpacked data");++		return ARCHIVE_FATAL;+	}++	rar5->cstate.last_write_ptr += flt->block_length;+	return ARCHIVE_OK;+}++/* The `push_data` function submits the selected data range to the user.+ * Next call of `use_data` will use the pointer, size and offset arguments+ * that are specified here. These arguments are pushed to the FIFO stack here,+ * and popped from the stack by the `use_data` function. */+static void push_data(struct archive_read* a, struct rar5 *rar5,+    const uint8_t* buf, int64_t idx_begin, int64_t idx_end)+{+	const ssize_t wmask = rar5->cstate.window_mask;+	const ssize_t solid_write_ptr = (rar5->cstate.solid_offset ++	    rar5->cstate.last_write_ptr) & wmask;++	idx_begin += rar5->cstate.solid_offset;+	idx_end += rar5->cstate.solid_offset;++	/* Check if our unpacked data is wrapped inside the window circular+	 * buffer.  If it's not wrapped, it can be copied out by using+	 * a single memcpy, but when it's wrapped, we need to copy the first+	 * part with one memcpy, and the second part with another memcpy. */++	if((idx_begin & wmask) > (idx_end & wmask)) {+		/* The data is wrapped (begin offset sis bigger than end+		 * offset). */+		const ssize_t frag1_size = rar5->cstate.window_size -+		    (idx_begin & wmask);+		const ssize_t frag2_size = idx_end & wmask;++		/* Copy the first part of the buffer first. */+		push_data_ready(a, rar5, buf + solid_write_ptr, frag1_size,+		    rar5->cstate.last_write_ptr);++		/* Copy the second part of the buffer. */+		push_data_ready(a, rar5, buf, frag2_size,+		    rar5->cstate.last_write_ptr + frag1_size);++		rar5->cstate.last_write_ptr += frag1_size + frag2_size;+	} else {+		/* Data is not wrapped, so we can just use one call to copy the+		 * data. */+		push_data_ready(a, rar5,+		    buf + solid_write_ptr, (idx_end - idx_begin) & wmask,+		    rar5->cstate.last_write_ptr);++		rar5->cstate.last_write_ptr += idx_end - idx_begin;+	}+}++/* Convenience function that submits the data to the user. It uses the+ * unpack window buffer as a source location. */+static void push_window_data(struct archive_read* a, struct rar5 *rar5,+    int64_t idx_begin, int64_t idx_end)+{+	push_data(a, rar5, rar5->cstate.window_buf, idx_begin, idx_end);+}++static int apply_filters(struct archive_read* a) {+	struct rar5 *rar5 = a->format->data;+	struct filter_info* flt;+	int ret;++	rar5->cstate.all_filters_applied = 0;++	/* Get the first filter that can be applied to our data. The data+	 * needs to be fully unpacked before the filter can be run. */+	if(CDE_OK == cdeque_front(&rar5->cstate.filters,+	    cdeque_filter_p(&flt))) {+		/* Check if our unpacked data fully covers this filter's+		 * range. */+		if(rar5->cstate.write_ptr > flt->block_start &&+		    rar5->cstate.write_ptr >= flt->block_start ++		    flt->block_length) {+			/* Check if we have some data pending to be written+			 * right before the filter's start offset. */+			if(rar5->cstate.last_write_ptr == flt->block_start) {+				/* Run the filter specified by descriptor+				 * `flt`. */+				ret = run_filter(a, flt);+				if(ret != ARCHIVE_OK) {+					/* Filter failure, return error. */+					return ret;+				}++				/* Filter descriptor won't be needed anymore+				 * after it's used, * so remove it from the+				 * filter list and free its memory. */+				(void) cdeque_pop_front(&rar5->cstate.filters,+				    cdeque_filter_p(&flt));++				free(flt);+			} else {+				/* We can't run filters yet, dump the memory+				 * right before the filter. */+				push_window_data(a, rar5,+				    rar5->cstate.last_write_ptr,+				    flt->block_start);+			}++			/* Return 'filter applied or not needed' state to the+			 * caller. */+			return ARCHIVE_RETRY;+		}+	}++	rar5->cstate.all_filters_applied = 1;+	return ARCHIVE_OK;+}++static void dist_cache_push(struct rar5 *rar5, int value) {+	int* q = rar5->cstate.dist_cache;++	q[3] = q[2];+	q[2] = q[1];+	q[1] = q[0];+	q[0] = value;+}++static int dist_cache_touch(struct rar5 *rar5, int idx) {+	int* q = rar5->cstate.dist_cache;+	int i, dist = q[idx];++	for(i = idx; i > 0; i--)+		q[i] = q[i - 1];++	q[0] = dist;+	return dist;+}++static void free_filters(struct rar5 *rar5) {+	struct cdeque* d = &rar5->cstate.filters;++	/* Free any remaining filters. All filters should be naturally+	 * consumed by the unpacking function, so remaining filters after+	 * unpacking normally mean that unpacking wasn't successful.+	 * But still of course we shouldn't leak memory in such case. */++	/* cdeque_size() is a fast operation, so we can use it as a loop+	 * expression. */+	while(cdeque_size(d) > 0) {+		struct filter_info* f = NULL;++		/* Pop_front will also decrease the collection's size. */+		if (CDE_OK == cdeque_pop_front(d, cdeque_filter_p(&f)))+			free(f);+	}++	cdeque_clear(d);++	/* Also clear out the variables needed for sanity checking. */+	rar5->cstate.last_block_start = 0;+	rar5->cstate.last_block_length = 0;+}++static void reset_file_context(struct rar5 *rar5) {+	memset(&rar5->file, 0, sizeof(rar5->file));+	blake2sp_init(&rar5->file.b2state, 32);++	if(rar5->main.solid) {+		rar5->cstate.solid_offset += rar5->cstate.write_ptr;+	} else {+		rar5->cstate.solid_offset = 0;+	}++	rar5->cstate.write_ptr = 0;+	rar5->cstate.last_write_ptr = 0;+	rar5->cstate.last_unstore_ptr = 0;++	rar5->file.redir_type = REDIR_TYPE_NONE;+	rar5->file.redir_flags = 0;++	free_filters(rar5);+}++static inline int get_archive_read(struct archive* a,+    struct archive_read** ar)+{+	*ar = (struct archive_read*) a;+	archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,+	    "archive_read_support_format_rar5");++	return ARCHIVE_OK;+}++static int read_ahead(struct archive_read* a, size_t how_many,+    const uint8_t** ptr)+{+	if(!ptr)+		return 0;++	*ptr = __archive_read_ahead(a, how_many, NULL);+	if(*ptr == NULL) {+		return 0;+	}++	return 1;+}++static int consume(struct archive_read* a, int64_t how_many) {+	int ret;++	ret = how_many == __archive_read_consume(a, how_many)+		? ARCHIVE_OK+		: ARCHIVE_FATAL;++	return ret;+}++/**+ * Read a RAR5 variable sized numeric value. This value will be stored in+ * `pvalue`. The `pvalue_len` argument points to a variable that will receive+ * the byte count that was consumed in order to decode the `pvalue` value, plus+ * one.+ *+ * pvalue_len is optional and can be NULL.+ *+ * NOTE: if `pvalue_len` is NOT NULL, the caller needs to manually consume+ * the number of bytes that `pvalue_len` value contains. If the `pvalue_len`+ * is NULL, this consuming operation is done automatically.+ *+ * Returns 1 if *pvalue was successfully read.+ * Returns 0 if there was an error. In this case, *pvalue contains an+ *           invalid value.+ */++static int read_var(struct archive_read* a, uint64_t* pvalue,+    uint64_t* pvalue_len)+{+	uint64_t multiplier;+	uint64_t result = 0;+	size_t i;+	const uint8_t* p;++	/* We will read maximum of 10 bytes. We don't have to handle the+	 * situation to read the RAR5 variable-sized value stored at the end of+	 * the file, because such situation will never happen. */+	if(!read_ahead(a, 10, &p))+		return 0;++	for(multiplier = 1, i = 0; i < 10; i++, multiplier *= 128) {+		uint64_t val;+		uint8_t b;++		b = p[i];++		/* Strip the MSB from the input byte and add the resulting+		 * number to the `result`. */+		if(archive_ckd_mul_u64(&val, b & 0x7F, multiplier) ||+		   archive_ckd_add_u64(&result, result, val)) {+			/* Integer overflow occurred. */+			return 0;+		}++		/* MSB set to 1 means we need to continue decoding process.+		 * MSB set to 0 means we're done.+		 *+		 * This conditional checks for the second case. */+		if((b & 0x80) == 0) {+			if(pvalue) {+				*pvalue = result;+			}++			/* If the caller has passed the `pvalue_len` pointer,+			 * store the number of consumed bytes in it and do NOT+			 * consume those bytes, since the caller has all the+			 * information it needs to perform */+			if(pvalue_len) {+				*pvalue_len = 1 + i;+			} else {+				/* If the caller did not provide the+				 * `pvalue_len` pointer, it will not have the+				 * possibility to advance the file pointer,+				 * because it will not know how many bytes it+				 * needs to consume. This is why we handle+				 * such situation here automatically. */+				if(ARCHIVE_OK != consume(a, 1 + i)) {+					return 0;+				}+			}++			/* End of decoding process, return success. */+			return 1;+		}+	}++	/* All continuation bits were set. This is an error. */+	return 0;+}++static int read_var_sized(struct archive_read* a, size_t* pvalue,+    size_t* pvalue_len)+{+	uint64_t v;+	uint64_t v_size = 0;++	const int ret = pvalue_len ? read_var(a, &v, &v_size)+				   : read_var(a, &v, NULL);++	if(ret == 1 && pvalue) {+		*pvalue = (size_t) v;+	}++	if(pvalue_len) {+		/* Possible data truncation should be safe. */+		*pvalue_len = (size_t) v_size;+	}++	return ret;+}++static int read_bits_32(struct archive_read* a, struct rar5 *rar5,+	const uint8_t* p, uint32_t* value)+{+	if(rar5->bits.in_addr >= rar5->cstate.cur_block_size) {+		archive_set_error(&a->archive,+			ARCHIVE_ERRNO_PROGRAMMER,+			"Premature end of stream during extraction of data (#1)");+		return ARCHIVE_FATAL;+	}++	uint32_t bits = archive_be32dec(p + rar5->bits.in_addr);+	bits <<= rar5->bits.bit_addr;+	bits |= p[rar5->bits.in_addr + 4] >> (8 - rar5->bits.bit_addr);+	*value = bits;+	return ARCHIVE_OK;+}++static int read_bits_16(struct archive_read* a, struct rar5 *rar5,+	const uint8_t* p, uint16_t* value)+{+	if(rar5->bits.in_addr >= rar5->cstate.cur_block_size) {+		archive_set_error(&a->archive,+			ARCHIVE_ERRNO_PROGRAMMER,+			"Premature end of stream during extraction of data (#2)");+		return ARCHIVE_FATAL;+	}++	uint32_t bits = archive_be24dec(p + (unsigned)rar5->bits.in_addr);+	bits >>= (8 - rar5->bits.bit_addr);+	*value = bits & 0xffff;+	return ARCHIVE_OK;+}++static void skip_bits(struct rar5 *rar5, int bits) {+	const int new_bits = rar5->bits.bit_addr + bits;+	rar5->bits.in_addr += new_bits >> 3;+	rar5->bits.bit_addr = new_bits & 7;+}++/* n = up to 16 */+static int read_consume_bits(struct archive_read* a, struct rar5 *rar5,+	const uint8_t* p, int n, int* value)+{+	uint16_t v;+	int ret, num;++	if(n == 0 || n > 16) {+		/* This is a programmer error and should never happen+		 * in runtime. */+		return ARCHIVE_FATAL;+	}++	ret = read_bits_16(a, rar5, p, &v);+	if(ret != ARCHIVE_OK)+		return ret;++	num = (int) v;+	num >>= 16 - n;++	skip_bits(rar5, n);++	if(value)+		*value = num;++	return ARCHIVE_OK;+}++static char read_u32(struct archive_read* a, uint32_t* pvalue) {+	const uint8_t* p;+	if(!read_ahead(a, 4, &p))+		return 0;++	*pvalue = archive_le32dec(p);+	return ARCHIVE_OK == consume(a, 4);+}++static char read_u64(struct archive_read* a, uint64_t* pvalue) {+	const uint8_t* p;+	if(!read_ahead(a, 8, &p))+		return 0;++	*pvalue = archive_le64dec(p);+	return ARCHIVE_OK == consume(a, 8);+}++static int bid_standard(struct archive_read* a) {+	const uint8_t* p;+	char signature[sizeof(rar5_signature_xor)];++	rar5_signature(signature);++	if(!read_ahead(a, sizeof(rar5_signature_xor), &p))+		return -1;++	if(!memcmp(signature, p, sizeof(rar5_signature_xor)))+		return 30;++	return -1;+}++static int bid_sfx(struct archive_read *a)+{+	const char *p;++	if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)+		return -1;++	if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {+		/* This is a PE file */+		char signature[sizeof(rar5_signature_xor)];+		ssize_t offset = 0x10000;+		ssize_t window = 4096;+		ssize_t bytes_avail;++		rar5_signature(signature);++		while (offset + window <= (1024 * 512)) {+			const char *buff = __archive_read_ahead(a, offset + window, &bytes_avail);+			if (buff == NULL) {+				/* Remaining bytes are less than window. */+				window >>= 1;+				if (window < 0x40)+					return 0;+				continue;+			}+			p = buff + offset;+			while (p + 8 < buff + bytes_avail) {+				if (memcmp(p, signature, sizeof(signature)) == 0)+					return 30;+				p += 0x10;+			}+			offset = p - buff;+		}+	}++	return 0;+}++static int rar5_bid(struct archive_read* a, int best_bid) {+	int my_bid;++	if(best_bid > 30)+		return -1;++	my_bid = bid_standard(a);+	if(my_bid > -1) {+		return my_bid;+	}+	my_bid = bid_sfx(a);+	if (my_bid > -1) {+		return my_bid;+	}++	return -1;+}++static int rar5_options(struct archive_read *a, const char *key,+    const char *val) {+	(void) a;+	(void) key;+	(void) val;++	/* No options supported in this version. Return the ARCHIVE_WARN code+	 * to signal the options supervisor that the unpacker didn't handle+	 * setting this option. */++	return ARCHIVE_WARN;+}++static void init_header(struct archive_read* a) {+	a->archive.archive_format = ARCHIVE_FORMAT_RAR_V5;+	a->archive.archive_format_name = "RAR5";+}++static void init_window_mask(struct rar5 *rar5) {+	if (rar5->cstate.window_size)+		rar5->cstate.window_mask = rar5->cstate.window_size - 1;+	else+		rar5->cstate.window_mask = 0;+}++enum HEADER_FLAGS {+	HFL_EXTRA_DATA = 0x0001,+	HFL_DATA = 0x0002,+	HFL_SKIP_IF_UNKNOWN = 0x0004,+	HFL_SPLIT_BEFORE = 0x0008,+	HFL_SPLIT_AFTER = 0x0010,+	HFL_CHILD = 0x0020,+	HFL_INHERITED = 0x0040+};++static int process_main_locator_extra_block(struct archive_read* a,+    struct rar5 *rar5)+{+	uint64_t locator_flags;++	enum LOCATOR_FLAGS {+		QLIST = 0x01, RECOVERY = 0x02,+	};++	if(!read_var(a, &locator_flags, NULL)) {+		return ARCHIVE_EOF;+	}++	if(locator_flags & QLIST) {+		if(!read_var(a, &rar5->qlist_offset, NULL)) {+			return ARCHIVE_EOF;+		}++		/* qlist is not used */+	}++	if(locator_flags & RECOVERY) {+		if(!read_var(a, &rar5->rr_offset, NULL)) {+			return ARCHIVE_EOF;+		}++		/* rr is not used */+	}++	return ARCHIVE_OK;+}++static int parse_file_extra_hash(struct archive_read* a, struct rar5 *rar5,+    int64_t* extra_data_size)+{+	size_t hash_type = 0;+	size_t value_len;++	enum HASH_TYPE {+		BLAKE2sp = 0x00+	};++	if(!read_var_sized(a, &hash_type, &value_len))+		return ARCHIVE_EOF;++	*extra_data_size -= value_len;+	if(ARCHIVE_OK != consume(a, value_len)) {+		return ARCHIVE_EOF;+	}++	/* The file uses BLAKE2sp checksum algorithm instead of plain old+	 * CRC32. */+	if(hash_type == BLAKE2sp) {+		const uint8_t* p;+		const int hash_size = sizeof(rar5->file.blake2sp);++		if(!read_ahead(a, hash_size, &p))+			return ARCHIVE_EOF;++		rar5->file.has_blake2 = 1;+		memcpy(&rar5->file.blake2sp, p, hash_size);++		if(ARCHIVE_OK != consume(a, hash_size)) {+			return ARCHIVE_EOF;+		}++		*extra_data_size -= hash_size;+	} else {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Unsupported hash type (0x%jx)", (uintmax_t)hash_type);+		return ARCHIVE_FATAL;+	}++	return ARCHIVE_OK;+}++static int parse_htime_item(struct archive_read* a, char unix_time,+    int64_t* sec, uint32_t* nsec, int64_t* extra_data_size)+{+	if(unix_time) {+		uint32_t time_val;+		if(!read_u32(a, &time_val))+			return ARCHIVE_EOF;++		*extra_data_size -= 4;+		*sec = (int64_t) time_val;+	} else {+		uint64_t windows_time;+		if(!read_u64(a, &windows_time))+			return ARCHIVE_EOF;++		ntfs_to_unix(windows_time, sec, nsec);+		*extra_data_size -= 8;+	}++	return ARCHIVE_OK;+}++static int parse_file_extra_version(struct archive_read* a,+    struct archive_entry* e, int64_t* extra_data_size)+{+	size_t flags = 0;+	size_t version = 0;+	size_t value_len = 0;+	struct archive_string version_string;+	struct archive_string name_utf8_string;+	const char* cur_filename;++	/* Flags are ignored. */+	if(!read_var_sized(a, &flags, &value_len))+		return ARCHIVE_EOF;++	*extra_data_size -= value_len;+	if(ARCHIVE_OK != consume(a, value_len))+		return ARCHIVE_EOF;++	if(!read_var_sized(a, &version, &value_len))+		return ARCHIVE_EOF;++	*extra_data_size -= value_len;+	if(ARCHIVE_OK != consume(a, value_len))+		return ARCHIVE_EOF;++	/* extra_data_size should be zero here. */++	cur_filename = archive_entry_pathname_utf8(e);+	if(cur_filename == NULL) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+		    "Version entry without file name");+		return ARCHIVE_FATAL;+	}++	archive_string_init(&version_string);+	archive_string_init(&name_utf8_string);++	/* Prepare a ;123 suffix for the filename, where '123' is the version+	 * value of this file. */+	archive_string_sprintf(&version_string, ";%zu", version);++	/* Build the new filename. */+	archive_strcat(&name_utf8_string, cur_filename);+	archive_strcat(&name_utf8_string, version_string.s);++	/* Apply the new filename into this file's context. */+	archive_entry_update_pathname_utf8(e, name_utf8_string.s);++	/* Free buffers. */+	archive_string_free(&version_string);+	archive_string_free(&name_utf8_string);+	return ARCHIVE_OK;+}++static int parse_file_extra_htime(struct archive_read* a,+    struct archive_entry* e, struct rar5 *rar5, int64_t* extra_data_size)+{+	char unix_time, has_unix_ns, has_mtime, has_ctime, has_atime;+	size_t flags = 0;+	size_t value_len;++	enum HTIME_FLAGS {+		IS_UNIX       = 0x01,+		HAS_MTIME     = 0x02,+		HAS_CTIME     = 0x04,+		HAS_ATIME     = 0x08,+		HAS_UNIX_NS   = 0x10,+	};++	if(!read_var_sized(a, &flags, &value_len))+		return ARCHIVE_EOF;++	*extra_data_size -= value_len;+	if(ARCHIVE_OK != consume(a, value_len)) {+		return ARCHIVE_EOF;+	}++	unix_time = flags & IS_UNIX;+	has_unix_ns = unix_time && (flags & HAS_UNIX_NS);+	has_mtime = flags & HAS_MTIME;+	has_atime = flags & HAS_ATIME;+	has_ctime = flags & HAS_CTIME;+	rar5->file.e_atime_ns = rar5->file.e_ctime_ns = rar5->file.e_mtime_ns = 0;++	if(has_mtime) {+		parse_htime_item(a, unix_time, &rar5->file.e_mtime,+		    &rar5->file.e_mtime_ns, extra_data_size);+	}++	if(has_ctime) {+		parse_htime_item(a, unix_time, &rar5->file.e_ctime,+		    &rar5->file.e_ctime_ns, extra_data_size);+	}++	if(has_atime) {+		parse_htime_item(a, unix_time, &rar5->file.e_atime,+		    &rar5->file.e_atime_ns, extra_data_size);+	}++	if(has_mtime && has_unix_ns) {+		if(!read_u32(a, &rar5->file.e_mtime_ns))+			return ARCHIVE_EOF;++		*extra_data_size -= 4;+	}++	if(has_ctime && has_unix_ns) {+		if(!read_u32(a, &rar5->file.e_ctime_ns))+			return ARCHIVE_EOF;++		*extra_data_size -= 4;+	}++	if(has_atime && has_unix_ns) {+		if(!read_u32(a, &rar5->file.e_atime_ns))+			return ARCHIVE_EOF;++		*extra_data_size -= 4;+	}++	/* The seconds and nanoseconds are either together, or separated in two+	 * fields so we parse them, then set the archive_entry's times. */+	if(has_mtime) {+		archive_entry_set_mtime(e, rar5->file.e_mtime, rar5->file.e_mtime_ns);+	}++	if(has_ctime) {+		archive_entry_set_ctime(e, rar5->file.e_ctime, rar5->file.e_ctime_ns);+	}++	if(has_atime) {+		archive_entry_set_atime(e, rar5->file.e_atime, rar5->file.e_atime_ns);+	}++	return ARCHIVE_OK;+}++static int parse_file_extra_redir(struct archive_read* a,+    struct archive_entry* e, struct rar5 *rar5, int64_t* extra_data_size)+{+	uint64_t value_size = 0;+	size_t target_size = 0;+	char target_utf8_buf[MAX_NAME_IN_BYTES];+	const uint8_t* p;++	if(!read_var(a, &rar5->file.redir_type, &value_size))+		return ARCHIVE_EOF;+	if(ARCHIVE_OK != consume(a, (int64_t)value_size))+		return ARCHIVE_EOF;+	*extra_data_size -= value_size;++	if(!read_var(a, &rar5->file.redir_flags, &value_size))+		return ARCHIVE_EOF;+	if(ARCHIVE_OK != consume(a, (int64_t)value_size))+		return ARCHIVE_EOF;+	*extra_data_size -= value_size;++	if(!read_var_sized(a, &target_size, NULL))+		return ARCHIVE_EOF;+	*extra_data_size -= target_size + 1;++	if(target_size > (MAX_NAME_IN_CHARS - 1)) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Link target is too long");+		return ARCHIVE_FATAL;+	}++	if(target_size == 0) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "No link target specified");+		return ARCHIVE_FATAL;+	}++	if(!read_ahead(a, target_size, &p))+		return ARCHIVE_EOF;++	memcpy(target_utf8_buf, p, target_size);+	target_utf8_buf[target_size] = 0;++	if(ARCHIVE_OK != consume(a, (int64_t)target_size))+		return ARCHIVE_EOF;++	switch(rar5->file.redir_type) {+		case REDIR_TYPE_UNIXSYMLINK:+		case REDIR_TYPE_WINSYMLINK:+			archive_entry_set_filetype(e, AE_IFLNK);+			archive_entry_update_symlink_utf8(e, target_utf8_buf);+			if (rar5->file.redir_flags & REDIR_SYMLINK_IS_DIR) {+				archive_entry_set_symlink_type(e,+					AE_SYMLINK_TYPE_DIRECTORY);+			} else {+				archive_entry_set_symlink_type(e,+				AE_SYMLINK_TYPE_FILE);+			}+			break;++		case REDIR_TYPE_HARDLINK:+			archive_entry_set_filetype(e, AE_IFREG);+			archive_entry_update_hardlink_utf8(e, target_utf8_buf);+			break;++		default:+			/* Unknown redir type, skip it. */+			break;+	}+	return ARCHIVE_OK;+}++static int parse_file_extra_owner(struct archive_read* a,+    struct archive_entry* e, int64_t* extra_data_size)+{+	uint64_t flags = 0;+	uint64_t value_size = 0;+	uint64_t id = 0;+	size_t name_len = 0;+	size_t name_size = 0;+	char namebuf[OWNER_MAXNAMELEN];+	const uint8_t* p;++	if(!read_var(a, &flags, &value_size))+		return ARCHIVE_EOF;+	if(ARCHIVE_OK != consume(a, (int64_t)value_size))+		return ARCHIVE_EOF;+	*extra_data_size -= value_size;++	if ((flags & OWNER_USER_NAME) != 0) {+		if(!read_var_sized(a, &name_size, NULL))+			return ARCHIVE_EOF;+		*extra_data_size -= name_size + 1;++		if(!read_ahead(a, name_size, &p))+			return ARCHIVE_EOF;++		if (name_size >= OWNER_MAXNAMELEN) {+			name_len = OWNER_MAXNAMELEN - 1;+		} else {+			name_len = name_size;+		}++		memcpy(namebuf, p, name_len);+		namebuf[name_len] = 0;+		if(ARCHIVE_OK != consume(a, (int64_t)name_size))+			return ARCHIVE_EOF;++		archive_entry_set_uname(e, namebuf);+	}+	if ((flags & OWNER_GROUP_NAME) != 0) {+		if(!read_var_sized(a, &name_size, NULL))+			return ARCHIVE_EOF;+		*extra_data_size -= name_size + 1;++		if(!read_ahead(a, name_size, &p))+			return ARCHIVE_EOF;++		if (name_size >= OWNER_MAXNAMELEN) {+			name_len = OWNER_MAXNAMELEN - 1;+		} else {+			name_len = name_size;+		}++		memcpy(namebuf, p, name_len);+		namebuf[name_len] = 0;+		if(ARCHIVE_OK != consume(a, (int64_t)name_size))+			return ARCHIVE_EOF;++		archive_entry_set_gname(e, namebuf);+	}+	if ((flags & OWNER_USER_UID) != 0) {+		if(!read_var(a, &id, &value_size))+			return ARCHIVE_EOF;+		if(ARCHIVE_OK != consume(a, (int64_t)value_size))+			return ARCHIVE_EOF;+		*extra_data_size -= value_size;++		archive_entry_set_uid(e, (la_int64_t)id);+	}+	if ((flags & OWNER_GROUP_GID) != 0) {+		if(!read_var(a, &id, &value_size))+			return ARCHIVE_EOF;+		if(ARCHIVE_OK != consume(a, (int64_t)value_size))+			return ARCHIVE_EOF;+		*extra_data_size -= value_size;++		archive_entry_set_gid(e, (la_int64_t)id);+	}+	return ARCHIVE_OK;+}++static int process_head_file_extra(struct archive_read* a,+    struct archive_entry* e, struct rar5 *rar5, int64_t extra_data_size)+{+	uint64_t extra_field_size;+	uint64_t extra_field_id = 0;+	uint64_t var_size;++	while(extra_data_size > 0) {+		/* Make sure we won't fail if the file declares only unsupported+		attributes. */+		int ret = ARCHIVE_OK;++		if(!read_var(a, &extra_field_size, &var_size))+			return ARCHIVE_EOF;++		extra_data_size -= var_size;+		if(ARCHIVE_OK != consume(a, var_size)) {+			return ARCHIVE_EOF;+		}++		if(!read_var(a, &extra_field_id, &var_size))+			return ARCHIVE_EOF;++		extra_field_size -= var_size;+		extra_data_size -= var_size;+		if(ARCHIVE_OK != consume(a, var_size)) {+			return ARCHIVE_EOF;+		}++		switch(extra_field_id) {+			case EX_HASH:+				ret = parse_file_extra_hash(a, rar5,+				    &extra_data_size);+				break;+			case EX_HTIME:+				ret = parse_file_extra_htime(a, e, rar5,+				    &extra_data_size);+				break;+			case EX_REDIR:+				ret = parse_file_extra_redir(a, e, rar5,+				    &extra_data_size);+				break;+			case EX_UOWNER:+				ret = parse_file_extra_owner(a, e,+				    &extra_data_size);+				break;+			case EX_VERSION:+				ret = parse_file_extra_version(a, e,+				    &extra_data_size);+				break;+			case EX_CRYPT:+				/* Mark the entry as encrypted */+				archive_entry_set_is_data_encrypted(e, 1);+				rar5->has_encrypted_entries = 1;+				rar5->cstate.data_encrypted = 1;+				/* fallthrough */+			case EX_SUBDATA:+				/* fallthrough */+			default:+				/* Skip unsupported entry. */+				extra_data_size -= extra_field_size;+				if (ARCHIVE_OK != consume(a, extra_field_size)) {+					return ARCHIVE_EOF;+				}++				/* Don't fail on unsupported attribute -- we've handled it+				   by skipping over it. */+				ret = ARCHIVE_OK;+		}++		if (ret != ARCHIVE_OK) {+			/* Forward any errors signalled by the attribute parsing+			   functions. */+			return ret;+		}+	}++	if (extra_data_size != 0) {+		/* We didn't skip everything, or we skipped too much; either way,+		   there's an error in this parsing function. */++		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+				"unsupported structure of file header extra data");+		return ARCHIVE_FATAL;+	}++	return ARCHIVE_OK;+}++static int file_entry_sanity_checks(struct archive_read* a,+	size_t block_flags, uint8_t is_dir, uint64_t unpacked_size,+	size_t packed_size)+{+	if (is_dir) {+		const int declares_data_size =+			(int) (unpacked_size != 0 || packed_size != 0);++		/* FILE entries for directories still declare HFL_DATA in block flags,+		   even though attaching data to such blocks doesn't make much sense. */+		if (declares_data_size) {+			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+				"directory entries cannot have any data");+			return ARCHIVE_FATAL;+		}+	} else {+		const int declares_hfl_data = (int) ((block_flags & HFL_DATA) != 0);+		if (!declares_hfl_data) {+			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+					"no data found in file/service block");+			return ARCHIVE_FATAL;+		}+	}++	return ARCHIVE_OK;+}++static int process_head_file(struct archive_read* a, struct rar5 *rar5,+    struct archive_entry* entry, size_t block_flags)+{+	int64_t extra_data_size = 0;+	size_t data_size = 0;+	size_t file_flags = 0;+	size_t file_attr = 0;+	size_t compression_info = 0;+	size_t host_os = 0;+	size_t name_size = 0;+	uint64_t unpacked_size, window_size;+	uint32_t mtime = 0, crc = 0;+	int c_method = 0, c_version = 0;+	char name_utf8_buf[MAX_NAME_IN_BYTES];+	const uint8_t* p;+	int sanity_ret;++	enum FILE_FLAGS {+		DIRECTORY = 0x0001, UTIME = 0x0002, CRC32 = 0x0004,+		UNKNOWN_UNPACKED_SIZE = 0x0008,+	};++	enum FILE_ATTRS {+		ATTR_READONLY = 0x1, ATTR_HIDDEN = 0x2, ATTR_SYSTEM = 0x4,+		ATTR_DIRECTORY = 0x10,+	};++	enum COMP_INFO_FLAGS {+		SOLID = 0x0040,+	};++	enum HOST_OS {+		HOST_WINDOWS = 0,+		HOST_UNIX = 1,+	};++	archive_entry_clear(entry);++	/* Do not reset file context if we're switching archives. */+	if(!rar5->cstate.switch_multivolume) {+		reset_file_context(rar5);+	}++	if(block_flags & HFL_EXTRA_DATA) {+		uint64_t edata_size = 0;+		if(!read_var(a, &edata_size, NULL))+			return ARCHIVE_EOF;++		/* Intentional type cast from unsigned to signed. */+		extra_data_size = (int64_t) edata_size;+	}++	if(block_flags & HFL_DATA) {+		if(!read_var_sized(a, &data_size, NULL))+			return ARCHIVE_EOF;++		if(data_size > SSIZE_MAX) {+			archive_set_error(&a->archive,+			    ARCHIVE_ERRNO_FILE_FORMAT,+			    "File data size is too large");+			return ARCHIVE_FATAL;+		}++		rar5->file.bytes_remaining = data_size;+	} else {+		rar5->file.bytes_remaining = 0;+	}++	if(!read_var_sized(a, &file_flags, NULL))+		return ARCHIVE_EOF;++	if(!read_var(a, &unpacked_size, NULL))+		return ARCHIVE_EOF;++	if(file_flags & UNKNOWN_UNPACKED_SIZE) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+		    "Files with unknown unpacked size are not supported");+		return ARCHIVE_FATAL;+	}++	rar5->file.dir = (uint8_t) ((file_flags & DIRECTORY) > 0);++	sanity_ret = file_entry_sanity_checks(a, block_flags, rar5->file.dir,+		unpacked_size, data_size);++	if (sanity_ret != ARCHIVE_OK) {+		return sanity_ret;+	}++	if(!read_var_sized(a, &file_attr, NULL))+		return ARCHIVE_EOF;++	if(file_flags & UTIME) {+		if(!read_u32(a, &mtime))+			return ARCHIVE_EOF;+	}++	if(file_flags & CRC32) {+		if(!read_u32(a, &crc))+			return ARCHIVE_EOF;+	}++	if(!read_var_sized(a, &compression_info, NULL))+		return ARCHIVE_EOF;++	c_method = (int) (compression_info >> 7) & 0x7;+	c_version = (int) (compression_info & 0x3f);++	/* RAR5 seems to limit the dictionary size to 64MB. */+	window_size = (rar5->file.dir > 0) ?+		0 :+		g_unpack_window_size << ((compression_info >> 10) & 15);+	rar5->cstate.method = c_method;+	rar5->cstate.version = c_version + 50;+	rar5->file.solid = (compression_info & SOLID) > 0;++	/* Archives which declare solid files without initializing the window+	 * buffer first are invalid, unless previous data was encrypted, in+	 * which case we may never have had the chance */++	if(rar5->file.solid > 0 && rar5->cstate.data_encrypted == 0 &&+	    rar5->cstate.window_buf == NULL) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+				  "Declared solid file, but no window buffer "+				  "initialized yet");+		return ARCHIVE_FATAL;+	}++	/* Check if window_size is a sane value. Also, if the file is not+	 * declared as a directory, disallow window_size == 0. */+	if(window_size > (64 * 1024 * 1024) ||+	    (rar5->file.dir == 0 && window_size == 0))+	{+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Declared dictionary size is not supported");+		return ARCHIVE_FATAL;+	}++	if(rar5->file.solid > 0) {+		/* Re-check if current window size is the same as previous+		 * window size (for solid files only). */+		if(rar5->file.solid_window_size > 0 &&+		    rar5->file.solid_window_size != (ssize_t) window_size)+		{+			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+			    "Window size for this solid file doesn't match "+			    "the window size used in previous solid file");+			return ARCHIVE_FATAL;+		}+	}+	else+		rar5->cstate.data_encrypted = 0; /* Reset for new buffer */++	if(rar5->cstate.window_size < (ssize_t) window_size &&+	    rar5->cstate.window_buf)+	{+		/* The `data_ready` stack contains pointers to the `window_buf` or+		 * `filtered_buf` buffers.  Since we're about to reallocate the first+		 * buffer, some of those pointers could become invalid. Therefore, we+		 * need to dispose of all entries from the stack before attempting the+		 * realloc. */+		clear_data_ready_stack(rar5);++		/* If window_buf has been allocated before, reallocate it, so+		 * that its size will match new window_size. */++		uint8_t* new_window_buf =+			realloc(rar5->cstate.window_buf, (size_t) window_size);++		if(!new_window_buf) {+			archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+				"Not enough memory when trying to realloc the window "+				"buffer");+			return ARCHIVE_FATAL;+		}++		rar5->cstate.window_buf = new_window_buf;+	}++	/* Values up to 64M should fit into ssize_t on every+	 * architecture. */+	rar5->cstate.window_size = (ssize_t) window_size;++	if(rar5->file.solid > 0 && rar5->file.solid_window_size == 0) {+		/* Solid files have to have the same window_size across+		   whole archive. Remember the window_size parameter+		   for first solid file found. */+		rar5->file.solid_window_size = rar5->cstate.window_size;+	}++	init_window_mask(rar5);++	rar5->file.service = 0;++	if(!read_var_sized(a, &host_os, NULL))+		return ARCHIVE_EOF;++	if(host_os == HOST_WINDOWS) {+		/* Host OS is Windows */++		__LA_MODE_T mode;++		if(file_attr & ATTR_DIRECTORY) {+			if (file_attr & ATTR_READONLY) {+				mode = 0555 | AE_IFDIR;+			} else {+				mode = 0755 | AE_IFDIR;+			}+		} else {+			if (file_attr & ATTR_READONLY) {+				mode = 0444 | AE_IFREG;+			} else {+				mode = 0644 | AE_IFREG;+			}+		}++		archive_entry_set_mode(entry, mode);++		if (file_attr & (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM)) {+			char buf[sizeof(",rdonly,hidden,system")];+			const char *fflags[3] = { "", "", "" };+			const char **flag = fflags;++			if (file_attr & ATTR_READONLY)+				*flag++ = ",rdonly";+			if (file_attr & ATTR_HIDDEN)+				*flag++ = ",hidden";+			if (file_attr & ATTR_SYSTEM)+				*flag++ = ",system";++			snprintf(buf, sizeof(buf), "%s%s%s",+			    fflags[0], fflags[1], fflags[2]);+			archive_entry_copy_fflags_text(entry, buf + 1);+		}+	} else if(host_os == HOST_UNIX) {+		/* Host OS is Unix */+		archive_entry_set_mode(entry, (__LA_MODE_T) file_attr);+	} else {+		/* Unknown host OS */+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+				"Unsupported Host OS: 0x%jx",+				(uintmax_t)host_os);++		return ARCHIVE_FATAL;+	}++	if(!read_var_sized(a, &name_size, NULL))+		return ARCHIVE_EOF;++	if(name_size > (MAX_NAME_IN_CHARS - 1)) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+				"Filename is too long");++		return ARCHIVE_FATAL;+	}++	if(name_size == 0) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+				"No filename specified");++		return ARCHIVE_FATAL;+	}++	if(!read_ahead(a, name_size, &p))+		return ARCHIVE_EOF;++	memcpy(name_utf8_buf, p, name_size);+	name_utf8_buf[name_size] = 0;+	if(ARCHIVE_OK != consume(a, name_size)) {+		return ARCHIVE_EOF;+	}++	archive_entry_update_pathname_utf8(entry, name_utf8_buf);++	if(extra_data_size > 0) {+		int ret = process_head_file_extra(a, entry, rar5,+		    extra_data_size);++		/*+		 * TODO: rewrite or remove useless sanity check+		 *       as extra_data_size is not passed as a pointer+		 *+		if(extra_data_size < 0) {+			archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+			    "File extra data size is not zero");+			return ARCHIVE_FATAL;+		}+		 */++		if(ret != ARCHIVE_OK)+			return ret;+	}++	if((file_flags & UNKNOWN_UNPACKED_SIZE) == 0) {+		rar5->file.unpacked_size = (ssize_t) unpacked_size;+		if(rar5->file.redir_type == REDIR_TYPE_NONE)+			archive_entry_set_size(entry, unpacked_size);+	}++	if(file_flags & UTIME) {+		archive_entry_set_mtime(entry, (time_t) mtime, 0);+	}++	if(file_flags & CRC32) {+		rar5->file.stored_crc32 = crc;+	}++	if(!rar5->cstate.switch_multivolume) {+		/* Do not reinitialize unpacking state if we're switching+		 * archives. */+		rar5->cstate.block_parsing_finished = 1;+		rar5->cstate.all_filters_applied = 1;+		rar5->cstate.initialized = 0;+	}++	if(rar5->generic.split_before > 0) {+		/* If now we're standing on a header that has a 'split before'+		 * mark, it means we're standing on a 'continuation' file+		 * header. Signal the caller that if it wants to move to+		 * another file, it must call rar5_read_header() function+		 * again. */++		return ARCHIVE_RETRY;+	} else {+		return ARCHIVE_OK;+	}+}++static int process_head_service(struct archive_read* a, struct rar5 *rar5,+    struct archive_entry* entry, size_t block_flags)+{+	/* Process this SERVICE block the same way as FILE blocks. */+	int ret = process_head_file(a, rar5, entry, block_flags);+	if(ret != ARCHIVE_OK)+		return ret;++	rar5->file.service = 1;++	/* But skip the data part automatically. It's no use for the user+	 * anyway.  It contains only service data, not even needed to+	 * properly unpack the file. */+	ret = rar5_read_data_skip(a);+	if(ret != ARCHIVE_OK)+		return ret;++	/* After skipping, try parsing another block automatically. */+	return ARCHIVE_RETRY;+}++static int process_head_main(struct archive_read* a, struct rar5 *rar5,+    struct archive_entry* entry, size_t block_flags)+{+	int ret;+	uint64_t extra_data_size = 0;+	size_t extra_field_size = 0;+	size_t extra_field_id = 0;+	size_t archive_flags = 0;++	enum MAIN_FLAGS {+		VOLUME = 0x0001,         /* multi-volume archive */+		VOLUME_NUMBER = 0x0002,  /* volume number, first vol doesn't+					  * have it */+		SOLID = 0x0004,          /* solid archive */+		PROTECT = 0x0008,        /* contains Recovery info */+		LOCK = 0x0010,           /* readonly flag, not used */+	};++	enum MAIN_EXTRA {+		// Just one attribute here.+		LOCATOR = 0x01,+	};++	(void) entry;++	if(block_flags & HFL_EXTRA_DATA) {+		if(!read_var(a, &extra_data_size, NULL))+			return ARCHIVE_EOF;+	} else {+		extra_data_size = 0;+	}++	if(!read_var_sized(a, &archive_flags, NULL)) {+		return ARCHIVE_EOF;+	}++	rar5->main.volume = (archive_flags & VOLUME) > 0;+	rar5->main.solid = (archive_flags & SOLID) > 0;++	if(archive_flags & VOLUME_NUMBER) {+		size_t v = 0;+		if(!read_var_sized(a, &v, NULL)) {+			return ARCHIVE_EOF;+		}++		if (v > UINT_MAX) {+			archive_set_error(&a->archive,+			    ARCHIVE_ERRNO_FILE_FORMAT,+			    "Invalid volume number");+			return ARCHIVE_FATAL;+		}++		rar5->main.vol_no = (unsigned int) v;+	} else {+		rar5->main.vol_no = 0;+	}++	if(rar5->vol.expected_vol_no > 0 &&+		rar5->main.vol_no != rar5->vol.expected_vol_no)+	{+		/* Returning EOF instead of FATAL because of strange+		 * libarchive behavior. When opening multiple files via+		 * archive_read_open_filenames(), after reading up the whole+		 * last file, the __archive_read_ahead function wraps up to+		 * the first archive instead of returning EOF. */+		return ARCHIVE_EOF;+	}++	if(extra_data_size == 0) {+		/* Early return. */+		return ARCHIVE_OK;+	}++	if(!read_var_sized(a, &extra_field_size, NULL)) {+		return ARCHIVE_EOF;+	}++	if(!read_var_sized(a, &extra_field_id, NULL)) {+		return ARCHIVE_EOF;+	}++	if(extra_field_size == 0) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Invalid extra field size");+		return ARCHIVE_FATAL;+	}++	switch(extra_field_id) {+		case LOCATOR:+			ret = process_main_locator_extra_block(a, rar5);+			if(ret != ARCHIVE_OK) {+				/* Error while parsing main locator extra+				 * block. */+				return ret;+			}++			break;+		default:+			archive_set_error(&a->archive,+			    ARCHIVE_ERRNO_FILE_FORMAT,+			    "Unsupported extra type (0x%jx)",+			    (uintmax_t)extra_field_id);+			return ARCHIVE_FATAL;+	}++	return ARCHIVE_OK;+}++static int skip_unprocessed_bytes(struct archive_read* a) {+	struct rar5 *rar5 = a->format->data;+	int ret;++	if(rar5->file.bytes_remaining) {+		/* Use different skipping method in block merging mode than in+		 * normal mode. If merge mode is active, rar5_read_data_skip+		 * can't be used, because it could allow recursive use of+		 * merge_block() * function, and this function doesn't support+		 * recursive use. */+		if(rar5->merge_mode) {+			/* Discard whole merged block. This is valid in solid+			 * mode as well, because the code will discard blocks+			 * only if those blocks are safe to discard (i.e.+			 * they're not FILE blocks).  */+			ret = consume(a, rar5->file.bytes_remaining);+			if(ret != ARCHIVE_OK) {+				return ret;+			}+			rar5->file.bytes_remaining = 0;+		} else {+			/* If we're not in merge mode, use safe skipping code.+			 * This will ensure we'll handle solid archives+			 * properly. */+			ret = rar5_read_data_skip(a);+			if(ret != ARCHIVE_OK) {+				return ret;+			}+		}+	}++	return ARCHIVE_OK;+}++static int scan_for_signature(struct archive_read* a);++/* Base block processing function. A 'base block' is a RARv5 header block+ * that tells the reader what kind of data is stored inside the block.+ *+ * From the birds-eye view a RAR file looks file this:+ *+ * <magic><base_block_1><base_block_2>...<base_block_n>+ *+ * There are a few types of base blocks. Those types are specified inside+ * the 'switch' statement in this function. For example purposes, I'll write+ * how a standard RARv5 file could look like here:+ *+ * <magic><MAIN><FILE><FILE><FILE><SERVICE><ENDARC>+ *+ * The structure above could describe an archive file with 3 files in it,+ * one service "QuickOpen" block (that is ignored by this parser), and an+ * end of file base block marker.+ *+ * If the file is stored in multiple archive files ("multiarchive"), it might+ * look like this:+ *+ * .part01.rar: <magic><MAIN><FILE><ENDARC>+ * .part02.rar: <magic><MAIN><FILE><ENDARC>+ * .part03.rar: <magic><MAIN><FILE><ENDARC>+ *+ * This example could describe 3 RAR files that contain ONE archived file.+ * Or it could describe 3 RAR files that contain 3 different files. Or 3+ * RAR files than contain 2 files. It all depends what metadata is stored in+ * the headers of <FILE> blocks.+ *+ * Each <FILE> block contains info about its size, the name of the file it's+ * storing inside, and whether this FILE block is a continuation block of+ * previous archive ('split before'), and is this FILE block should be+ * continued in another archive ('split after'). By parsing the 'split before'+ * and 'split after' flags, we're able to tell if multiple <FILE> base blocks+ * are describing one file, or multiple files (with the same filename, for+ * example).+ *+ * One thing to note is that if we're parsing the first <FILE> block, and+ * we see 'split after' flag, then we need to jump over to another <FILE>+ * block to be able to decompress rest of the data. To do this, we need+ * to skip the <ENDARC> block, then switch to another file, then skip the+ * <magic> block, <MAIN> block, and then we're standing on the proper+ * <FILE> block.+ */++/*+ * A header that carries no file data (HEAD_MAIN, or an unknown block+ * flagged HFL_SKIP_IF_UNKNOWN) may leave bytes in its body that the+ * sub-parser did not read. Skip them before returning ARCHIVE_RETRY,+ * otherwise rar5_read_header() re-parses the same block region O(N)+ * times instead of O(1), letting a crafted RAR5 file stall the reader+ * (GHSA-9h2c-464f-j3hj).+ *+ * Safe because read_ahead(a, hdr_size, &p) pre-loaded the whole block+ * into one contiguous buffer with no compaction until we return, so+ * body_start stays valid and (cur - body_start) is the exact number of+ * body bytes consumed so far.+ */+static void+rar5_skip_remaining_block(struct archive_read* a,+    const uint8_t* body_start, size_t raw_hdr_size)+{+	const uint8_t* cur;++	if(read_ahead(a, 1, &cur)) {+		size_t body_used = (size_t)(cur - body_start);++		if(body_used < raw_hdr_size)+			(void)consume(a, raw_hdr_size - body_used);+	}+}++static int process_base_block(struct archive_read* a,+    struct archive_entry* entry)+{+	const size_t SMALLEST_RAR5_BLOCK_SIZE = 3;++	struct rar5 *rar5 = a->format->data;+	uint32_t hdr_crc, computed_crc;+	size_t raw_hdr_size = 0, hdr_size_len, hdr_size;+	size_t header_id = 0;+	size_t header_flags = 0;+	const uint8_t* p;+	const uint8_t* body_start;+	int ret;++	enum HEADER_TYPE {+		HEAD_MARK    = 0x00, HEAD_MAIN  = 0x01, HEAD_FILE   = 0x02,+		HEAD_SERVICE = 0x03, HEAD_CRYPT = 0x04, HEAD_ENDARC = 0x05,+		HEAD_UNKNOWN = 0xff,+	};++	/* Skip any unprocessed data for this file. */+	ret = skip_unprocessed_bytes(a);+	if(ret != ARCHIVE_OK)+		return ret;++	/* Read the expected CRC32 checksum. */+	if(!read_u32(a, &hdr_crc)) {+		return ARCHIVE_EOF;+	}++	/* Read header size. */+	if(!read_var_sized(a, &raw_hdr_size, &hdr_size_len)) {+		return ARCHIVE_EOF;+	}++	hdr_size = raw_hdr_size + hdr_size_len;++	/* Sanity check, maximum header size for RAR5 is 2MB. */+	if(hdr_size > (2 * 1024 * 1024)) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Base block header is too large");++		return ARCHIVE_FATAL;+	}++	/* Additional sanity checks to weed out invalid files. */+	if(raw_hdr_size == 0 || hdr_size_len == 0 ||+		hdr_size < SMALLEST_RAR5_BLOCK_SIZE)+	{+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Too small block encountered (%zu bytes)",+		    raw_hdr_size);++		return ARCHIVE_FATAL;+	}++	/* Read the whole header data into memory, maximum memory use here is+	 * 2MB. */+	if(!read_ahead(a, hdr_size, &p)) {+		return ARCHIVE_EOF;+	}++	/* Verify the CRC32 of the header data. */+	computed_crc = (uint32_t) crc32(0, p, (int) hdr_size);+	if(computed_crc != hdr_crc) {+#ifndef DONT_FAIL_ON_CRC_ERROR+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Header CRC error");++		return ARCHIVE_FATAL;+#endif+	}++	/* Remember the first byte of the block body so we can later skip+	 * any bytes the sub-parser leaves unconsumed. */+	body_start = p + hdr_size_len;++	/* If the checksum is OK, we proceed with parsing. */+	if(ARCHIVE_OK != consume(a, hdr_size_len)) {+		return ARCHIVE_EOF;+	}++	if(!read_var_sized(a, &header_id, NULL))+		return ARCHIVE_EOF;++	if(!read_var_sized(a, &header_flags, NULL))+		return ARCHIVE_EOF;++	rar5->generic.split_after = (header_flags & HFL_SPLIT_AFTER) > 0;+	rar5->generic.split_before = (header_flags & HFL_SPLIT_BEFORE) > 0;+	rar5->generic.size = (int)hdr_size;+	rar5->generic.last_header_id = (int)header_id;+	rar5->main.endarc = 0;++	/* Those are possible header ids in RARv5. */+	switch(header_id) {+		case HEAD_MAIN:+			ret = process_head_main(a, rar5, entry, header_flags);++			/* Main header doesn't have any files in it, so it's+			 * pointless to return to the caller. Retry to next+			 * header, which should be HEAD_FILE/HEAD_SERVICE. */+			if(ret == ARCHIVE_OK) {+				rar5_skip_remaining_block(a, body_start,+				    raw_hdr_size);+				return ARCHIVE_RETRY;+			}++			return ret;+		case HEAD_SERVICE:+			ret = process_head_service(a, rar5, entry, header_flags);+			return ret;+		case HEAD_FILE:+			ret = process_head_file(a, rar5, entry, header_flags);+			return ret;+		case HEAD_CRYPT:+			archive_entry_set_is_metadata_encrypted(entry, 1);+			archive_entry_set_is_data_encrypted(entry, 1);+			rar5->has_encrypted_entries = 1;+			rar5->headers_are_encrypted = 1;+			archive_set_error(&a->archive,+			    ARCHIVE_ERRNO_FILE_FORMAT,+			    "Encryption is not supported");+			return ARCHIVE_FATAL;+		case HEAD_ENDARC:+			rar5->main.endarc = 1;++			/* After encountering an end of file marker, we need+			 * to take into consideration if this archive is+			 * continued in another file (i.e. is it part01.rar:+			 * is there a part02.rar?) */+			if(rar5->main.volume) {+				/* In case there is part02.rar, position the+				 * read pointer in a proper place, so we can+				 * resume parsing. */+				ret = scan_for_signature(a);+				if(ret == ARCHIVE_FATAL) {+					return ARCHIVE_EOF;+				} else {+					if(rar5->vol.expected_vol_no ==+					    UINT_MAX) {+						archive_set_error(&a->archive,+						    ARCHIVE_ERRNO_FILE_FORMAT,+						    "Header error");+							return ARCHIVE_FATAL;+					}++					rar5->vol.expected_vol_no =+					    rar5->main.vol_no + 1;+					return ARCHIVE_OK;+				}+			} else {+				return ARCHIVE_EOF;+			}+		case HEAD_MARK:+			return ARCHIVE_EOF;+		default:+			if((header_flags & HFL_SKIP_IF_UNKNOWN) == 0) {+				archive_set_error(&a->archive,+				    ARCHIVE_ERRNO_FILE_FORMAT,+				    "Header type error");+				return ARCHIVE_FATAL;+			} else {+				/* If the block is marked as 'skip if unknown',+				 * do as the flag says: skip the block+				 * instead on failing on it. */+				rar5_skip_remaining_block(a, body_start,+				    raw_hdr_size);+				return ARCHIVE_RETRY;+			}+	}++#if !defined WIN32+	// Not reached.+	archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+	    "Internal unpacker error");+	return ARCHIVE_FATAL;+#endif+}++static int skip_base_block(struct archive_read* a) {+	struct rar5 *rar5 = a->format->data;+	int ret;++	/* Create a new local archive_entry structure that will be operated on+	 * by header reader; operations on this archive_entry will be discarded.+	 */+	struct archive_entry* entry = archive_entry_new();+	if (entry == NULL)+		return ARCHIVE_FATAL;++	ret = process_base_block(a, entry);++	/* Discard operations on this archive_entry structure. */+	archive_entry_free(entry);+	if(ret == ARCHIVE_FATAL)+		return ret;++	if(rar5->generic.last_header_id == 2 && rar5->generic.split_before > 0)+		return ARCHIVE_OK;++	if(ret == ARCHIVE_OK)+		return ARCHIVE_RETRY;+	else+		return ret;+}++static int try_skip_sfx(struct archive_read *a)+{+	const char *p;++	if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)+		return ARCHIVE_EOF;++	if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0)+	{+		char signature[sizeof(rar5_signature_xor)];+		const void *h;+		const char *q;+		size_t skip, total = 0;+		ssize_t bytes, window = 4096;++		rar5_signature(signature);++		while (total + window <= (1024 * 512)) {+			h = __archive_read_ahead(a, window, &bytes);+			if (h == NULL) {+				/* Remaining bytes are less than window. */+				window >>= 1;+				if (window < 0x40)+					goto fatal;+				continue;+			}+			if (bytes < 0x40)+				goto fatal;+			p = h;+			q = p + bytes;++			/*+			 * Scan ahead until we find something that looks+			 * like the RAR header.+			 */+			while (p + 8 < q) {+				if (memcmp(p, signature, sizeof(signature)) == 0) {+					skip = p - (const char *)h;+					__archive_read_consume(a, skip);+					return (ARCHIVE_OK);+				}+				p += 0x10;+			}+			skip = p - (const char *)h;+			__archive_read_consume(a, skip);+			total += skip;+		}+	}++	return ARCHIVE_OK;+fatal:+	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+			"Couldn't find out RAR header");+	return (ARCHIVE_FATAL);+}++static int rar5_read_header(struct archive_read *a,+    struct archive_entry *entry)+{+	struct rar5 *rar5 = a->format->data;+	int ret;++	/*+	 * It should be sufficient to call archive_read_next_header() for+	 * a reader to determine if an entry is encrypted or not.+	 */+	if (rar5->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {+		rar5->has_encrypted_entries = 0;+	}++	if(rar5->header_initialized == 0) {+		init_header(a);+		if ((ret = try_skip_sfx(a)) < ARCHIVE_WARN)+			return ret;+		rar5->header_initialized = 1;+	}++	if(rar5->skipped_magic == 0) {+		if(ARCHIVE_OK != consume(a, sizeof(rar5_signature_xor))) {+			return ARCHIVE_EOF;+		}++		rar5->skipped_magic = 1;+	}++	do {+		ret = process_base_block(a, entry);+	} while(ret == ARCHIVE_RETRY ||+			(rar5->main.endarc > 0 && ret == ARCHIVE_OK));++	return ret;+}++static int init_unpack(struct rar5 *rar5) {+	rar5->file.calculated_crc32 = 0;+	init_window_mask(rar5);++	free(rar5->cstate.window_buf);+	free(rar5->cstate.filtered_buf);++	rar5->cstate.window_buf = NULL;+	rar5->cstate.filtered_buf = NULL;++	if(rar5->cstate.window_size > 0) {+		rar5->cstate.window_buf = calloc(1, rar5->cstate.window_size);+		if(rar5->cstate.window_buf == NULL)+			return ARCHIVE_FATAL;+		rar5->cstate.filtered_buf = calloc(1,+		    rar5->cstate.window_size);+		if(rar5->cstate.filtered_buf == NULL)+			return ARCHIVE_FATAL;+	}++	clear_data_ready_stack(rar5);++	rar5->cstate.write_ptr = 0;+	rar5->cstate.last_write_ptr = 0;++	memset(&rar5->cstate.bd, 0, sizeof(rar5->cstate.bd));+	memset(&rar5->cstate.ld, 0, sizeof(rar5->cstate.ld));+	memset(&rar5->cstate.dd, 0, sizeof(rar5->cstate.dd));+	memset(&rar5->cstate.ldd, 0, sizeof(rar5->cstate.ldd));+	memset(&rar5->cstate.rd, 0, sizeof(rar5->cstate.rd));+	return ARCHIVE_OK;+}++static void update_crc(struct rar5 *rar5, const uint8_t* p, size_t to_read) {+    int verify_crc;++	if(rar5->skip_mode) {+#if defined CHECK_CRC_ON_SOLID_SKIP+		verify_crc = 1;+#else+		verify_crc = 0;+#endif+	} else+		verify_crc = 1;++	if(verify_crc) {+		/* Don't update CRC32 if the file doesn't have the+		 * `stored_crc32` info filled in. */+		if(rar5->file.stored_crc32 > 0) {+			rar5->file.calculated_crc32 =+				crc32(rar5->file.calculated_crc32, p,+				    (unsigned int)to_read);+		}++		/* Check if the file uses an optional BLAKE2sp checksum+		 * algorithm. */+		if(rar5->file.has_blake2 > 0) {+			/* Return value of the `update` function is always 0,+			 * so we can explicitly ignore it here. */+			(void) blake2sp_update(&rar5->file.b2state, p,+			    to_read);+		}+	}+}++static int create_decode_tables(uint8_t* bit_length,+    struct decode_table* table, int size)+{+	int code, upper_limit = 0, i, lc[16];+	uint32_t decode_pos_clone[rar5_countof(table->decode_pos)];+	ssize_t cur_len, quick_data_size;++	memset(&lc, 0, sizeof(lc));+	memset(table->decode_num, 0, sizeof(table->decode_num));+	table->size = size;+	table->quick_bits = size == HUFF_NC ? 10 : 7;++	for(i = 0; i < size; i++) {+		lc[bit_length[i] & 15]++;+	}++	lc[0] = 0;+	table->decode_pos[0] = 0;+	table->decode_len[0] = 0;++	for(i = 1; i < 16; i++) {+		upper_limit += lc[i];++		table->decode_len[i] = upper_limit << (16 - i);+		table->decode_pos[i] = table->decode_pos[i - 1] + lc[i - 1];++		upper_limit <<= 1;+	}++	/* Verify the code-length distribution is not over-subscribed.+	 * After the loop above, upper_limit == sum(lc[i] * 2^(16-i)).+	 * For a valid prefix-free code this must be <= 2^16 = 65536.+	 * An over-subscribed table (> 65536) cannot produce a valid+	 * decode table and must be rejected. */+	if(upper_limit > 65536) {+		return ARCHIVE_FAILED;+	}++	memcpy(decode_pos_clone, table->decode_pos, sizeof(decode_pos_clone));++	for(i = 0; i < size; i++) {+		uint8_t clen = bit_length[i] & 15;+		if(clen > 0) {+			int last_pos = decode_pos_clone[clen];+			table->decode_num[last_pos] = i;+			decode_pos_clone[clen]++;+		}+	}++	quick_data_size = (int64_t)1 << table->quick_bits;+	cur_len = 1;+	for(code = 0; code < quick_data_size; code++) {+		int bit_field = code << (16 - table->quick_bits);+		int dist, pos;++		while(cur_len < rar5_countof(table->decode_len) &&+				bit_field >= table->decode_len[cur_len]) {+			cur_len++;+		}++		table->quick_len[code] = (uint8_t) cur_len;++		dist = bit_field - table->decode_len[cur_len - 1];+		dist >>= (16 - cur_len);++		pos = table->decode_pos[cur_len & 15] + dist;+		if(cur_len < rar5_countof(table->decode_pos) && pos < size) {+			table->quick_num[code] = table->decode_num[pos];+		} else {+			table->quick_num[code] = 0;+		}+	}++	return ARCHIVE_OK;+}++static int decode_number(struct archive_read* a, struct decode_table* table,+    const uint8_t* p, uint16_t* num)+{+	struct rar5 *rar5 = a->format->data;+	int i, bits, dist, ret;+	uint16_t bitfield;+	uint32_t pos;++	if(ARCHIVE_OK != (ret = read_bits_16(a, rar5, p, &bitfield))) {+		return ret;+	}++	bitfield &= 0xfffe;++	if(bitfield < table->decode_len[table->quick_bits]) {+		int code = bitfield >> (16 - table->quick_bits);+		skip_bits(rar5, table->quick_len[code]);+		*num = table->quick_num[code];+		return ARCHIVE_OK;+	}++	bits = 15;++	for(i = table->quick_bits + 1; i < 15; i++) {+		if(bitfield < table->decode_len[i]) {+			bits = i;+			break;+		}+	}++	skip_bits(rar5, bits);++	dist = bitfield - table->decode_len[bits - 1];+	dist >>= (16 - bits);+	pos = table->decode_pos[bits] + dist;++	if(pos >= table->size)+		pos = 0;++	*num = table->decode_num[pos];+	return ARCHIVE_OK;+}++/* Reads and parses Huffman tables from the beginning of the block. */+static int parse_tables(struct archive_read* a, struct rar5 *rar5,+    const uint8_t* p)+{+	int ret, value, i, w, idx = 0;+	uint8_t bit_length[HUFF_BC],+		table[HUFF_TABLE_SIZE],+		nibble_mask = 0xF0,+		nibble_shift = 4;++	enum { ESCAPE = 15 };++	/* The data for table generation is compressed using a simple RLE-like+	 * algorithm when storing zeroes, so we need to unpack it first. */+	for(w = 0, i = 0; w < HUFF_BC;) {+		if(i >= rar5->cstate.cur_block_size) {+			/* Truncated data, can't continue. */+			archive_set_error(&a->archive,+			    ARCHIVE_ERRNO_FILE_FORMAT,+			    "Truncated data in huffman tables");+			return ARCHIVE_FAILED;+		}++		value = (p[i] & nibble_mask) >> nibble_shift;++		if(nibble_mask == 0x0F)+			++i;++		nibble_mask ^= 0xFF;+		nibble_shift ^= 4;++		/* Values smaller than 15 is data, so we write it directly.+		 * Value 15 is a flag telling us that we need to unpack more+		 * bytes. */+		if(value == ESCAPE) {+			value = (p[i] & nibble_mask) >> nibble_shift;+			if(nibble_mask == 0x0F)+				++i;+			nibble_mask ^= 0xFF;+			nibble_shift ^= 4;++			if(value == 0) {+				/* We sometimes need to write the actual value+				 * of 15, so this case handles that. */+				bit_length[w++] = ESCAPE;+			} else {+				int k;++				/* Fill zeroes. */+				for(k = 0; (k < value + 2) && (w < HUFF_BC);+				    k++) {+					bit_length[w++] = 0;+				}+			}+		} else {+			bit_length[w++] = value;+		}+	}++	rar5->bits.in_addr = i;+	rar5->bits.bit_addr = nibble_shift ^ 4;++	ret = create_decode_tables(bit_length, &rar5->cstate.bd, HUFF_BC);+	if(ret != ARCHIVE_OK) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Decoding huffman tables failed");+		return ARCHIVE_FAILED;+	}++	for(i = 0; i < HUFF_TABLE_SIZE;) {+		uint16_t num;++		ret = decode_number(a, &rar5->cstate.bd, p, &num);+		if(ret != ARCHIVE_OK) {+			archive_set_error(&a->archive,+			    ARCHIVE_ERRNO_FILE_FORMAT,+			    "Decoding huffman tables failed");+			return ARCHIVE_FAILED;+		}++		if(num < 16) {+			/* 0..15: store directly */+			table[i] = (uint8_t) num;+			i++;+		} else if(num < 18) {+			/* 16..17: repeat previous code */+			uint16_t n;++			if(ARCHIVE_OK != (ret = read_bits_16(a, rar5, p, &n)))+				return ret;++			if(num == 16) {+				n >>= 13;+				n += 3;+				skip_bits(rar5, 3);+			} else {+				n >>= 9;+				n += 11;+				skip_bits(rar5, 7);+			}++			if(i > 0) {+				while(n-- > 0 && i < HUFF_TABLE_SIZE) {+					table[i] = table[i - 1];+					i++;+				}+			} else {+				archive_set_error(&a->archive,+				    ARCHIVE_ERRNO_FILE_FORMAT,+				    "Unexpected error when decoding "+				    "huffman tables");+				return ARCHIVE_FAILED;+			}+		} else {+			/* other codes: fill with zeroes `n` times */+			uint16_t n;++			if(ARCHIVE_OK != (ret = read_bits_16(a, rar5, p, &n)))+				return ret;++			if(num == 18) {+				n >>= 13;+				n += 3;+				skip_bits(rar5, 3);+			} else {+				n >>= 9;+				n += 11;+				skip_bits(rar5, 7);+			}++			while(n-- > 0 && i < HUFF_TABLE_SIZE)+				table[i++] = 0;+		}+	}++	ret = create_decode_tables(&table[idx], &rar5->cstate.ld, HUFF_NC);+	if(ret != ARCHIVE_OK) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		     "Failed to create literal table");+		return ARCHIVE_FAILED;+	}++	idx += HUFF_NC;++	ret = create_decode_tables(&table[idx], &rar5->cstate.dd, HUFF_DC);+	if(ret != ARCHIVE_OK) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Failed to create distance table");+		return ARCHIVE_FAILED;+	}++	idx += HUFF_DC;++	ret = create_decode_tables(&table[idx], &rar5->cstate.ldd, HUFF_LDC);+	if(ret != ARCHIVE_OK) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Failed to create lower bits of distances table");+		return ARCHIVE_FAILED;+	}++	idx += HUFF_LDC;++	ret = create_decode_tables(&table[idx], &rar5->cstate.rd, HUFF_RC);+	if(ret != ARCHIVE_OK) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Failed to create repeating distances table");+		return ARCHIVE_FAILED;+	}++	return ARCHIVE_OK;+}++/* Parses the block header, verifies its CRC byte, and saves the header+ * fields inside the `hdr` pointer. */+static int parse_block_header(struct archive_read* a, const uint8_t* p,+    ssize_t* block_size, struct compressed_block_header* hdr)+{+	uint8_t calculated_cksum;+	memcpy(hdr, p, sizeof(struct compressed_block_header));++	if(bf_byte_count(hdr) > 2) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Unsupported block header size (was %d, max is 2)",+		    bf_byte_count(hdr));+		return ARCHIVE_FAILED;+	}++	/* This should probably use bit reader interface in order to be more+	 * future-proof. */+	*block_size = 0;+	switch(bf_byte_count(hdr)) {+		/* 1-byte block size */+		case 0:+			*block_size = *(const uint8_t*) &p[2];+			break;++		/* 2-byte block size */+		case 1:+			*block_size = archive_le16dec(&p[2]);+			break;++		/* 3-byte block size */+		case 2:+			*block_size = archive_le32dec(&p[2]);+			*block_size &= 0x00FFFFFF;+			break;++		/* Other block sizes are not supported. This case is not+		 * reached, because we have an 'if' guard before the switch+		 * that makes sure of it. */+		default:+			return ARCHIVE_FATAL;+	}++	/* Verify the block header checksum. 0x5A is a magic value and is+	 * always * constant. */+	calculated_cksum = 0x5A+	    ^ (uint8_t) hdr->block_flags_u8+	    ^ (uint8_t) *block_size+	    ^ (uint8_t) (*block_size >> 8)+	    ^ (uint8_t) (*block_size >> 16);++	if(calculated_cksum != hdr->block_cksum) {+#ifndef DONT_FAIL_ON_CRC_ERROR+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Block checksum error: got 0x%x, expected 0x%x",+		    hdr->block_cksum, calculated_cksum);++		return ARCHIVE_FAILED;+#endif+	}++	return ARCHIVE_OK;+}++/* Convenience function used during filter processing. */+static int parse_filter_data(struct archive_read* a, struct rar5 *rar5,+	const uint8_t* p, uint32_t* filter_data)+{+	int i, bytes, ret;+	uint32_t data = 0;++	if(ARCHIVE_OK != (ret = read_consume_bits(a, rar5, p, 2, &bytes)))+		return ret;++	bytes++;++	for(i = 0; i < bytes; i++) {+		uint16_t byte;++		if(ARCHIVE_OK != (ret = read_bits_16(a, rar5, p, &byte))) {+			return ret;+		}++		/* Cast to uint32_t will ensure the shift operation will not+		 * produce undefined result. */+		data += ((uint32_t) byte >> 8) << (i * 8);+		skip_bits(rar5, 8);+	}++	*filter_data = data;+	return ARCHIVE_OK;+}++/* Function is used during sanity checking. */+static int is_valid_filter_block_start(struct rar5 *rar5,+    uint32_t start)+{+	const int64_t block_start = (ssize_t) start + rar5->cstate.write_ptr;+	const int64_t last_bs = rar5->cstate.last_block_start;+	const ssize_t last_bl = rar5->cstate.last_block_length;++	if(last_bs == 0 || last_bl == 0) {+		/* We didn't have any filters yet, so accept this offset. */+		return 1;+	}++	if(block_start >= last_bs + last_bl) {+		/* Current offset is bigger than last block's end offset, so+		 * accept current offset. */+		return 1;+	}++	/* Any other case is not a normal situation and we should fail. */+	return 0;+}++/* The function will create a new filter, read its parameters from the input+ * stream and add it to the filter collection. */+static int parse_filter(struct archive_read* ar, const uint8_t* p) {+	struct rar5 *rar5 = ar->format->data;+	uint32_t block_start, block_length;+	uint16_t filter_type;+	struct filter_info* filt = NULL;+	int ret;++	/* Read the parameters from the input stream. */+	if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar5, p, &block_start)))+		return ret;++	if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar5, p, &block_length)))+		return ret;++	if(ARCHIVE_OK != (ret = read_bits_16(ar, rar5, p, &filter_type)))+		return ret;++	filter_type >>= 13;+	skip_bits(rar5, 3);++	/* Perform some sanity checks on this filter parameters. */++	if(block_length < 4 ||+	    block_length > 0x400000 ||+	    !is_valid_filter_block_start(rar5, block_start) ||+	    (rar5->cstate.window_size > 0 &&+	     (ssize_t)block_length > rar5->cstate.window_size >> 1))+	{+		archive_set_error(&ar->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Invalid filter encountered");+		return ARCHIVE_FAILED;+	}++	/* Allocate a new filter. */+	filt = add_new_filter(rar5);+	if(filt == NULL) {+		archive_set_error(&ar->archive, ENOMEM,+		    "Can't allocate memory for a filter descriptor");+		return ARCHIVE_FATAL;+	}++	filt->type = filter_type;+	filt->block_start = rar5->cstate.write_ptr + block_start;+	filt->block_length = block_length;++	rar5->cstate.last_block_start = filt->block_start;+	rar5->cstate.last_block_length = filt->block_length;++	/* Read some more data in case this is a DELTA filter. Other filter+	 * types don't require any additional data over what was already+	 * read. */+	if(filter_type == FILTER_DELTA) {+		int channels;++		if(ARCHIVE_OK != (ret = read_consume_bits(ar, rar5, p, 5, &channels)))+			return ret;++		filt->channels = channels + 1;+	}++	return ARCHIVE_OK;+}++static int decode_code_length(struct archive_read* a, struct rar5 *rar5,+	const uint8_t* p, uint16_t code)+{+	int lbits, length = 2;++	if(code < 8) {+		lbits = 0;+		length += code;+	} else {+		lbits = code / 4 - 1;+		length += (4 | (code & 3)) << lbits;+	}++	if(lbits > 0) {+		int add;++		if(ARCHIVE_OK != read_consume_bits(a, rar5, p, lbits, &add))+			return -1;++		length += add;+	}++	return length;+}++static int copy_string(struct archive_read* a, int len, int dist) {+	struct rar5 *rar5 = a->format->data;+	const ssize_t cmask = rar5->cstate.window_mask;+	const uint64_t write_ptr = rar5->cstate.write_ptr ++	    rar5->cstate.solid_offset;+	int i;++	if (rar5->cstate.window_buf == NULL)+		return ARCHIVE_FATAL;++	if (rar5->cstate.write_ptr > rar5->file.unpacked_size ||+	    len > rar5->file.unpacked_size - rar5->cstate.write_ptr) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Uncompressed data exceeds declared size");+		return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;+	}++	/* The unpacker spends most of the time in this function. It would be+	 * a good idea to introduce some optimizations here.+	 *+	 * Just remember that this loop treats buffers that overlap differently+	 * than buffers that do not overlap. This is why a simple memcpy(3)+	 * call will not be enough. */++	for(i = 0; i < len; i++) {+		const ssize_t write_idx = (write_ptr + i) & cmask;+		const ssize_t read_idx = (write_ptr + i - dist) & cmask;+		rar5->cstate.window_buf[write_idx] =+		    rar5->cstate.window_buf[read_idx];+	}++	rar5->cstate.write_ptr += len;+	return ARCHIVE_OK;+}++static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {+	struct rar5 *rar5 = a->format->data;+	uint16_t num;+	int ret;++	const uint64_t cmask = rar5->cstate.window_mask;+	const struct compressed_block_header* hdr = &rar5->last_block_hdr;+	const uint8_t bit_size = 1 + bf_bit_size(hdr);++	while(1) {+		if(rar5->cstate.write_ptr - rar5->cstate.last_write_ptr >+		    (rar5->cstate.window_size >> 1)) {+			/* Don't allow growing data by more than half of the+			 * window size at a time. In such case, break the loop;+			 *  next call to this function will continue processing+			 *  from this moment. */+			break;+		}++		if(rar5->bits.in_addr > rar5->cstate.cur_block_size - 1 ||+		    (rar5->bits.in_addr == rar5->cstate.cur_block_size - 1 &&+		    rar5->bits.bit_addr >= bit_size))+		{+			/* If the program counter is here, it means the+			 * function has finished processing the block. */+			rar5->cstate.block_parsing_finished = 1;+			break;+		}++		/* Decode the next literal. */+		if(ARCHIVE_OK != decode_number(a, &rar5->cstate.ld, p, &num)) {+			return ARCHIVE_EOF;+		}++		/* Num holds a decompression literal, or 'command code'.+		 *+		 * - Values lower than 256 are just bytes. Those codes+		 *   can be stored in the output buffer directly.+		 *+		 * - Code 256 defines a new filter, which is later used to+		 *   transform the data block accordingly to the filter type.+		 *   The data block needs to be fully uncompressed first.+		 *+		 * - Code bigger than 257 and smaller than 262 define+		 *   a repetition pattern that should be copied from+		 *   an already uncompressed chunk of data.+		 */++		if(num < 256) {+			/* Directly store the byte. */+			int64_t write_idx;++			/* A literal write emits one byte; copy_string() checks len. */+			if(rar5->cstate.write_ptr >= rar5->file.unpacked_size) {+				archive_set_error(&a->archive,+				    ARCHIVE_ERRNO_FILE_FORMAT,+				    "Uncompressed data exceeds declared size");+				return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;+			}++			write_idx = rar5->cstate.solid_offset ++			    rar5->cstate.write_ptr++;++			rar5->cstate.window_buf[write_idx & cmask] =+			    (uint8_t) num;+			continue;+		} else if(num >= 262) {+			uint16_t dist_slot;+			int len = decode_code_length(a, rar5, p, num - 262),+				dbits,+				dist = 1;++			if(len == -1) {+				archive_set_error(&a->archive,+				    ARCHIVE_ERRNO_PROGRAMMER,+				    "Failed to decode the code length");++				return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;+			}++			if(ARCHIVE_OK != decode_number(a, &rar5->cstate.dd, p,+			    &dist_slot))+			{+				archive_set_error(&a->archive,+				    ARCHIVE_ERRNO_PROGRAMMER,+				    "Failed to decode the distance slot");++				return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;+			}++			if(dist_slot < 4) {+				dbits = 0;+				dist += dist_slot;+			} else {+				dbits = dist_slot / 2 - 1;++				/* Cast to uint32_t will make sure the shift+				 * left operation won't produce undefined+				 * result. Then, the uint32_t type will+				 * be implicitly casted to int. */+				dist += (uint32_t) (2 |+				    (dist_slot & 1)) << dbits;+			}++			if(dbits > 0) {+				if(dbits >= 4) {+					uint32_t add = 0;+					uint16_t low_dist;++					if(dbits > 4) {+						if(ARCHIVE_OK != (ret = read_bits_32(+						    a, rar5, p, &add))) {+							/* Return EOF if we+							 * can't read more+							 * data. */+							return ret;+						}++						skip_bits(rar5, dbits - 4);+						add = (add >> (+						    36 - dbits)) << 4;+						dist += add;+					}++					if(ARCHIVE_OK != decode_number(a,+					    &rar5->cstate.ldd, p, &low_dist))+					{+						archive_set_error(&a->archive,+						    ARCHIVE_ERRNO_PROGRAMMER,+						    "Failed to decode the "+						    "distance slot");++						return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;+					}++					if(dist >= INT_MAX - low_dist - 1) {+						/* This only happens in+						 * invalid archives. */+						archive_set_error(&a->archive,+						    ARCHIVE_ERRNO_FILE_FORMAT,+						    "Distance pointer "+						    "overflow");+						return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;+					}++					dist += low_dist;+				} else {+					/* dbits is one of [0,1,2,3] */+					int add;++					if(ARCHIVE_OK != (ret = read_consume_bits(a, rar5,+					     p, dbits, &add))) {+						/* Return EOF if we can't read+						 * more data. */+						return ret;+					}++					dist += add;+				}+			}++			if(dist > 0x100) {+				len++;++				if(dist > 0x2000) {+					len++;++					if(dist > 0x40000) {+						len++;+					}+				}+			}++			dist_cache_push(rar5, dist);+			rar5->cstate.last_len = len;++			ret = copy_string(a, len, dist);+			if(ret != ARCHIVE_OK)+				return ret;++			continue;+		} else if(num == 256) {+			/* Create a filter. */+			ret = parse_filter(a, p);+			if(ret != ARCHIVE_OK)+				return ret;++			continue;+		} else if(num == 257) {+			if(rar5->cstate.last_len != 0) {+				ret = copy_string(a,+				    rar5->cstate.last_len,+				    rar5->cstate.dist_cache[0]);+				if(ret != ARCHIVE_OK)+					return ret;+			}++			continue;+		} else {+			/* num < 262 */+			const int idx = num - 258;+			const int dist = dist_cache_touch(rar5, idx);++			uint16_t len_slot;+			int len;++			if(ARCHIVE_OK != decode_number(a, &rar5->cstate.rd, p,+			    &len_slot)) {+				return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;+			}++			len = decode_code_length(a, rar5, p, len_slot);+			if (len == -1) {+				return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;+			}++			rar5->cstate.last_len = len;++			ret = copy_string(a, len, dist);+			if(ret != ARCHIVE_OK)+				return ret;++			continue;+		}+	}++	return ARCHIVE_OK;+}++/* Binary search for the RARv5 signature. */+static int scan_for_signature(struct archive_read* a) {+	const uint8_t* p;+	const int chunk_size = 512;+	ssize_t i;+	char signature[sizeof(rar5_signature_xor)];++	/* If we're here, it means we're on an 'unknown territory' data.+	 * There's no indication what kind of data we're reading here.+	 * It could be some text comment, any kind of binary data,+	 * digital sign, dragons, etc.+	 *+	 * We want to find a valid RARv5 magic header inside this unknown+	 * data. */++	/* Is it possible in libarchive to just skip everything until the+	 * end of the file? If so, it would be a better approach than the+	 * current implementation of this function. */++	rar5_signature(signature);++	while(1) {+		if(!read_ahead(a, chunk_size, &p))+			return ARCHIVE_EOF;++		for(i = 0; i < chunk_size - (int)sizeof(rar5_signature_xor);+		    i++) {+			if(memcmp(&p[i], signature,+			    sizeof(rar5_signature_xor)) == 0) {+				/* Consume the number of bytes we've used to+				 * search for the signature, as well as the+				 * number of bytes used by the signature+				 * itself. After this we should be standing+				 * on a valid base block header. */+				(void) consume(a,+				    i + sizeof(rar5_signature_xor));+				return ARCHIVE_OK;+			}+		}++		consume(a, chunk_size);+	}++	return ARCHIVE_FATAL;+}++/* This function will switch the multivolume archive file to another file,+ * i.e. from part03 to part 04. */+static int advance_multivolume(struct archive_read* a) {+	struct rar5 *rar5 = a->format->data;+	int lret;++	/* A small state machine that will skip unnecessary data, needed to+	 * switch from one multivolume to another. Such skipping is needed if+	 * we want to be an stream-oriented (instead of file-oriented)+	 * unpacker.+	 *+	 * The state machine starts with `rar5->main.endarc` == 0. It also+	 * assumes that current stream pointer points to some base block+	 * header.+	 *+	 * The `endarc` field is being set when the base block parsing+	 * function encounters the 'end of archive' marker.+	 */++	while(1) {+		if(rar5->main.endarc == 1) {+			int looping = 1;++			rar5->main.endarc = 0;++			while(looping) {+				lret = skip_base_block(a);+				switch(lret) {+					case ARCHIVE_RETRY:+						/* Continue looping. */+						break;+					case ARCHIVE_OK:+						/* Break loop. */+						looping = 0;+						break;+					default:+						/* Forward any errors to the+						 * caller. */+						return lret;+				}+			}++			break;+		} else {+			/* Skip current base block. In order to properly skip+			 * it, we really need to simply parse it and discard+			 * the results. */++			lret = skip_base_block(a);+			if(lret == ARCHIVE_FATAL || lret == ARCHIVE_FAILED)+				return lret;++			/* The `skip_base_block` function tells us if we+			 * should continue with skipping, or we should stop+			 * skipping. We're trying to skip everything up to+			 * a base FILE block. */++			if(lret != ARCHIVE_RETRY) {+				/* If there was an error during skipping, or we+				 * have just skipped a FILE base block... */++				if(rar5->main.endarc == 0) {+					return lret;+				} else {+					continue;+				}+			}+		}+	}++	return ARCHIVE_OK;+}++/* Merges the partial block from the first multivolume archive file, and+ * partial block from the second multivolume archive file. The result is+ * a chunk of memory containing the whole block, and the stream pointer+ * is advanced to the next block in the second multivolume archive file. */+static int merge_block(struct archive_read* a, ssize_t block_size,+    const uint8_t** p)+{+	struct rar5 *rar5 = a->format->data;+	ssize_t cur_block_size, partial_offset = 0;+	const uint8_t* lp;+	int ret;++	if(rar5->merge_mode) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+		    "Recursive merge is not allowed");++		return ARCHIVE_FATAL;+	}++	/* Set a flag that we're in the switching mode. */+	rar5->cstate.switch_multivolume = 1;++	/* Reallocate the memory which will hold the whole block. */+	if(rar5->vol.push_buf)+		free((void*) rar5->vol.push_buf);++	/* Increasing the allocation block by 8 is due to bit reading functions,+	 * which are using additional 2 or 4 bytes. Allocating the block size+	 * by exact value would make bit reader perform reads from invalid+	 * memory block when reading the last byte from the buffer. */+	rar5->vol.push_buf = malloc(block_size + 8);+	if(!rar5->vol.push_buf) {+		archive_set_error(&a->archive, ENOMEM,+		    "Can't allocate memory for a merge block buffer");+		rar5->cstate.switch_multivolume = 0;+		return ARCHIVE_FATAL;+	}++	/* Valgrind complains if the extension block for bit reader is not+	 * initialized, so initialize it. */+	memset(&rar5->vol.push_buf[block_size], 0, 8);++	/* A single block can span across multiple multivolume archive files,+	 * so we use a loop here. This loop will consume enough multivolume+	 * archive files until the whole block is read. */++	while(1) {+		/* Get the size of current block chunk in this multivolume+		 * archive file and read it. */+		cur_block_size = rar5_min(rar5->file.bytes_remaining,+		    block_size - partial_offset);++		if(cur_block_size < 1) {+			/* bytes_remaining is less than 1 at the wrong point in+			 * the merge loop, indicating corrupt volume+			 * accounting. */+			archive_set_error(&a->archive,+			    ARCHIVE_ERRNO_FILE_FORMAT,+			    "Encountered invalid block size during block merge");+			rar5->cstate.switch_multivolume = 0;+			return ARCHIVE_FATAL;+		}++		if(!read_ahead(a, cur_block_size, &lp)) {+			rar5->cstate.switch_multivolume = 0;+			return ARCHIVE_EOF;+		}++		/* Sanity check; there should never be a situation where this+		 * function reads more data than the block's size. */+		if(partial_offset + cur_block_size > block_size) {+			archive_set_error(&a->archive,+			    ARCHIVE_ERRNO_PROGRAMMER,+			    "Consumed too much data when merging blocks");+			rar5->cstate.switch_multivolume = 0;+			return ARCHIVE_FATAL;+		}++		/* Merge previous block chunk with current block chunk,+		 * or create first block chunk if this is our first+		 * iteration. */+		memcpy(&rar5->vol.push_buf[partial_offset], lp, cur_block_size);++		/* Advance the stream read pointer by this block chunk size. */+		if(ARCHIVE_OK != consume(a, cur_block_size)) {+			/* Data was copied but stream pointer didn't advance;+			 * stream position is unrecoverable. */+			rar5->cstate.switch_multivolume = 0;+			return ARCHIVE_FATAL;+		}++		/* Update the pointers. `partial_offset` contains information+		 * about the sum of merged block chunks. */+		partial_offset += cur_block_size;+		rar5->file.bytes_remaining -= cur_block_size;++		/* If `partial_offset` is the same as `block_size`, this means+		 * we've merged all block chunks and we have a valid full+		 * block. */+		if(partial_offset == block_size) {+			break;+		}++		/* If we don't have any bytes to read, this means we should+		 * switch to another multivolume archive file. */+		if(rar5->file.bytes_remaining == 0) {+			rar5->merge_mode++;+			ret = advance_multivolume(a);+			rar5->merge_mode--;+			if(ret != ARCHIVE_OK) {+				rar5->cstate.switch_multivolume = 0;+				return ret;+			}+		}+	}++	*p = rar5->vol.push_buf;++	/* If we're here, we can resume unpacking by processing the block+	 * pointed to by the `*p` memory pointer. */++	return ARCHIVE_OK;+}++static int process_block(struct archive_read* a) {+	struct rar5 *rar5 = a->format->data;+	const uint8_t* p;+	int ret;++	/* If we don't have any data to be processed, this most probably means+	 * we need to switch to the next volume. */+	if(rar5->main.volume && rar5->file.bytes_remaining == 0) {+		ret = advance_multivolume(a);+		if(ret != ARCHIVE_OK)+			return ret;+	}++	if(rar5->cstate.block_parsing_finished) {+		ssize_t block_size;+		ssize_t to_skip;+		ssize_t cur_block_size;++		/* The header size won't be bigger than 6 bytes. */+		if(!read_ahead(a, 6, &p)) {+			/* Failed to prefetch data block header. */+			return ARCHIVE_EOF;+		}++		/*+		 * Read block_size by parsing block header. Validate the header+		 * by calculating CRC byte stored inside the header. Size of+		 * the header is not constant (block size can be stored either+		 * in 1 or 2 bytes), that's why block size is left out from the+		 * `compressed_block_header` structure and returned by+		 * `parse_block_header` as the second argument. */++		ret = parse_block_header(a, p, &block_size,+		    &rar5->last_block_hdr);+		if(ret != ARCHIVE_OK) {+			return ret;+		}++		/* Skip block header. Next data is huffman tables,+		 * if present. */+		to_skip = sizeof(struct compressed_block_header) ++			bf_byte_count(&rar5->last_block_hdr) + 1;++		/* If the block header's to_skip value exceeds the declared+		 * remaining data, the archive is malformed. */+		if(to_skip > rar5->file.bytes_remaining) {+			archive_set_error(&a->archive,+			    ARCHIVE_ERRNO_FILE_FORMAT,+			    "Block header size exceeds remaining file data");+			return ARCHIVE_FATAL;+		}++		if(ARCHIVE_OK != consume(a, to_skip))+			return ARCHIVE_EOF;++		rar5->file.bytes_remaining -= to_skip;++		/* The block size gives information about the whole block size,+		 * but the block could be stored in split form when using+		 * multi-volume archives. In this case, the block size will be+		 * bigger than the actual data stored in this file. Remaining+		 * part of the data will be in another file. */++		cur_block_size =+			rar5_min(rar5->file.bytes_remaining, block_size);++		if(block_size > rar5->file.bytes_remaining) {+			/* If current blocks' size is bigger than our data+			 * size, this means we have a multivolume archive.+			 * In this case, skip all base headers until the end+			 * of the file, proceed to next "partXXX.rar" volume,+			 * find its signature, skip all headers up to the first+			 * FILE base header, and continue from there.+			 *+			 * Note that `merge_block` will update the `rar`+			 * context structure quite extensively. */++			ret = merge_block(a, block_size, &p);+			if(ret != ARCHIVE_OK) {+				return ret;+			}++			cur_block_size = block_size;++			/* Current stream pointer should be now directly+			 * *after* the block that spanned through multiple+			 * archive files. `p` pointer should have the data of+			 * the *whole* block (merged from partial blocks+			 * stored in multiple archives files). */+		} else {+			rar5->cstate.switch_multivolume = 0;++			/* Read the whole block size into memory. This can take+			 * up to  8 megabytes of memory in theoretical cases.+			 * Might be worth to optimize this and use a standard+			 * chunk of 4kb's. */+			if(!read_ahead(a, 4 + cur_block_size, &p)) {+				/* Failed to prefetch block data. */+				return ARCHIVE_EOF;+			}+		}++		rar5->cstate.block_buf = p;+		rar5->cstate.cur_block_size = cur_block_size;+		rar5->cstate.block_parsing_finished = 0;++		rar5->bits.in_addr = 0;+		rar5->bits.bit_addr = 0;++		if(bf_is_table_present(&rar5->last_block_hdr)) {+			/* Load Huffman tables. */+			ret = parse_tables(a, rar5, p);+			if(ret != ARCHIVE_OK) {+				/* Error during decompression of Huffman+				 * tables. */+				return ret;+			}+		}+	} else {+		/* Block parsing not finished, reuse previous memory buffer. */+		p = rar5->cstate.block_buf;+	}++	/* Uncompress the block, or a part of it, depending on how many bytes+	 * will be generated by uncompressing the block.+	 *+	 * In case too many bytes will be generated, calling this function+	 * again will resume the uncompression operation. */+	ret = do_uncompress_block(a, p);+	if(ret != ARCHIVE_OK) {+		return ret;+	}++	if(rar5->cstate.block_parsing_finished &&+	    rar5->cstate.switch_multivolume == 0 &&+	    rar5->cstate.cur_block_size > 0)+	{+		/* If we're processing a normal block, consume the whole+		 * block. We can do this because we've already read the whole+		 * block to memory. */+		if(ARCHIVE_OK != consume(a, rar5->cstate.cur_block_size))+			return ARCHIVE_FATAL;++		rar5->file.bytes_remaining -= rar5->cstate.cur_block_size;+	} else if(rar5->cstate.switch_multivolume) {+		/* Don't consume the block if we're doing multivolume+		 * processing. The volume switching function will consume+		 * the proper count of bytes instead. */+		rar5->cstate.switch_multivolume = 0;+	}++	return ARCHIVE_OK;+}++/* Pops the `buf`, `size` and `offset` from the "data ready" stack.+ *+ * Returns ARCHIVE_OK when those arguments can be used, ARCHIVE_RETRY+ * when there is no data on the stack. */+static int use_data(struct rar5 *rar5, const void** buf, size_t* size,+    int64_t* offset)+{+	int i;++	for(i = 0; i < rar5_countof(rar5->cstate.dready); i++) {+		struct data_ready *d = &rar5->cstate.dready[i];++		if(d->used) {+			if(buf)    *buf = d->buf;+			if(size)   *size = d->size;+			if(offset) *offset = d->offset;++			d->used = 0;+			return ARCHIVE_OK;+		}+	}++	return ARCHIVE_RETRY;+}++static void clear_data_ready_stack(struct rar5 *rar5) {+	memset(&rar5->cstate.dready, 0, sizeof(rar5->cstate.dready));+}++/* Pushes the `buf`, `size` and `offset` arguments to the rar5->cstate.dready+ * FIFO stack. Those values will be popped from this stack by the `use_data`+ * function. */+static int push_data_ready(struct archive_read* a, struct rar5 *rar5,+    const uint8_t* buf, size_t size, int64_t offset)+{+	int i;++	/* Don't push if we're in skip mode. This is needed because solid+	 * streams need full processing even if we're skipping data. After+	 * fully processing the stream, we need to discard the generated bytes,+	 * because we're interested only in the side effect: building up the+	 * internal window circular buffer. This window buffer will be used+	 * later during unpacking of requested data. */+	if(rar5->skip_mode)+		return ARCHIVE_OK;++	/* Sanity check. */+	if(offset != rar5->file.last_offset + rar5->file.last_size) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+		    "Sanity check error: output stream is not continuous");+		return ARCHIVE_FATAL;+	}++	for(i = 0; i < rar5_countof(rar5->cstate.dready); i++) {+		struct data_ready* d = &rar5->cstate.dready[i];+		if(!d->used) {+			d->used = 1;+			d->buf = buf;+			d->size = size;+			d->offset = offset;++			/* These fields are used only in sanity checking. */+			rar5->file.last_offset = offset;+			rar5->file.last_size = size;++			/* Calculate the checksum of this new block before+			 * submitting data to libarchive's engine. */+			update_crc(rar5, d->buf, d->size);++			return ARCHIVE_OK;+		}+	}++	/* Program counter will reach this code if the+	 * `rar5->cstate.data_ready` stack will be filled up so that no new+	 * entries will be allowed. The code shouldn't allow such situation to+	 * occur. So we treat this case as an internal error. */++	archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+	    "Premature end of data_ready stack");+	return ARCHIVE_FATAL;+}++/* This function uncompresses the data that is stored in the <FILE> base+ * block.+ *+ * The FILE base block looks like this:+ *+ * <header><huffman tables><block_1><block_2>...<block_n>+ *+ * The <header> is a block header, that is parsed in parse_block_header().+ * It's a "compressed_block_header" structure, containing metadata needed+ * to know when we should stop looking for more <block_n> blocks.+ *+ * <huffman tables> contain data needed to set up the huffman tables, needed+ * for the actual decompression.+ *+ * Each <block_n> consists of series of literals:+ *+ * <literal><literal><literal>...<literal>+ *+ * Those literals generate the uncompression data. They operate on a circular+ * buffer, sometimes writing raw data into it, sometimes referencing+ * some previous data inside this buffer, and sometimes declaring a filter+ * that will need to be executed on the data stored in the circular buffer.+ * It all depends on the literal that is used.+ *+ * Sometimes blocks produce output data, sometimes they don't. For example, for+ * some huge files that use lots of filters, sometimes a block is filled with+ * only filter declaration literals. Such blocks won't produce any data in the+ * circular buffer.+ *+ * Sometimes blocks will produce 4 bytes of data, and sometimes 1 megabyte,+ * because a literal can reference previously decompressed data. For example,+ * there can be a literal that says: 'append a byte 0xFE here', and after+ * it another literal can say 'append 1 megabyte of data from circular buffer+ * offset 0x12345'. This is how RAR format handles compressing repeated+ * patterns.+ *+ * The RAR compressor creates those literals and the actual efficiency of+ * compression depends on what those literals are. The literals can also+ * be seen as a kind of a non-turing-complete virtual machine that simply+ * tells the decompressor what it should do.+ * */++static int do_uncompress_file(struct archive_read* a) {+	struct rar5 *rar5 = a->format->data;+	int ret;+	int64_t max_end_pos;++	if(!rar5->cstate.initialized) {+		/* Don't perform full context reinitialization if we're+		 * processing a solid archive. */+		if(!rar5->main.solid || !rar5->cstate.window_buf) {+			if((ret = init_unpack(rar5)) != ARCHIVE_OK)+				return ret;+		}++		rar5->cstate.initialized = 1;+	}++	/* Don't allow extraction if window_size is invalid. */+	if(rar5->cstate.window_size == 0) {+		archive_set_error(&a->archive,+			ARCHIVE_ERRNO_FILE_FORMAT,+			"Invalid window size declaration in this file");++		/* This should never happen in valid files. */+		return ARCHIVE_FAILED;+	}++	if(rar5->cstate.all_filters_applied == 1) {+		/* We use while(1) here, but standard case allows for just 1+		 * iteration. The loop will iterate if process_block() didn't+		 * generate any data at all. This can happen if the block+		 * contains only filter definitions (this is common in big+		 * files). */+		while(1) {+			ret = process_block(a);+			if(ret != ARCHIVE_OK)+				return ret;++			if(rar5->cstate.last_write_ptr ==+			    rar5->cstate.write_ptr) {+				/* The block didn't generate any new data,+				 * so just process a new block if this one+				 * wasn't the last block in the file. */+				if (bf_is_last_block(&rar5->last_block_hdr)) {+					return ARCHIVE_EOF;+				}++				continue;+			}++			/* The block has generated some new data, so break+			 * the loop. */+			break;+		}+	}++	/* Try to run filters. If filters won't be applied, it means that+	 * insufficient data was generated. */+	ret = apply_filters(a);+	if(ret == ARCHIVE_RETRY) {+		return ARCHIVE_OK;+	} else if(ret != ARCHIVE_OK) {+		return ret;+	}++	if(cdeque_size(&rar5->cstate.filters) > 0) {+		/* Check if we can write something before hitting first+		 * filter. */+		struct filter_info* flt;++		/* Get the block_start offset from the first filter. */+		if(CDE_OK != cdeque_front(&rar5->cstate.filters,+		    cdeque_filter_p(&flt)))+		{+			archive_set_error(&a->archive,+			    ARCHIVE_ERRNO_PROGRAMMER,+			    "Can't read first filter");+			return ARCHIVE_FATAL;+		}++		max_end_pos = rar5_min(flt->block_start,+		    rar5->cstate.write_ptr);+	} else {+		/* There are no filters defined, or all filters were applied.+		 * This means we can just store the data without any+		 * postprocessing. */+		max_end_pos = rar5->cstate.write_ptr;+	}++	if(max_end_pos == rar5->cstate.last_write_ptr) {+		/* We can't write anything yet. The block uncompression+		 * function did not generate enough data, and no filter can be+		 * applied. At the same time we don't have any data that can be+		 *  stored without filter postprocessing. This means we need to+		 *  wait for more data to be generated, so we can apply the+		 * filters.+		 *+		 * Signal the caller that we need more data to be able to do+		 * anything.+		 */+		return ARCHIVE_RETRY;+	} else {+		/* We can write the data before hitting the first filter.+		 * So let's do it. The push_window_data() function will+		 * effectively return the selected data block to the user+		 * application. */+		push_window_data(a, rar5, rar5->cstate.last_write_ptr,+		    max_end_pos);+		rar5->cstate.last_write_ptr = max_end_pos;+	}++	return ARCHIVE_OK;+}++static int uncompress_file(struct archive_read* a) {+	int ret;++	while(1) {+		/* Sometimes the uncompression function will return a+		 * 'retry' signal. If this will happen, we have to retry+		 * the function. */+		ret = do_uncompress_file(a);+		if(ret != ARCHIVE_RETRY)+			return ret;+	}+}+++static int do_unstore_file(struct archive_read* a,+    struct rar5 *rar5, const void** buf, size_t* size, int64_t* offset)+{+	size_t to_read;+	const uint8_t* p;++	if(rar5->file.bytes_remaining == 0 && rar5->main.volume > 0 &&+	    rar5->generic.split_after > 0)+	{+		int ret;++		rar5->cstate.switch_multivolume = 1;+		ret = advance_multivolume(a);+		rar5->cstate.switch_multivolume = 0;++		if(ret != ARCHIVE_OK) {+			/* Failed to advance to next multivolume archive+			 * file. */+			return ret;+		}+	}++	to_read = rar5_min(rar5->file.bytes_remaining, 64 * 1024);+	if(to_read == 0) {+		return ARCHIVE_EOF;+	}++	if(!read_ahead(a, to_read, &p)) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "I/O error when unstoring file");+		return ARCHIVE_FATAL;+	}++	if(ARCHIVE_OK != consume(a, to_read)) {+		return ARCHIVE_EOF;+	}++	if(buf)    *buf = p;+	if(size)   *size = to_read;+	if(offset) *offset = rar5->cstate.last_unstore_ptr;++	rar5->file.bytes_remaining -= to_read;+	rar5->cstate.last_unstore_ptr += to_read;++	update_crc(rar5, p, to_read);+	return ARCHIVE_OK;+}++static int do_unpack(struct archive_read* a, struct rar5 *rar5,+    const void** buf, size_t* size, int64_t* offset)+{+	enum COMPRESSION_METHOD {+		STORE = 0, FASTEST = 1, FAST = 2, NORMAL = 3, GOOD = 4,+		BEST = 5+	};++	if(rar5->file.service > 0) {+		return do_unstore_file(a, rar5, buf, size, offset);+	} else {+		switch(rar5->cstate.method) {+			case STORE:+				return do_unstore_file(a, rar5, buf, size,+				    offset);+			case FASTEST:+				/* fallthrough */+			case FAST:+				/* fallthrough */+			case NORMAL:+				/* fallthrough */+			case GOOD:+				/* fallthrough */+			case BEST:+				/* No data is returned here. But because a sparse-file aware+				 * caller (like archive_read_data_into_fd) may treat zero-size+				 * as a sparse file block, we need to update the offset+				 * accordingly. At this point the decoder doesn't have any+				 * pending uncompressed data blocks, so the current position in+				 * the output file should be last_write_ptr. */+				if (offset) *offset = rar5->cstate.last_write_ptr;+				return uncompress_file(a);+			default:+				archive_set_error(&a->archive,+				    ARCHIVE_ERRNO_FILE_FORMAT,+				    "Compression method not supported: 0x%x",+				    (unsigned int)rar5->cstate.method);++				return ARCHIVE_FATAL;+		}+	}++#if !defined WIN32+	/* Not reached. */+	return ARCHIVE_OK;+#endif+}++static int verify_checksums(struct archive_read* a) {+	struct rar5 *rar5 = a->format->data;+	int verify_crc;++	/* Check checksums only when actually unpacking the data. There's no+	 * need to calculate checksum when we're skipping data in solid archives+	 * (skipping in solid archives is the same thing as unpacking compressed+	 * data and discarding the result). */++	if(!rar5->skip_mode) {+		/* Always check checksums if we're not in skip mode */+		verify_crc = 1;+	} else {+		/* We can override the logic above with a compile-time option+		 * NO_CRC_ON_SOLID_SKIP. This option is used during debugging,+		 * and it will check checksums of unpacked data even when+		 * we're skipping it. */++#if defined CHECK_CRC_ON_SOLID_SKIP+		/* Debug case */+		verify_crc = 1;+#else+		/* Normal case */+		verify_crc = 0;+#endif+	}++	if(verify_crc) {+		/* During unpacking, on each unpacked block we're calling the+		 * update_crc() function. Since we are here, the unpacking+		 * process is already over and we can check if calculated+		 * checksum (CRC32 or BLAKE2sp) is the same as what is stored+		 * in the archive. */+		if(rar5->file.stored_crc32 > 0) {+			/* Check CRC32 only when the file contains a CRC32+			 * value for this file. */++			if(rar5->file.calculated_crc32 !=+			    rar5->file.stored_crc32) {+				/* Checksums do not match; the unpacked file+				 * is corrupted. */++				DEBUG_CODE {+					printf("Checksum error: CRC32 "+					    "(was: %08" PRIx32 ", expected: %08" PRIx32 ")\n",+					    rar5->file.calculated_crc32,+					    rar5->file.stored_crc32);+				}++#ifndef DONT_FAIL_ON_CRC_ERROR+				archive_set_error(&a->archive,+				    ARCHIVE_ERRNO_FILE_FORMAT,+				    "Checksum error: CRC32");+				return ARCHIVE_FAILED;+#endif+			} else {+				DEBUG_CODE {+					printf("Checksum OK: CRC32 "+					    "(%08" PRIx32 "/%08" PRIx32 ")\n",+					    rar5->file.stored_crc32,+					    rar5->file.calculated_crc32);+				}+			}+		}++		if(rar5->file.has_blake2 > 0) {+			/* BLAKE2sp is an optional checksum algorithm that is+			 * added to RARv5 archives when using the `-htb` switch+			 *  during creation of archive.+			 *+			 * We now finalize the hash calculation by calling the+			 * `final` function. This will generate the final hash+			 * value we can use to compare it with the BLAKE2sp+			 * checksum that is stored in the archive.+			 *+			 * The return value of this `final` function is not+			 * very helpful, as it guards only against improper use.+ 			 * This is why we're explicitly ignoring it. */++			uint8_t b2_buf[32];+			(void) blake2sp_final(&rar5->file.b2state, b2_buf, 32);++			if(memcmp(&rar5->file.blake2sp, b2_buf, 32) != 0) {+#ifndef DONT_FAIL_ON_CRC_ERROR+				archive_set_error(&a->archive,+				    ARCHIVE_ERRNO_FILE_FORMAT,+				    "Checksum error: BLAKE2");++				return ARCHIVE_FAILED;+#endif+			}+		}+	}++	/* Finalization for this file has been successfully completed. */+	return ARCHIVE_OK;+}++static int verify_global_checksums(struct archive_read* a) {+	return verify_checksums(a);+}++/*+ * Decryption function for the magic signature pattern. Check the comment near+ * the `rar5_signature_xor` symbol to read the rationale behind this.+ */+static void rar5_signature(char *buf) {+		size_t i;++		for(i = 0; i < sizeof(rar5_signature_xor); i++) {+			buf[i] = rar5_signature_xor[i] ^ 0xA1;+		}+}++static int rar5_read_data(struct archive_read *a, const void **buff,+    size_t *size, int64_t *offset) {+	struct rar5 *rar5 = a->format->data;+	int ret;++	if (size)+		*size = 0;++	if (rar5->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {+		rar5->has_encrypted_entries = 0;+	}++	if (rar5->headers_are_encrypted || rar5->cstate.data_encrypted) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Reading encrypted data is not currently supported");+		return ARCHIVE_FAILED;+	}++	if(rar5->file.dir > 0) {+		/* Don't process any data if this file entry was declared+		 * as a directory. This is needed, because entries marked as+		 * directory doesn't have any dictionary buffer allocated, so+		 * it's impossible to perform any decompression. */+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Can't decompress an entry marked as a directory");+		return ARCHIVE_FATAL;+	}++	if(!rar5->skip_mode && (rar5->cstate.last_write_ptr > rar5->file.unpacked_size)) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,+		    "Unpacker has written too many bytes");+		return ARCHIVE_FATAL;+	}++	ret = use_data(rar5, buff, size, offset);+	if(ret == ARCHIVE_OK) {+		return ret;+	}++	if(rar5->file.eof == 1) {+		return ARCHIVE_EOF;+	}++	ret = do_unpack(a, rar5, buff, size, offset);+	if(ret != ARCHIVE_OK) {+		return ret;+	}++	if(rar5->file.bytes_remaining == 0 &&+			rar5->cstate.last_write_ptr == rar5->file.unpacked_size)+	{+		/* If all bytes of current file were processed, run+		 * finalization.+		 *+		 * Finalization will check checksum against proper values. If+		 * some of the checksums will not match, we'll return an error+		 * value in the last `archive_read_data` call to signal an error+		 * to the user. */++		rar5->file.eof = 1;+		return verify_global_checksums(a);+	}++	return ARCHIVE_OK;+}++static int rar5_read_data_skip(struct archive_read *a) {+	struct rar5 *rar5 = a->format->data;++	if(rar5->main.solid && (rar5->cstate.data_encrypted == 0)) {+		/* In solid archives, instead of skipping the data, we need to+		 * extract it, and dispose the result. The side effect of this+		 * operation will be setting up the initial window buffer state+		 * needed to be able to extract the selected file. Note that+		 * this is only possible when data within this solid block is+		 * not encrypted, in which case we'll skip and fail if the user+		 * tries to read data. */++		int ret;++		/* Make sure to process all blocks in the compressed stream. */+		while(rar5->file.bytes_remaining > 0) {+			/* Setting the "skip mode" will allow us to skip+			 * checksum checks during data skipping. Checking the+			 * checksum of skipped data isn't really necessary and+			 * it's only slowing things down.+			 *+			 * This is incremented instead of setting to 1 because+			 * this data skipping function can be called+			 * recursively. */+			rar5->skip_mode++;++			/* We're disposing 1 block of data, so we use triple+			 * NULLs in arguments. */+			ret = rar5_read_data(a, NULL, NULL, NULL);++			/* Turn off "skip mode". */+			rar5->skip_mode--;++			if(ret < 0 || ret == ARCHIVE_EOF) {+				/* Propagate any potential error conditions+				 * to the caller. */+				return ret;+			}+		}+	} else {+		/* In standard archives, we can just jump over the compressed+		 * stream. Each file in non-solid archives starts from an empty+		 * window buffer. */++		if(ARCHIVE_OK != consume(a, rar5->file.bytes_remaining)) {+			return ARCHIVE_FATAL;+		}++		rar5->file.bytes_remaining = 0;+	}++	return ARCHIVE_OK;+}++static int64_t rar5_seek_data(struct archive_read *a, int64_t offset,+    int whence)+{+	(void) offset;+	(void) whence;++	/* We're a streaming unpacker, and we don't support seeking.+	 * That's a capability gap, not a fatal error. */+	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+	    "Seeking of RAR5 files is unsupported");++	return (ARCHIVE_FAILED);+}++static int rar5_cleanup(struct archive_read *a) {+	struct rar5 *rar5 = a->format->data;++	free(rar5->cstate.window_buf);+	free(rar5->cstate.filtered_buf);+	clear_data_ready_stack(rar5);++	free(rar5->vol.push_buf);++	free_filters(rar5);+	rar5_deinit(rar5);++	free(rar5);+	a->format->data = NULL;++	return ARCHIVE_OK;+}++static int rar5_capabilities(struct archive_read * a) {+	(void) a;+	return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA+			| ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);+}++static int rar5_has_encrypted_entries(struct archive_read *_a) {+	if (_a && _a->format) {+		struct rar5 *rar5 = _a->format->data;+		if (rar5) {+			return rar5->has_encrypted_entries;+		}+	}++	return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;+}++/* Must match deallocations in rar5_deinit */+static int rar5_init(struct rar5 *rar5) {+	memset(rar5, 0, sizeof(struct rar5));++	if(CDE_OK != cdeque_init(&rar5->cstate.filters, 8192))+		return ARCHIVE_FATAL;++	/*+	 * Until enough data has been read, we cannot tell about+	 * any encrypted entries yet.+	 */+	rar5->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;++	return ARCHIVE_OK;+}++/* Must match allocations in rar5_init */+static void rar5_deinit(struct rar5 *rar5) {+	cdeque_free(&rar5->cstate.filters);+}++int archive_read_support_format_rar5(struct archive *_a) {+	struct archive_read* ar;+	int ret;+	struct rar5 *rar5;++	if(ARCHIVE_OK != (ret = get_archive_read(_a, &ar)))+		return ret;++	rar5 = malloc(sizeof(*rar5));+	if(rar5 == NULL) {+		archive_set_error(&ar->archive, ENOMEM,+		    "Can't allocate rar5 data");+		return ARCHIVE_FATAL;+	}++	if(ARCHIVE_OK != rar5_init(rar5)) {+		archive_set_error(&ar->archive, ENOMEM,+		    "Can't allocate rar5 filter buffer");+		free(rar5);+		return ARCHIVE_FATAL;+	}++	ret = __archive_read_register_format(ar,+	    rar5,+	    "rar5",+	    rar5_bid,+	    rar5_options,+	    rar5_read_header,+	    rar5_read_data,+	    rar5_read_data_skip,+	    rar5_seek_data,+	    rar5_cleanup,+	    rar5_capabilities,+	    rar5_has_encrypted_entries);++	if(ret != ARCHIVE_OK) {+		rar5_deinit(rar5);+		free(rar5); 	}  	return ARCHIVE_OK;
c/archive_read_support_format_raw.c view
@@ -34,10 +34,11 @@  #include "archive.h" #include "archive_entry.h"+#include "archive_integer.h" #include "archive_private.h" #include "archive_read_private.h" -struct raw_info {+struct raw { 	int64_t offset; /* Current position in the file. */ 	int64_t unconsumed; 	int     end_of_file;@@ -54,22 +55,22 @@ int archive_read_support_format_raw(struct archive *_a) {-	struct raw_info *info; 	struct archive_read *a = (struct archive_read *)_a;+	struct raw *raw; 	int r;  	archive_check_magic(_a, ARCHIVE_READ_MAGIC, 	    ARCHIVE_STATE_NEW, "archive_read_support_format_raw"); -	info = calloc(1, sizeof(*info));-	if (info == NULL) {+	raw = calloc(1, sizeof(*raw));+	if (raw == NULL) { 		archive_set_error(&a->archive, ENOMEM,-		    "Can't allocate raw_info data");+		    "Can't allocate raw data"); 		return (ARCHIVE_FATAL); 	}  	r = __archive_read_register_format(a,-	    info,+	    raw, 	    "raw", 	    archive_read_format_raw_bid, 	    NULL,@@ -81,7 +82,7 @@ 	    NULL, 	    NULL); 	if (r != ARCHIVE_OK)-		free(info);+		free(raw); 	return (r); } @@ -107,10 +108,9 @@ archive_read_format_raw_read_header(struct archive_read *a,     struct archive_entry *entry) {-	struct raw_info *info;+	struct raw *raw = a->format->data; -	info = (struct raw_info *)(a->format->data);-	if (info->end_of_file)+	if (raw->end_of_file) 		return (ARCHIVE_EOF);  	a->archive.archive_format = ARCHIVE_FORMAT_RAW;@@ -128,39 +128,43 @@ archive_read_format_raw_read_data(struct archive_read *a,     const void **buff, size_t *size, int64_t *offset) {-	struct raw_info *info;+	struct raw *raw = a->format->data; 	ssize_t avail; -	info = (struct raw_info *)(a->format->data);- 	/* Consume the bytes we read last time. */-	if (info->unconsumed) {-		__archive_read_consume(a, info->unconsumed);-		info->unconsumed = 0;+	if (raw->unconsumed) {+		__archive_read_consume(a, raw->unconsumed);+		raw->unconsumed = 0; 	} -	if (info->end_of_file)+	if (raw->end_of_file) 		return (ARCHIVE_EOF);  	/* Get whatever bytes are immediately available. */ 	*buff = __archive_read_ahead(a, 1, &avail); 	if (avail > 0) { 		/* Return the bytes we just read */+		*offset = raw->offset;+		if (archive_ckd_add_i64(&raw->offset, raw->offset, avail)) {+			avail = INT64_MAX - *offset;+			if (avail == 0) {+				*size = 0;+				return (ARCHIVE_FATAL);+			}+		} 		*size = avail;-		*offset = info->offset;-		info->offset += *size;-		info->unconsumed = avail;+		raw->unconsumed = avail; 		return (ARCHIVE_OK); 	} else if (0 == avail) { 		/* Record and return end-of-file. */-		info->end_of_file = 1;+		raw->end_of_file = 1; 		*size = 0;-		*offset = info->offset;+		*offset = raw->offset; 		return (ARCHIVE_EOF); 	} else { 		/* Record and return an error. */ 		*size = 0;-		*offset = info->offset;+		*offset = raw->offset; 		return ((int)avail); 	} }@@ -168,24 +172,23 @@ static int archive_read_format_raw_read_data_skip(struct archive_read *a) {-	struct raw_info *info = (struct raw_info *)(a->format->data);+	struct raw *raw = a->format->data;  	/* Consume the bytes we read last time. */-	if (info->unconsumed) {-		__archive_read_consume(a, info->unconsumed);-		info->unconsumed = 0;+	if (raw->unconsumed) {+		__archive_read_consume(a, raw->unconsumed);+		raw->unconsumed = 0; 	}-	info->end_of_file = 1;+	raw->end_of_file = 1; 	return (ARCHIVE_OK); }  static int archive_read_format_raw_cleanup(struct archive_read *a) {-	struct raw_info *info;+	struct raw *raw = a->format->data; -	info = (struct raw_info *)(a->format->data);-	free(info);+	free(raw); 	a->format->data = NULL; 	return (ARCHIVE_OK); }
c/archive_read_support_format_tar.c view
@@ -251,36 +251,6 @@ static const size_t acl_limit = 131072; /* Longest textual ACL: 128kiB */ static const int64_t entry_limit = 0xfffffffffffffffLL; /* 2^60 bytes = 1 ExbiByte */ -/*- * There's no standard for TIME_T_MAX.  So we compute it- * here.  TODO: Move this to configure time, but be careful- * about cross-compile environments.- */-static time_t-get_time_t_max(void)-{-#if defined(TIME_T_MAX)-        return TIME_T_MAX;-#else-        /* ISO C allows time_t to be a floating-point type,-           but POSIX requires an integer type.  The following-           should work on any system that follows the POSIX-           conventions. */-        if (((time_t)0) < ((time_t)-1)) {-                /* Time_t is unsigned */-                return (~(time_t)0);-        } else {-                /* Time_t is signed. */-                /* Assume it's the same as int64_t or int32_t */-                if (sizeof(time_t) == sizeof(int64_t)) {-                        return (time_t)INT64_MAX;-                } else {-                        return (time_t)INT32_MAX;-                }-        }-#endif-}- int archive_read_support_format_gnutar(struct archive *a) {@@ -330,9 +300,8 @@ static int archive_read_format_tar_cleanup(struct archive_read *a) {-	struct tar *tar;+	struct tar *tar = a->format->data; -	tar = (struct tar *)(a->format->data); 	gnu_clear_sparse_list(tar); 	archive_string_free(&tar->entry_pathname); 	archive_string_free(&tar->entry_pathname_override);@@ -342,7 +311,7 @@ 	archive_string_free(&tar->line); 	archive_string_free(&tar->localname); 	free(tar);-	(a->format->data) = NULL;+	a->format->data = NULL; 	return (ARCHIVE_OK); } @@ -469,10 +438,9 @@ archive_read_format_tar_options(struct archive_read *a,     const char *key, const char *val) {-	struct tar *tar;+	struct tar *tar = a->format->data; 	int ret = ARCHIVE_FAILED; -	tar = (struct tar *)(a->format->data); 	if (strcmp(key, "compat-2x")  == 0) { 		/* Handle UTF-8 filenames as libarchive 2.x */ 		tar->compat_2x = (val != NULL && val[0] != 0);@@ -555,15 +523,13 @@ 	 * probably not worthwhile just to support the relatively 	 * obscure tar->cpio conversion case. 	 */-	struct tar *tar;+	struct tar *tar = a->format->data; 	const char *p; 	const wchar_t *wp; 	int r; 	size_t l; 	int64_t unconsumed = 0; -	tar = (struct tar *)(a->format->data);- 	/* Assign default device/inode values. */ 	archive_entry_set_dev(entry, 1 + tar->default_dev); /* Don't use zero. */ 	archive_entry_set_ino(entry, ++tar->default_inode); /* Don't use zero. */@@ -639,12 +605,10 @@ archive_read_format_tar_read_data(struct archive_read *a,     const void **buff, size_t *size, int64_t *offset) {+	struct tar *tar = a->format->data; 	ssize_t bytes_read;-	struct tar *tar; 	struct sparse_block *p; -	tar = (struct tar *)(a->format->data);- 	for (;;) { 		/* Remove exhausted entries from sparse list. */ 		while (tar->sparse_list != NULL &&@@ -703,11 +667,9 @@ static int archive_read_format_tar_skip(struct archive_read *a) {+	struct tar *tar = a->format->data; 	int64_t request;-	struct tar* tar; -	tar = (struct tar *)(a->format->data);- 	request = tar->entry_bytes_remaining + tar->entry_padding + 	    tar->entry_bytes_unconsumed; @@ -1104,21 +1066,19 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,     struct archive_entry *entry, const void *h, int64_t *unconsumed) {-	const struct archive_entry_header_ustar *header; 	struct archive_string	 acl_text; 	size_t size; 	int err, acl_type; 	uint64_t type; 	char *acl, *p; -	header = (const struct archive_entry_header_ustar *)h;-	size = (size_t)tar_atol(header->size, sizeof(header->size)); 	archive_string_init(&acl_text); 	err = read_body_to_string(a, tar, &acl_text, h, unconsumed); 	if (err != ARCHIVE_OK) { 		archive_string_free(&acl_text); 		return (err); 	}+	size = archive_strlen(&acl_text);  	/* TODO: Examine the first characters to see if this 	 * is an AIX ACL descriptor.  We'll likely never support@@ -1377,6 +1337,7 @@ 	const struct archive_entry_header_ustar	*header; 	const char *existing_linkpath; 	const wchar_t *existing_wcs_linkpath;+	mode_t header_mode; 	int     err = ARCHIVE_OK;  	header = (const struct archive_entry_header_ustar *)h;@@ -1384,12 +1345,10 @@ 	/* Parse out the numeric fields (all are octal) */  	/* Split mode handling: Set filetype always, perm only if not already set */-	archive_entry_set_filetype(entry,-	    (mode_t)tar_atol(header->mode, sizeof(header->mode)));-	if (!archive_entry_perm_is_set(entry)) {-		archive_entry_set_perm(entry,-			(mode_t)tar_atol(header->mode, sizeof(header->mode)));-	}+	header_mode = (mode_t)tar_atol(header->mode, sizeof(header->mode));+	archive_entry_set_filetype(entry, header_mode);+	if (!archive_entry_perm_is_set(entry))+		archive_entry_set_perm(entry, header_mode);  	/* Set uid, gid, mtime if not already set */ 	if (!archive_entry_uid_is_set(entry)) {@@ -1402,7 +1361,7 @@ 		int64_t t64 = tar_atol(header->mtime, sizeof(header->mtime)); 		time_t t = (time_t)t64; 		if ((int64_t)t != t64) { /* time_t overflowed */-			t = get_time_t_max();+			t = TIME_MAX; 		} 		archive_entry_set_mtime(entry, t, 0); 	}@@ -1679,33 +1638,33 @@ 	const char *p, *name; 	const wchar_t *wp, *wname; -	wname = wp = archive_entry_pathname_w(entry);-	if (wp != NULL) {+	name = p = archive_entry_pathname(entry);+	if (p != NULL) { 		/* Find the last path element. */-		for (; *wp != L'\0'; ++wp) {-			if (wp[0] == '/' && wp[1] != L'\0')-				wname = wp + 1;+		for (; *p != '\0'; ++p) {+			if (p[0] == '/' && p[1] != '\0')+				name = p + 1; 		} 		/* 		 * If last path element starts with "._", then 		 * this is a Mac extension. 		 */-		if (wname[0] == L'.' && wname[1] == L'_' && wname[2] != L'\0')+		if (name[0] == '.' && name[1] == '_' && name[2] != '\0') 			return 1; 	} else { 		/* Find the last path element. */-		name = p = archive_entry_pathname(entry);-		if (p == NULL)-			return (ARCHIVE_FAILED);-		for (; *p != '\0'; ++p) {-			if (p[0] == '/' && p[1] != '\0')-				name = p + 1;+		wname = wp = archive_entry_pathname_w(entry);+		if (wp == NULL)+			return 0;+		for (; *wp != L'\0'; ++wp) {+			if (wp[0] == L'/' && wp[1] != L'\0')+				wname = wp + 1; 		} 		/* 		 * If last path element starts with "._", then 		 * this is a Mac extension. 		 */-		if (name[0] == '.' && name[1] == '_' && name[2] != '\0')+		if (wname[0] == L'.' && wname[1] == L'_' && wname[2] != L'\0') 			return 1; 	} 	/* Not a mac extension */@@ -1787,7 +1746,6 @@ 	const struct archive_entry_header_ustar *header; 	int64_t size, to_consume; -	(void)a; /* UNUSED */ 	(void)tar; /* UNUSED */ 	(void)entry; /* UNUSED */ @@ -1799,6 +1757,11 @@ 		    (long long)size); 		return (ARCHIVE_FATAL); 	}+	if (size == 0) {+		archive_set_error(&a->archive, EINVAL,+		    "Invalid empty pax global extended header");+		return (ARCHIVE_FATAL);+	} 	to_consume = ((size + 511) & ~511); 	*unconsumed += to_consume; 	return (ARCHIVE_OK);@@ -1945,6 +1908,11 @@ 			    (long long)ext_size); 	  return (ARCHIVE_FATAL); 	}+	if (ext_size == 0) {+		archive_set_error(&a->archive, EINVAL,+		    "Invalid empty pax extended header");+		return (ARCHIVE_FATAL);+	}  	ext_padding = 0x1ff & (-ext_size); 	if (ext_size > ext_size_limit) {@@ -3056,6 +3024,7 @@ header_gnutar(struct archive_read *a, struct tar *tar,     struct archive_entry *entry, const void *h, int64_t *unconsumed) {+	struct archive_entry_header_gnutar header_copy; 	const struct archive_entry_header_gnutar *header; 	int64_t t; 	int err = ARCHIVE_OK;@@ -3066,8 +3035,14 @@ 	 * filename is stored as in old-style archives. 	 */ +	/*+	 * Sparse extension reads can reuse the callback buffer containing h,+	 * so preserve the main header until common fields are parsed.+	 */+	memcpy(&header_copy, h, sizeof(header_copy));+	header = &header_copy;+ 	/* Copy filename over (to ensure null termination). */-	header = (const struct archive_entry_header_gnutar *)h; 	const char *existing_pathname = archive_entry_pathname(entry); 	const wchar_t *existing_wcs_pathname = archive_entry_pathname_w(entry); 	if ((existing_pathname == NULL || existing_pathname[0] == '\0')@@ -3146,7 +3121,7 @@ 	}  	/* Grab fields common to all tar variants. */-	err = header_common(a, tar, entry, h);+	err = header_common(a, tar, entry, header); 	if (err == ARCHIVE_FATAL) 		return (err); @@ -3469,13 +3444,10 @@ 				return (ARCHIVE_FATAL); 			tar->sparse_last->hole = hole; 		}-		if (length == 0 || *e == '\n') {-			if (length == 0 && *e == '\n') {-				return (ARCHIVE_OK);-			} else {-				return (ARCHIVE_WARN);-			}-		}+		if (length == 0)+			return (ARCHIVE_OK);+		if (*e == '\n')+			return (ARCHIVE_WARN); 		p = e + 1; 		length--; 		hole = hole == 0;@@ -3538,17 +3510,17 @@ 	}  	l = 0;-	if (char_cnt != 0) {+	while (char_cnt != 0) { 		digit = *p - '0';-		while (digit >= 0 && digit < base && char_cnt != 0) {-			if (archive_ckd_mul_i64(&l, l, base) ||-			    archive_ckd_add_i64(&l, l, sign * digit)) {-				 /* Truncate on overflow. */-				return sign < 0 ? INT64_MIN : INT64_MAX;-			}-			digit = *++p - '0';-			char_cnt--;+		if (digit < 0 || digit >= base)+			break;+		if (archive_ckd_mul_i64(&l, l, base) ||+		    archive_ckd_add_i64(&l, l, sign * digit)) {+			 /* Truncate on overflow. */+			return sign < 0 ? INT64_MIN : INT64_MAX; 		}+		p++;+		char_cnt--; 	} 	return l; }
c/archive_read_support_format_warc.c view
@@ -25,28 +25,35 @@  #include "archive_platform.h" -/**- * WARC is standardised by ISO TC46/SC4/WG12 and currently available as- * ISO 28500:2009.- * For the purposes of this file we used the final draft from:+/*+ * An overview of WARC format:+ *+ * WARC files are laid out as a sequence of records.  Each record has+ * a text header followed by a content block whose size is given by+ * Content-Length.  This reader supports WARC/0.12 through WARC/1.0+ * and was written using the final draft that became ISO 28500:2009:  * http://bibnum.bnf.fr/warc/WARC_ISO_28500_version1_latestdraft.pdf  *- * Todo:- * [ ] real-world warcs can contain resources at endpoints ending in /- *     e.g. http://bibnum.bnf.fr/warc/- *     if you're lucky their response contains a Content-Location: header- *     pointing to a unix-compliant filename, in the example above it's- *     Content-Location: http://bibnum.bnf.fr/warc/index.html- *     however, that's not mandated and github for example doesn't follow- *     this convention.- *     We need a set of archive options to control what to do with- *     entries like these, at the moment care is taken to skip them.+ * This reader exposes resource and response records as regular files+ * when they have a usable WARC-Target-URI.  WARC-Date is exposed as+ * ctime, and a Last-Modified record header is exposed as mtime when+ * present.  *- **/+ * TODO: Real-world WARCs can contain resources at endpoints ending in+ * a slash, for example http://bibnum.bnf.fr/warc/.  Some responses+ * include a Content-Location header that points to a Unix-compatible+ * filename such as http://bibnum.bnf.fr/warc/index.html, but WARC does+ * not require that convention and some sites do not follow it.  Until+ * archive options exist to control these entries, this reader skips+ * them instead of creating directory endpoints as files.+ */  #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif+#ifdef HAVE_CTYPE_H+#include <ctype.h>+#endif #ifdef HAVE_ERRNO_H #include <errno.h> #endif@@ -56,40 +63,35 @@ #ifdef HAVE_STRING_H #include <string.h> #endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif-#ifdef HAVE_CTYPE_H-#include <ctype.h>-#endif #ifdef HAVE_TIME_H #include <time.h> #endif  #include "archive.h" #include "archive_entry.h"+#include "archive_integer.h" #include "archive_private.h" #include "archive_read_private.h"  typedef enum { 	WT_NONE,-	/* warcinfo */+	/* WARC info */ 	WT_INFO,-	/* metadata */+	/* Metadata */ 	WT_META,-	/* resource */+	/* Resource */ 	WT_RSRC,-	/* request, unsupported */+	/* Request, unsupported */ 	WT_REQ,-	/* response, unsupported */+	/* Response */ 	WT_RSP,-	/* revisit, unsupported */+	/* Revisit, unsupported */ 	WT_RVIS,-	/* conversion, unsupported */+	/* Conversion, unsupported */ 	WT_CONV,-	/* continuation, unsupported at the moment */+	/* Continuation, currently unsupported */ 	WT_CONT,-	/* invalid type */+	/* Invalid type */ 	LAST_WT } warc_type_t; @@ -103,82 +105,92 @@ 	char *str; } warc_strbuf_t; -struct warc_s {-	/* content length ahead */-	size_t cntlen;-	/* and how much we've processed so far */-	size_t cntoff;-	/* and how much we need to consume between calls */-	size_t unconsumed;+struct warc {+	/* Content length of the current record */+	int64_t cntlen;+	/* Bytes processed from the current record */+	int64_t cntoff;+	/* Bytes to consume before the next read */+	int64_t unconsumed; -	/* string pool */+	/* String pool */ 	warc_strbuf_t pool;-	/* previous version */+	/* Previous version */ 	unsigned int pver;-	/* stringified format name */+	/* Stringified format name */ 	struct archive_string sver; }; -static int _warc_bid(struct archive_read *a, int);-static int _warc_cleanup(struct archive_read *a);-static int _warc_read(struct archive_read*, const void**, size_t*, int64_t*);-static int _warc_skip(struct archive_read *a);-static int _warc_rdhdr(struct archive_read *a, struct archive_entry *e);+static int	archive_read_format_warc_bid(struct archive_read *, int);+static int	archive_read_format_warc_cleanup(struct archive_read *);+static int	archive_read_format_warc_read_data(struct archive_read *,+		    const void **, size_t *, int64_t *);+static int	archive_read_format_warc_skip(struct archive_read *);+static int	archive_read_format_warc_read_header(struct archive_read *,+		    struct archive_entry *); -/* private routines */-static unsigned int _warc_rdver(const char *buf, size_t bsz);-static unsigned int _warc_rdtyp(const char *buf, size_t bsz);-static warc_string_t _warc_rduri(const char *buf, size_t bsz);-static ssize_t _warc_rdlen(const char *buf, size_t bsz);-static time_t _warc_rdrtm(const char *buf, size_t bsz);-static time_t _warc_rdmtm(const char *buf, size_t bsz);-static const char *_warc_find_eoh(const char *buf, size_t bsz);-static const char *_warc_find_eol(const char *buf, size_t bsz);+/* Private routines */+static unsigned int	warc_read_version(const char *, size_t);+static unsigned int	warc_read_type(const char *, size_t);+static warc_string_t	warc_read_uri(const char *, size_t);+static int64_t		warc_read_length(const char *, size_t);+static time_t		warc_read_date(const char *, size_t);+static time_t		warc_read_last_modified(const char *, size_t);+static const char	*warc_find_eoh(const char *, size_t);+static const char	*warc_find_eol(const char *, size_t);  int archive_read_support_format_warc(struct archive *_a) { 	struct archive_read *a = (struct archive_read *)_a;-	struct warc_s *w;+	struct warc *warc; 	int r;  	archive_check_magic(_a, ARCHIVE_READ_MAGIC, 	    ARCHIVE_STATE_NEW, "archive_read_support_format_warc"); -	if ((w = calloc(1, sizeof(*w))) == NULL) {+	if ((warc = calloc(1, sizeof(*warc))) == NULL) { 		archive_set_error(&a->archive, ENOMEM, 		    "Can't allocate warc data"); 		return (ARCHIVE_FATAL); 	} -	r = __archive_read_register_format(-		a, w, "warc",-		_warc_bid, NULL, _warc_rdhdr, _warc_read,-		_warc_skip, NULL, _warc_cleanup, NULL, NULL);+	r = __archive_read_register_format(a,+	    warc,+	    "warc",+	    archive_read_format_warc_bid,+	    NULL,+	    archive_read_format_warc_read_header,+	    archive_read_format_warc_read_data,+	    archive_read_format_warc_skip,+	    NULL,+	    archive_read_format_warc_cleanup,+	    NULL,+	    NULL);  	if (r != ARCHIVE_OK) {-		free(w);+		free(warc); 		return (r); 	} 	return (ARCHIVE_OK); }  static int-_warc_cleanup(struct archive_read *a)+archive_read_format_warc_cleanup(struct archive_read *a) {-	struct warc_s *w = a->format->data;+	struct warc *warc = a->format->data; -	if (w->pool.len > 0U) {-		free(w->pool.str);+	if (warc->pool.len > 0U) {+		free(warc->pool.str); 	}-	archive_string_free(&w->sver);-	free(w);+	archive_string_free(&warc->sver);+	free(warc); 	a->format->data = NULL; 	return (ARCHIVE_OK); }  static int-_warc_bid(struct archive_read *a, int best_bid)+archive_read_format_warc_bid(struct archive_read *a, int best_bid) { 	const char *hdr; 	ssize_t nrd;@@ -186,55 +198,52 @@  	(void)best_bid; /* UNUSED */ -	/* check first line of file, it should be a record already */-	if ((hdr = __archive_read_ahead(a, 12U, &nrd)) == NULL) {-		/* no idea what to do */-		return -1;-	} else if (nrd < 12) {-		/* nah, not for us, our magic cookie is at least 12 bytes */+	/* Check the first line, which should already be a record header. */+	if ((hdr = __archive_read_ahead(a, 12, &nrd)) == NULL) {+		/* Not enough data to identify this format. */ 		return -1; 	} -	/* otherwise snarf the record's version number */-	ver = _warc_rdver(hdr, nrd);+	/* Parse the record version number. */+	ver = warc_read_version(hdr, nrd); 	if (ver < 1200U || ver > 10000U) {-		/* we only support WARC 0.12 to 1.0 */+		/* Only WARC 0.12 through WARC 1.0 are supported. */ 		return -1; 	} -	/* otherwise be confident */+	/* WARC magic and version checks passed. */ 	return (64); }  static int-_warc_rdhdr(struct archive_read *a, struct archive_entry *entry)+archive_read_format_warc_read_header(struct archive_read *a,+    struct archive_entry *entry) { #define HDR_PROBE_LEN		(12U)-	struct warc_s *w = a->format->data;+	struct warc *warc = a->format->data; 	unsigned int ver; 	const char *buf; 	ssize_t nrd; 	const char *eoh; 	char *tmp;-	/* for the file name, saves some strndup()'ing */+	/* Reuse the header buffer while parsing the file name. */ 	warc_string_t fnam;-	/* warc record type, not that we really use it a lot */+	/* WARC record type */ 	warc_type_t ftyp;-	/* content-length+error monad */-	ssize_t cntlen;-	/* record time is the WARC-Date time we reinterpret it as ctime */+	/* Content length, or a negative error indicator */+	int64_t cntlen;+	/* WARC-Date is exposed as the entry ctime. */ 	time_t rtime;-	/* mtime is the Last-Modified time which will be the entry's mtime */+	/* A Last-Modified record header is exposed as the entry mtime. */ 	time_t mtime;  start_over:-	/* just use read_ahead() they keep track of unconsumed-	 * bits and bobs for us; no need to put an extra shift in-	 * and reproduce that functionality here */+	/* Use read_ahead(); it already tracks unconsumed bytes, so this+	 * reader does not need a separate shift buffer. */ 	buf = __archive_read_ahead(a, HDR_PROBE_LEN, &nrd);  	if (nrd < 0) {-		/* no good */+		/* I/O or stream error. */ 		archive_set_error( 			&a->archive, ARCHIVE_ERRNO_MISC, 			"Bad record header");@@ -244,19 +253,17 @@ 		 * must be EOF therefore */ 		return (ARCHIVE_EOF); 	}- 	/* looks good so far, try and find the end of the header now */-	eoh = _warc_find_eoh(buf, nrd);+	/* Locate the end of the record header. */+	eoh = warc_find_eoh(buf, nrd); 	if (eoh == NULL) {-		/* still no good, the header end might be beyond the-		 * probe we've requested, but then again who'd cram-		 * so much stuff into the header *and* be 28500-compliant */+		/* The header terminator was not found in the probed data. */ 		archive_set_error( 			&a->archive, ARCHIVE_ERRNO_MISC, 			"Bad record header"); 		return (ARCHIVE_FATAL); 	}-	ver = _warc_rdver(buf, eoh - buf);-	/* we currently support WARC 0.12 to 1.0 */+	ver = warc_read_version(buf, eoh - buf);+	/* Only WARC 0.12 through WARC 1.0 are supported. */ 	if (ver == 0U) { 		archive_set_error( 			&a->archive, ARCHIVE_ERRNO_MISC,@@ -269,78 +276,73 @@ 			ver / 10000, (ver % 10000) / 100); 		return (ARCHIVE_FATAL); 	}-	cntlen = _warc_rdlen(buf, eoh - buf);+	cntlen = warc_read_length(buf, eoh - buf); 	if (cntlen < 0) {-		/* nightmare!  the specs say content-length is mandatory-		 * so I don't feel overly bad stopping the reader here */+		/* This reader requires Content-Length before processing a record. */ 		archive_set_error( 			&a->archive, EINVAL, 			"Bad content length"); 		return (ARCHIVE_FATAL); 	}-	rtime = _warc_rdrtm(buf, eoh - buf);+	rtime = warc_read_date(buf, eoh - buf); 	if (rtime == (time_t)-1) {-		/* record time is mandatory as per WARC/1.0,-		 * so just barf here, fast and loud */+		/* This reader requires WARC-Date before processing a record. */ 		archive_set_error( 			&a->archive, EINVAL, 			"Bad record time"); 		return (ARCHIVE_FATAL); 	} -	/* let the world know we're a WARC archive */+	/* Report this archive as WARC. */ 	a->archive.archive_format = ARCHIVE_FORMAT_WARC;-	if (ver != w->pver) {-		/* stringify this entry's version */-		archive_string_sprintf(&w->sver,+	if (ver != warc->pver) {+		/* Format this entry's WARC version. */+		archive_string_sprintf(&warc->sver, 			"WARC/%u.%u", ver / 10000, (ver % 10000) / 100);-		/* remember the version */-		w->pver = ver;+		/* Remember the version for later entries. */+		warc->pver = ver; 	}-	/* start off with the type */-	ftyp = _warc_rdtyp(buf, eoh - buf);-	/* and let future calls know about the content */-	w->cntlen = cntlen;-	w->cntoff = 0U;-	mtime = 0;/* Avoid compiling error on some platform. */+	/* Parse the record type. */+	ftyp = warc_read_type(buf, eoh - buf);+	/* Save content state for subsequent read calls. */+	warc->cntlen = cntlen;+	warc->cntoff = 0;+	mtime = 0;/* Avoid compiler warnings on some platforms. */  	switch (ftyp) { 	case WT_RSRC: 	case WT_RSP:-		/* only try and read the filename in the cases that are-		 * guaranteed to have one */-		fnam = _warc_rduri(buf, eoh - buf);-		/* check the last character in the URI to avoid creating-		 * directory endpoints as files, see Todo above */+		/* Read the filename only for record types that are expected to+		 * have a target URI. */+		fnam = warc_read_uri(buf, eoh - buf);+		/* Avoid creating directory endpoints as files. */ 		if (fnam.len == 0 || fnam.str[fnam.len - 1] == '/') {-			/* break here for now */+			/* Skip this record. */ 			fnam.len = 0U; 			fnam.str = NULL; 			break; 		}-		/* bang to our string pool, so we save a-		 * malloc()+free() roundtrip */-		if (fnam.len + 1U > w->pool.len) {-			w->pool.len = ((fnam.len + 64U) / 64U) * 64U;-			tmp = realloc(w->pool.str, w->pool.len);+		/* Copy the name into the reusable string pool to avoid a malloc/free+		 * roundtrip for each entry. */+		if (fnam.len + 1U > warc->pool.len) {+			warc->pool.len = ((fnam.len + 64U) / 64U) * 64U;+			tmp = realloc(warc->pool.str, warc->pool.len); 			if (tmp == NULL) { 				archive_set_error( 					&a->archive, ENOMEM, 					"Out of memory"); 				return (ARCHIVE_FATAL); 			}-			w->pool.str = tmp;+			warc->pool.str = tmp; 		}-		memcpy(w->pool.str, fnam.str, fnam.len);-		w->pool.str[fnam.len] = '\0';-		/* let no one else know about the pool, it's a secret, shhh */-		fnam.str = w->pool.str;+		memcpy(warc->pool.str, fnam.str, fnam.len);+		warc->pool.str[fnam.len] = '\0';+		/* Hide the pool implementation behind the parsed string. */+		fnam.str = warc->pool.str; -		/* snarf mtime or deduce from rtime-		 * this is a custom header added by our writer, it's quite-		 * hard to believe anyone else would go through with it-		 * (apart from being part of some http responses of course) */-		if ((mtime = _warc_rdmtm(buf, eoh - buf)) == (time_t)-1) {+		/* Use a Last-Modified record header when present; otherwise fall back+		 * to WARC-Date. */+		if ((mtime = warc_read_last_modified(buf, eoh - buf)) == (time_t)-1) { 			mtime = rtime; 		} 		break;@@ -358,19 +360,19 @@ 		break; 	} -	/* now eat some of those delicious buffer bits */+	/* Consume the record header. */ 	__archive_read_consume(a, eoh - buf);  	switch (ftyp) { 	case WT_RSRC: 	case WT_RSP: 		if (fnam.len > 0U) {-			/* populate entry object */+			/* Populate the entry object. */ 			archive_entry_set_filetype(entry, AE_IFREG); 			archive_entry_copy_pathname(entry, fnam.str); 			archive_entry_set_size(entry, cntlen); 			archive_entry_set_perm(entry, 0644);-			/* rtime is the new ctime, mtime stays mtime */+			/* WARC-Date becomes ctime; mtime comes from Last-Modified or WARC-Date. */ 			archive_entry_set_ctime(entry, rtime, 0L); 			archive_entry_set_mtime(entry, mtime, 0L); 			break;@@ -385,8 +387,8 @@ 	case WT_CONT: 	case LAST_WT: 	default:-		/* consume the content and start over */-		if (_warc_skip(a) < 0)+		/* Skip this record body and look for the next one. */+		if (archive_read_format_warc_skip(a) < 0) 			return (ARCHIVE_FATAL); 		goto start_over; 	}@@ -394,62 +396,69 @@ }  static int-_warc_read(struct archive_read *a, const void **buf, size_t *bsz, int64_t *off)+archive_read_format_warc_read_data(struct archive_read *a, const void **buf,+    size_t *bsz, int64_t *off) {-	struct warc_s *w = a->format->data;+	struct warc *warc = a->format->data; 	const char *rab; 	ssize_t nrd; -	if (w->cntoff >= w->cntlen) {-	eof:-		/* it's our lucky day, no work, we can leave early */+	if (warc->unconsumed) {+		__archive_read_consume(a, warc->unconsumed);+		warc->unconsumed = 0;+	}++	if (warc->cntoff >= warc->cntlen) {+		/* No data is available to return for this entry. */ 		*buf = NULL; 		*bsz = 0U;-		*off = w->cntoff;-		w->unconsumed = 0U;+		*off = warc->cntoff; 		return (ARCHIVE_EOF); 	} -	if (w->unconsumed) {-		__archive_read_consume(a, w->unconsumed);-		w->unconsumed = 0U;-	}- 	rab = __archive_read_ahead(a, 1U, &nrd); 	if (nrd < 0) { 		*bsz = 0U;-		/* big catastrophe */+		/* Propagate the read error. */ 		return (int)nrd; 	} else if (nrd == 0) {-		goto eof;-	} else if ((size_t)nrd > w->cntlen - w->cntoff) {-		/* clamp to content-length */-		nrd = w->cntlen - w->cntoff;+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,+		    "Truncated WARC file data");+		return (ARCHIVE_FATAL);+	} else if ((int64_t)nrd > warc->cntlen - warc->cntoff) {+		/* Clamp reads to Content-Length. */+		nrd = warc->cntlen - warc->cntoff; 	}-	*off = w->cntoff;+	*off = warc->cntoff; 	*bsz = nrd; 	*buf = rab; -	w->cntoff += nrd;-	w->unconsumed = (size_t)nrd;+	warc->cntoff += nrd;+	warc->unconsumed = nrd; 	return (ARCHIVE_OK); }  static int-_warc_skip(struct archive_read *a)+archive_read_format_warc_skip(struct archive_read *a) {-	struct warc_s *w = a->format->data;+	struct warc *warc = a->format->data; -	if (__archive_read_consume(a, w->cntlen) < 0 ||+	if (warc->cntoff > warc->cntlen)+		return (ARCHIVE_FATAL);+	if (warc->unconsumed) {+		__archive_read_consume(a, warc->unconsumed);+		warc->unconsumed = 0;+	}+	if (__archive_read_consume(a, warc->cntlen - warc->cntoff) < 0 || 	    __archive_read_consume(a, 4U/*\r\n\r\n separator*/) < 0) 		return (ARCHIVE_FATAL);-	w->cntlen = 0U;-	w->cntoff = 0U;+	warc->cntlen = 0;+	warc->cntoff = 0; 	return (ARCHIVE_OK); }  -/* private routines */+/* Private routines */ static void* deconst(const void *c) {@@ -469,44 +478,41 @@ 	unsigned int nsum; 	unsigned int eqp; -	/* trivial checks first-         * a 0-sized needle is defined to be found anywhere in haystack-         * then run strchr() to find a candidate in HAYSTACK (i.e. a portion-         * that happens to begin with *NEEDLE) */+	/* Handle trivial cases first.  A zero-sized needle is defined to be+	 * found anywhere in the haystack; otherwise find the first candidate+	 * that begins with *NEEDLE. */ 	if (needlesize == 0UL) { 		return deconst(hay); 	} else if ((hay = memchr(hay, *needle, haysize)) == NULL) {-		/* trivial */+		/* No candidate match remains. */ 		return NULL; 	} -	/* First characters of haystack and needle are the same now. Both are-	 * guaranteed to be at least one character long.  Now computes the sum-	 * of characters values of needle together with the sum of the first-	 * needle_len characters of haystack. */+	/* The first characters of haystack and needle already match, and both+	 * strings are at least one character long.  Compute the rolling XOR+	 * values for the needle and the first NEEDLESIZE characters of haystack. */ 	for (hp = hay + 1U, np = needle + 1U, hsum = *hay, nsum = *hay, eqp = 1U; 	     hp < eoh && np < eon; 	     hsum ^= *hp, nsum ^= *np, eqp &= *hp == *np, hp++, np++);  	/* HP now references the (NEEDLESIZE + 1)-th character. */ 	if (np < eon) {-		/* haystack is smaller than needle, :O */+		/* The haystack is smaller than the needle. */ 		return NULL; 	} else if (eqp) {-		/* found a match */+		/* Found a match. */ 		return deconst(hay); 	} -	/* now loop through the rest of haystack,-	 * updating the sum iteratively */+	/* Loop through the rest of the haystack and update the rolling XOR+	 * iteratively. */ 	for (cand = hay; hp < eoh; hp++) { 		hsum ^= *cand++; 		hsum ^= *hp; -		/* Since the sum of the characters is already known to be-		 * equal at that point, it is enough to check just NEEDLESIZE - 1-		 * characters for equality,-		 * also CAND is by design < HP, so no need for range checks */+		/* When the rolling XOR values match, it is enough to check+		 * NEEDLESIZE - 1 characters for equality.  CAND is always before+		 * HP by design, so no range check is needed. */ 		if (hsum == nsum && memcmp(cand, needle, needlesize - 1U) == 0) { 			return deconst(cand); 		}@@ -519,7 +525,7 @@ { 	int res = 0; 	const char *sp;-	/* we keep track of the number of digits via rulim */+	/* Track the number of digits with rulim. */ 	int rulim;  	for (sp = str, rulim = ulim > 10 ? ulim : 10;@@ -546,11 +552,11 @@         /* Use platform timegm() if available. */         return (timegm(t)); #else-        /* Else use direct calculation using POSIX assumptions. */-        /* First, fix up tm_yday based on the year/month/day. */+        /* Otherwise, calculate directly using POSIX assumptions. */+        /* First, fix up tm_yday based on the year, month, and day. */         if (mktime(t) == (time_t)-1)                 return ((time_t)-1);-        /* Then we can compute timegm() from first principles. */+        /* Then compute timegm() from first principles. */         return (t->tm_sec             + t->tm_min * 60             + t->tm_hour * 3600@@ -565,48 +571,48 @@ static time_t xstrpisotime(const char *s, char **endptr) {-/** like strptime() but strictly for ISO 8601 Zulu strings */+/* Like strptime(), but only for ISO 8601 Zulu strings. */ 	struct tm tm; 	time_t res = (time_t)-1; -	/* make sure tm is clean */+	/* Clear the tm structure. */ 	memset(&tm, 0, sizeof(tm)); -	/* as a courtesy to our callers, and since this is a non-standard-	 * routine, we skip leading whitespace */+	/* This is a non-standard routine, so skip leading whitespace for+	 * caller convenience. */ 	while (*s == ' ' || *s == '\t') 		++s; -	/* read year */+	/* Read the year. */ 	if ((tm.tm_year = strtoi_lim(s, &s, 1583, 4095)) < 0 || *s++ != '-') { 		goto out; 	}-	/* read month */+	/* Read the month. */ 	if ((tm.tm_mon = strtoi_lim(s, &s, 1, 12)) < 0 || *s++ != '-') { 		goto out; 	}-	/* read day-of-month */+	/* Read the day of the month. */ 	if ((tm.tm_mday = strtoi_lim(s, &s, 1, 31)) < 0 || *s++ != 'T') { 		goto out; 	}-	/* read hour */+	/* Read the hour. */ 	if ((tm.tm_hour = strtoi_lim(s, &s, 0, 23)) < 0 || *s++ != ':') { 		goto out; 	}-	/* read minute */+	/* Read the minute. */ 	if ((tm.tm_min = strtoi_lim(s, &s, 0, 59)) < 0 || *s++ != ':') { 		goto out; 	}-	/* read second */+	/* Read the second. */ 	if ((tm.tm_sec = strtoi_lim(s, &s, 0, 60)) < 0 || *s++ != 'Z') { 		goto out; 	} -	/* massage TM to fulfill some of POSIX' constraints */+	/* Adjust tm fields to satisfy POSIX constraints. */ 	tm.tm_year -= 1900; 	tm.tm_mon--; -	/* now convert our custom tm struct to a unix stamp using UTC */+	/* Convert the tm structure to a Unix timestamp in UTC. */ 	res = time_from_tm(&tm);  out:@@ -616,8 +622,14 @@ 	return res; } +static int+warc_isdigit(const char c)+{+	return c >= '0' && c <= '9';+}+ static unsigned int-_warc_rdver(const char *buf, size_t bsz)+warc_read_version(const char *buf, size_t bsz) { 	static const char magic[] = "WARC/"; 	const char *c;@@ -625,35 +637,34 @@ 	unsigned int end = 0U;  	if (bsz < 12 || memcmp(buf, magic, sizeof(magic) - 1U) != 0) {-		/* buffer too small or invalid magic */+		/* Buffer too small or invalid magic. */ 		return ver; 	}-	/* looks good so far, read the version number for a laugh */+	/* Parse the version number. */ 	buf += sizeof(magic) - 1U; -	if (isdigit((unsigned char)buf[0U]) && (buf[1U] == '.') &&-	    isdigit((unsigned char)buf[2U])) {-		/* we support a maximum of 2 digits in the minor version */-		if (isdigit((unsigned char)buf[3U]))+	if (warc_isdigit(buf[0]) && buf[1] == '.' && warc_isdigit(buf[2])) {+		/* Support at most two digits in the minor version. */+		if (warc_isdigit(buf[3])) 			end = 1U;-		/* set up major version */+		/* Set up the major version. */ 		ver = (buf[0U] - '0') * 10000U;-		/* set up minor version */+		/* Set up the minor version. */ 		if (end == 1U) { 			ver += (buf[2U] - '0') * 1000U; 			ver += (buf[3U] - '0') * 100U; 		} else 			ver += (buf[2U] - '0') * 100U; 		/*-		 * WARC below version 0.12 has a space-separated header-		 * WARC 0.12 and above terminates the version with a CRLF+		 * WARC versions before 0.12 use a space-separated header.+		 * WARC 0.12 and later terminate the version with CRLF. 		 */ 		c = buf + 3U + end; 		if (ver >= 1200U) { 			if (memcmp(c, "\r\n", 2U) != 0) 				ver = 0U; 		} else {-			/* ver < 1200U */+			/* Version is below WARC 0.12. */ 			if (*c != ' ' && *c != '\t') 				ver = 0U; 		}@@ -662,22 +673,22 @@ }  static unsigned int-_warc_rdtyp(const char *buf, size_t bsz)+warc_read_type(const char *buf, size_t bsz) { 	static const char _key[] = "\r\nWARC-Type:"; 	const char *val, *eol;  	if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {-		/* no bother */+		/* Header field is absent. */ 		return WT_NONE; 	} 	val += sizeof(_key) - 1U;-	if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {-		/* no end of line */+	if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL) {+		/* Header field has no end of line. */ 		return WT_NONE; 	} -	/* overread whitespace */+	/* Skip leading whitespace. */ 	while (val < eol && (*val == ' ' || *val == '\t')) 		++val; @@ -691,55 +702,55 @@ }  static warc_string_t-_warc_rduri(const char *buf, size_t bsz)+warc_read_uri(const char *buf, size_t bsz) { 	static const char _key[] = "\r\nWARC-Target-URI:"; 	const char *val, *uri, *eol, *p; 	warc_string_t res = {0U, NULL};  	if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {-		/* no bother */+		/* Header field is absent. */ 		return res; 	}-	/* overread whitespace */+	/* Skip leading whitespace. */ 	val += sizeof(_key) - 1U;-	if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {-		/* no end of line */+	if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL) {+		/* Header field has no end of line. */ 		return res; 	}  	while (val < eol && (*val == ' ' || *val == '\t')) 		++val; -	/* overread URL designators */+	/* Locate the :// separator. */ 	if ((uri = xmemmem(val, eol - val, "://", 3U)) == NULL) {-		/* not touching that! */+		/* Ignore values without a :// separator. */ 		return res; 	} -	/* spaces inside uri are not allowed, CRLF should follow */+	/* Spaces inside a URI are not allowed; CRLF should follow. */ 	for (p = val; p < eol; p++) { 		if (isspace((unsigned char)*p)) 			return res; 	} -	/* there must be at least space for ftp */+	/* Require enough room for the shortest supported scheme. */ 	if (uri < (val + 3U)) 		return res; -	/* move uri to point to after :// */+	/* Move uri past the :// separator. */ 	uri += 3U; -	/* now then, inspect the URI */+	/* Inspect the scheme prefix. */ 	if (memcmp(val, "file", 4U) == 0) {-		/* perfect, nothing left to do here */+		/* Keep file:// paths as-is. */  	} else if (memcmp(val, "http", 4U) == 0 || 		   memcmp(val, "ftp", 3U) == 0) {-		/* overread domain, and the first / */+		/* Skip the domain and the first slash. */ 		while (uri < eol && *uri++ != '/'); 	} else {-		/* not sure what to do? best to bugger off */+		/* Unsupported URI scheme. */ 		return res; 	} 	res.str = uri;@@ -747,42 +758,49 @@ 	return res; } -static ssize_t-_warc_rdlen(const char *buf, size_t bsz)+static int64_t+warc_read_length(const char *buf, size_t bsz) { 	static const char _key[] = "\r\nContent-Length:";-	const char *val, *eol;-	char *on = NULL;-	long int len;+	const char *val, *eol, *p;+	int64_t len;  	if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {-		/* no bother */+		/* Header field is absent. */ 		return -1; 	} 	val += sizeof(_key) - 1U;-	if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {-		/* no end of line */++	if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL) {+		/* Malformed field with no end of line. */ 		return -1; 	} -	/* skip leading whitespace */+	/* Skip leading whitespace. */ 	while (val < eol && (*val == ' ' || *val == '\t')) 		val++;-	/* there must be at least one digit */-	if (!isdigit((unsigned char)*val))-		return -1;-	errno = 0;-	len = strtol(val, &on, 10);-	if (errno != 0 || on != eol) {-		/* line must end here */++	/* Require at least one digit. */+	if (val >= eol || *val < '0' || *val > '9') 		return -1;++	len = 0;+	for (p = val; p < eol; p++) {+		int64_t digit;++		if (*p < '0' || *p > '9')+			return -1;+		digit = *p - '0';+		if (archive_ckd_mul_i64(&len, len, 10) ||+		    archive_ckd_add_i64(&len, len, digit))+			return -1; 	} -	return (size_t)len;+	return len; }  static time_t-_warc_rdrtm(const char *buf, size_t bsz)+warc_read_date(const char *buf, size_t bsz) { 	static const char _key[] = "\r\nWARC-Date:"; 	const char *val, *eol;@@ -790,26 +808,26 @@ 	time_t res;  	if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {-		/* no bother */+		/* Header field is absent. */ 		return (time_t)-1; 	} 	val += sizeof(_key) - 1U;-	if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL ) {-		/* no end of line */+	if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL ) {+		/* Header field has no end of line. */ 		return -1; 	} -	/* xstrpisotime() kindly overreads whitespace for us, so use that */+	/* xstrpisotime() skips leading whitespace. */ 	res = xstrpisotime(val, &on); 	if (on != eol) {-		/* line must end here */+		/* The field must end here. */ 		return -1; 	} 	return res; }  static time_t-_warc_rdmtm(const char *buf, size_t bsz)+warc_read_last_modified(const char *buf, size_t bsz) { 	static const char _key[] = "\r\nLast-Modified:"; 	const char *val, *eol;@@ -817,26 +835,26 @@ 	time_t res;  	if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {-		/* no bother */+		/* Header field is absent. */ 		return (time_t)-1; 	} 	val += sizeof(_key) - 1U;-	if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL ) {-		/* no end of line */+	if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL ) {+		/* Header field has no end of line. */ 		return -1; 	} -	/* xstrpisotime() kindly overreads whitespace for us, so use that */+	/* xstrpisotime() skips leading whitespace. */ 	res = xstrpisotime(val, &on); 	if (on != eol) {-		/* line must end here */+		/* The field must end here. */ 		return -1; 	} 	return res; } -static const char*-_warc_find_eoh(const char *buf, size_t bsz)+static const char *+warc_find_eoh(const char *buf, size_t bsz) { 	static const char _marker[] = "\r\n\r\n"; 	const char *hit = xmemmem(buf, bsz, _marker, sizeof(_marker) - 1U);@@ -847,12 +865,11 @@ 	return hit; } -static const char*-_warc_find_eol(const char *buf, size_t bsz)+static const char *+warc_find_eol(const char *buf, size_t bsz) { 	static const char _marker[] = "\r\n"; 	const char *hit = xmemmem(buf, bsz, _marker, sizeof(_marker) - 1U);  	return hit; }-/* archive_read_support_format_warc.c ends here */
c/archive_read_support_format_xar.c view
@@ -108,10 +108,14 @@ #define CKSUM_NONE	0 #define CKSUM_SHA1	1 #define CKSUM_MD5	2+#define CKSUM_SHA256	3+#define CKSUM_SHA512	4  #define MD5_SIZE	16 #define SHA1_SIZE	20-#define MAX_SUM_SIZE	20+#define SHA256_SIZE	32+#define SHA512_SIZE	64+#define MAX_SUM_SIZE	64  enum enctype { 	NONE,@@ -135,6 +139,12 @@ #ifdef ARCHIVE_HAS_SHA1 	archive_sha1_ctx	 sha1ctx; #endif+#ifdef ARCHIVE_HAS_SHA256+	archive_sha256_ctx	 sha256ctx;+#endif+#ifdef ARCHIVE_HAS_SHA512+	archive_sha512_ctx	 sha512ctx;+#endif };  struct xattr {@@ -214,8 +224,8 @@  struct heap_queue { 	struct xar_file		**files;-	int			 allocated;-	int			 used;+	size_t			 allocated;+	size_t			 used; };  enum xmlstatus {@@ -396,7 +406,7 @@ static struct xar_file *heap_get_entry(struct heap_queue *); static int	add_link(struct archive_read *,     struct xar *, struct xar_file *);-static void	checksum_init(struct archive_read *, int, int);+static int	checksum_init(struct archive_read *, int, int); static void	checksum_update(struct archive_read *, const void *, 		    size_t, const void *, size_t); static int	checksum_final(struct archive_read *, const void *,@@ -524,6 +534,8 @@ 	case CKSUM_NONE: 	case CKSUM_SHA1: 	case CKSUM_MD5:+	case CKSUM_SHA256:+	case CKSUM_SHA512: 		bid += 32; 		break; 	default:@@ -536,7 +548,7 @@ static int read_toc(struct archive_read *a) {-	struct xar *xar;+	struct xar *xar = a->format->data; 	struct xar_file *file; 	const unsigned char *b; 	uint64_t toc_compressed_size;@@ -545,8 +557,6 @@ 	ssize_t bytes; 	int r; -	xar = (struct xar *)(a->format->data);- 	/* 	 * Read xar header. 	 */@@ -674,12 +684,11 @@ static int xar_read_header(struct archive_read *a, struct archive_entry *entry) {-	struct xar *xar;+	struct xar *xar = a->format->data; 	struct xar_file *file; 	struct xattr *xattr; 	int r; -	xar = (struct xar *)(a->format->data); 	r = ARCHIVE_OK;  	if (xar->offset == 0) {@@ -729,6 +738,7 @@ 		if (errno == ENOMEM) { 			archive_set_error(&a->archive, ENOMEM, 			    "Can't allocate memory for Gname");+			file_free(file); 			return (ARCHIVE_FATAL); 		} 		archive_set_error(&a->archive,@@ -744,6 +754,7 @@ 		if (errno == ENOMEM) { 			archive_set_error(&a->archive, ENOMEM, 			    "Can't allocate memory for Uname");+			file_free(file); 			return (ARCHIVE_FATAL); 		} 		archive_set_error(&a->archive,@@ -758,6 +769,7 @@ 		if (errno == ENOMEM) { 			archive_set_error(&a->archive, ENOMEM, 			    "Can't allocate memory for Pathname");+			file_free(file); 			return (ARCHIVE_FATAL); 		} 		archive_set_error(&a->archive,@@ -774,6 +786,7 @@ 		if (errno == ENOMEM) { 			archive_set_error(&a->archive, ENOMEM, 			    "Can't allocate memory for Linkname");+			file_free(file); 			return (ARCHIVE_FATAL); 		} 		archive_set_error(&a->archive,@@ -874,12 +887,10 @@ xar_read_data(struct archive_read *a,     const void **buff, size_t *size, int64_t *offset) {-	struct xar *xar;+	struct xar *xar = a->format->data; 	size_t used = 0; 	int r; -	xar = (struct xar *)(a->format->data);- 	if (xar->entry_unconsumed) { 		__archive_read_consume(a, xar->entry_unconsumed); 		xar->entry_unconsumed = 0;@@ -937,10 +948,9 @@ static int xar_read_data_skip(struct archive_read *a) {-	struct xar *xar;+	struct xar *xar = a->format->data; 	int64_t bytes_skipped; -	xar = (struct xar *)(a->format->data); 	if (xar->end_of_file) 		return (ARCHIVE_EOF); 	bytes_skipped = __archive_read_consume(a, xar->entry_remaining +@@ -955,12 +965,11 @@ static int xar_cleanup(struct archive_read *a) {-	struct xar *xar;+	struct xar *xar = a->format->data; 	struct hdlink *hdlink;-	int i;+	size_t i; 	int r; -	xar = (struct xar *)(a->format->data); 	checksum_cleanup(a); 	r = decompression_cleanup(a); 	hdlink = xar->hdlink_list;@@ -990,9 +999,8 @@ static int move_reading_point(struct archive_read *a, uint64_t offset) {-	struct xar *xar;+	struct xar *xar = a->format->data; -	xar = (struct xar *)(a->format->data); 	if (xar->offset - xar->h_base != offset) { 		/* Seek forward to the start of file contents. */ 		int64_t step;@@ -1027,8 +1035,7 @@ 	if ((r = decompression_init(a, encoding)) != ARCHIVE_OK) 		return (r); 	/* Init checksum library. */-	checksum_init(a, a_sum_alg, e_sum_alg);-	return (ARCHIVE_OK);+	return (checksum_init(a, a_sum_alg, e_sum_alg)); }  static int@@ -1077,16 +1084,14 @@ 	uint64_t l;  	l = 0;-	if (char_cnt > 0) {-		int digit;+	while (char_cnt-- > 0) {+		int digit = *p++ - '0'; -		digit = *p - '0';-		while (digit >= 0 && digit < base && char_cnt-- > 0) {-			if (archive_ckd_mul_u64(&l, l, base) ||-			    archive_ckd_add_u64(&l, l, digit))-				return (ARCHIVE_FATAL);-			digit = *++p - '0';-		}+		if (digit < 0 || digit >= base)+			break;+		if (archive_ckd_mul_u64(&l, l, base) ||+		    archive_ckd_add_u64(&l, l, digit))+			return (ARCHIVE_FATAL); 	}  	*val = l;@@ -1166,31 +1171,31 @@ 	p += 4; 	if (*p++ != '-') 		return (t);-	if (atou64(p, 4, 10, &data) != ARCHIVE_OK || data < 1 || data > 12)+	if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data < 1 || data > 12) 		return (t); 	tm.tm_mon = (int)data -1; 	p += 2; 	if (*p++ != '-') 		return (t);-	if (atou64(p, 4, 10, &data) != ARCHIVE_OK || data < 1 || data > 31)+	if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data < 1 || data > 31) 		return (t); 	tm.tm_mday = (int)data; 	p += 2; 	if (*p++ != 'T') 		return (t);-	if (atou64(p, 4, 10, &data) != ARCHIVE_OK || data > 23)+	if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data > 23) 		return (t); 	tm.tm_hour = (int)data; 	p += 2; 	if (*p++ != ':') 		return (t);-	if (atou64(p, 4, 10, &data) != ARCHIVE_OK || data > 59)+	if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data > 59) 		return (t); 	tm.tm_min = (int)data; 	p += 2; 	if (*p++ != ':') 		return (t);-	if (atou64(p, 4, 10, &data) != ARCHIVE_OK || data > 60)+	if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data > 60) 		return (t); 	tm.tm_sec = (int)data; #if 0@@ -1209,19 +1214,17 @@     struct heap_queue *heap, struct xar_file *file) { 	uint64_t file_id, parent_id;-	int hole, parent;+	size_t hole, parent;  	/* Expand our pending files list as necessary. */ 	if (heap->used >= heap->allocated) { 		struct xar_file **new_pending_files;-		int new_size;+		size_t new_size;  		if (heap->allocated < 1024) 			new_size = 1024;-		else-			new_size = heap->allocated * 2;-		/* Overflow might keep us from growing the list. */-		if (new_size <= heap->allocated) {+		else if (archive_ckd_mul_size(&new_size, heap->allocated, 2)) {+			/* Overflow keeps us from growing the list. */ 			archive_set_error(&a->archive, 			    ENOMEM, "Out of memory"); 			return (ARCHIVE_FATAL);@@ -1249,7 +1252,7 @@ 	 */ 	hole = heap->used++; 	while (hole > 0) {-		parent = (hole - 1)/2;+		parent = (hole - 1) / 2; 		parent_id = heap->files[parent]->id; 		if (file_id >= parent_id) { 			heap->files[hole] = file;@@ -1268,7 +1271,7 @@ heap_get_entry(struct heap_queue *heap) { 	uint64_t a_id, b_id, c_id;-	int a, b, c;+	size_t a, b, c; 	struct xar_file *r, *tmp;  	if (heap->used < 1)@@ -1338,7 +1341,7 @@ 	return (ARCHIVE_OK); } -static void+static int _checksum_init(struct chksumwork *sumwrk, int sum_alg) { 	sumwrk->alg = sum_alg;@@ -1351,7 +1354,20 @@ 	case CKSUM_MD5: 		archive_md5_init(&(sumwrk->md5ctx)); 		break;+#ifdef ARCHIVE_HAS_SHA256+	case CKSUM_SHA256:+		archive_sha256_init(&(sumwrk->sha256ctx));+		break;+#endif+#ifdef ARCHIVE_HAS_SHA512+	case CKSUM_SHA512:+		archive_sha512_init(&(sumwrk->sha512ctx));+		break;+#endif+	default:+		return (ARCHIVE_FATAL); 	}+	return (ARCHIVE_OK); }  static void@@ -1367,6 +1383,16 @@ 	case CKSUM_MD5: 		archive_md5_update(&(sumwrk->md5ctx), buff, size); 		break;+#ifdef ARCHIVE_HAS_SHA256+	case CKSUM_SHA256:+		archive_sha256_update(&(sumwrk->sha256ctx), buff, size);+		break;+#endif+#ifdef ARCHIVE_HAS_SHA512+	case CKSUM_SHA512:+		archive_sha512_update(&(sumwrk->sha512ctx), buff, size);+		break;+#endif 	} } @@ -1391,27 +1417,48 @@ 		    memcmp(val, sum, MD5_SIZE) != 0) 			r = ARCHIVE_FAILED; 		break;+#ifdef ARCHIVE_HAS_SHA256+	case CKSUM_SHA256:+		archive_sha256_final(&(sumwrk->sha256ctx), sum);+		if (len != SHA256_SIZE ||+		    memcmp(val, sum, SHA256_SIZE) != 0)+			r = ARCHIVE_FAILED;+		break;+#endif+#ifdef ARCHIVE_HAS_SHA512+	case CKSUM_SHA512:+		archive_sha512_final(&(sumwrk->sha512ctx), sum);+		if (len != SHA512_SIZE ||+		    memcmp(val, sum, SHA512_SIZE) != 0)+			r = ARCHIVE_FAILED;+		break;+#endif+	default:+		r = ARCHIVE_FAILED; 	} 	return (r); } -static void+static int checksum_init(struct archive_read *a, int a_sum_alg, int e_sum_alg) {-	struct xar *xar;+	struct xar *xar = a->format->data; -	xar = (struct xar *)(a->format->data);-	_checksum_init(&(xar->a_sumwrk), a_sum_alg);-	_checksum_init(&(xar->e_sumwrk), e_sum_alg);+	if (_checksum_init(&(xar->a_sumwrk), a_sum_alg) != ARCHIVE_OK ||+	    _checksum_init(&(xar->e_sumwrk), e_sum_alg) != ARCHIVE_OK) {+		archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,+		    "Unsupported checksum");+		return (ARCHIVE_FATAL);+	}+	return (ARCHIVE_OK); }  static void checksum_update(struct archive_read *a, const void *abuff, size_t asize,     const void *ebuff, size_t esize) {-	struct xar *xar;+	struct xar *xar = a->format->data; -	xar = (struct xar *)(a->format->data); 	_checksum_update(&(xar->a_sumwrk), abuff, asize); 	_checksum_update(&(xar->e_sumwrk), ebuff, esize); }@@ -1420,27 +1467,24 @@ checksum_final(struct archive_read *a, const void *a_sum_val,     size_t a_sum_len, const void *e_sum_val, size_t e_sum_len) {-	struct xar *xar;-	int r;+	struct xar *xar = a->format->data; -	xar = (struct xar *)(a->format->data);-	r = _checksum_final(&(xar->a_sumwrk), a_sum_val, a_sum_len);-	if (r == ARCHIVE_OK)-		r = _checksum_final(&(xar->e_sumwrk), e_sum_val, e_sum_len);-	if (r != ARCHIVE_OK)+	if (_checksum_final(&(xar->a_sumwrk), a_sum_val, a_sum_len) != ARCHIVE_OK ||+	    _checksum_final(&(xar->e_sumwrk), e_sum_val, e_sum_len) != ARCHIVE_OK) { 		archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,-		    "Sumcheck error");-	return (r);+		    "Checksum error");+		return (ARCHIVE_FATAL);+	}+	return (ARCHIVE_OK); }  static int decompression_init(struct archive_read *a, enum enctype encoding) {-	struct xar *xar;+	struct xar *xar = a->format->data; 	const char *detail; 	int r; -	xar = (struct xar *)(a->format->data); 	xar->rd_encoding = encoding; 	switch (encoding) { 	case NONE:@@ -1576,12 +1620,11 @@ decompress(struct archive_read *a, const void **buff, size_t *outbytes,     const void *b, size_t *used) {-	struct xar *xar;+	struct xar *xar = a->format->data; 	void *outbuff; 	size_t avail_in, avail_out; 	int r; -	xar = (struct xar *)(a->format->data); 	avail_in = *used; 	outbuff = (void *)(uintptr_t)*buff; 	if (outbuff == NULL) {@@ -1704,10 +1747,9 @@ static int decompression_cleanup(struct archive_read *a) {-	struct xar *xar;+	struct xar *xar = a->format->data; 	int r; -	xar = (struct xar *)(a->format->data); 	r = ARCHIVE_OK; 	if (xar->stream_valid) { 		if (inflateEnd(&(xar->stream)) != Z_OK) {@@ -1736,9 +1778,7 @@  static void checksum_cleanup(struct archive_read *a) {-	struct xar *xar;--	xar = (struct xar *)(a->format->data);+	struct xar *xar = a->format->data;  	_checksum_final(&(xar->a_sumwrk), NULL, 0); 	_checksum_final(&(xar->e_sumwrk), NULL, 0);@@ -1791,8 +1831,11 @@ 	} 	xar->file = file; 	file->nlink = 1;-	if (heap_add_entry(a, &(xar->file_queue), file) != ARCHIVE_OK)+	if (heap_add_entry(a, &(xar->file_queue), file) != ARCHIVE_OK) {+		xar->file = file->parent;+		file_free(file); 		return (ARCHIVE_FATAL);+	} 	return (ARCHIVE_OK); } @@ -1897,9 +1940,16 @@ 			const char *v = attr->value; 			if ((v[0] == 'S' || v[0] == 's') && 			    (v[1] == 'H' || v[1] == 'h') &&-			    (v[2] == 'A' || v[2] == 'a') &&-			    v[3] == '1' && v[4] == '\0')-				alg = CKSUM_SHA1;+			    (v[2] == 'A' || v[2] == 'a')) {+				if (v[3] == '1' && v[4] == '\0')+					alg = CKSUM_SHA1;+				else if (v[3] == '2' && v[4] == '5' &&+				    v[5] == '6' && v[6] == '\0')+					alg = CKSUM_SHA256;+				else if (v[3] == '5' && v[4] == '1' &&+				    v[5] == '2' && v[6] == '\0')+					alg = CKSUM_SHA512;+			} 			if ((v[0] == 'M' || v[0] == 'm') && 			    (v[1] == 'D' || v[1] == 'd') && 			    v[2] == '5' && v[3] == '\0')@@ -1957,11 +2007,9 @@ static int xml_start(struct archive_read *a, const char *name, struct xmlattr_list *list) {-	struct xar *xar;+	struct xar *xar = a->format->data; 	struct xmlattr *attr; -	xar = (struct xar *)(a->format->data);- #if DEBUG 	fprintf(stderr, "xml_sta:[%s]\n", name); 	for (attr = list->first; attr != NULL; attr = attr->next)@@ -2253,11 +2301,8 @@ static void xml_end(void *userData, const char *name) {-	struct archive_read *a;-	struct xar *xar;--	a = (struct archive_read *)userData;-	xar = (struct xar *)(a->format->data);+	struct archive_read *a = (struct archive_read *)userData;+	struct xar *xar = a->format->data;  #if DEBUG 	fprintf(stderr, "xml_end:[%s]\n", name);@@ -2631,7 +2676,7 @@ 	len = 0; 	out = buff; 	b = (const unsigned char *)s;-	while (l > 0) {+	while (l > 1) { 		int n = 0;  		if (base64[b[0]] < 0 || base64[b[1]] < 0)@@ -2679,14 +2724,11 @@ static int xml_data(void *userData, const char *s, size_t len) {+	struct archive_read *a = (struct archive_read *)userData;+	struct xar *xar = a->format->data; 	uint64_t val;-	struct archive_read *a;-	struct xar *xar; 	int r; -	a = (struct archive_read *)userData;-	xar = (struct xar *)(a->format->data);- #if DEBUG 	{ 		char buff[1024];@@ -3166,16 +3208,13 @@ static int xml2_read_cb(void *context, char *buffer, int len) {-	struct archive_read *a;-	struct xar *xar;+	struct archive_read *a = (struct archive_read *)context;+	struct xar *xar = a->format->data; 	const void *d; 	size_t outbytes; 	size_t used = 0; 	int r; -	a = (struct archive_read *)context;-	xar = (struct xar *)(a->format->data);- 	if (xar->toc_remaining <= 0) 		return (0); 	d = buffer;@@ -3204,10 +3243,9 @@ xml2_error_hdr(void *arg, const char *msg, xmlParserSeverities severity,     xmlTextReaderLocatorPtr locator) {-	struct archive_read *a;+	struct archive_read *a = (struct archive_read *)arg;  	(void)locator; /* UNUSED */-	a = (struct archive_read *)arg; 	switch (severity) { 	case XML_PARSER_SEVERITY_VALIDITY_WARNING: 	case XML_PARSER_SEVERITY_WARNING:@@ -3357,15 +3395,13 @@ static int expat_read_toc(struct archive_read *a) {-	struct xar *xar;+	struct xar *xar = a->format->data; 	XML_Parser parser; 	struct expat_userData ud;  	ud.state = ARCHIVE_OK; 	ud.archive = a; -	xar = (struct xar *)(a->format->data);- 	/* Initialize XML Parser library. */ 	parser = XML_ParserCreate(NULL); 	if (parser == NULL) {@@ -3449,15 +3485,12 @@ asaRead(ISequentialStream *this, void *pv, ULONG cb, ULONG *pcbRead) { 	struct ArchiveStreamAdapter *asa = (struct ArchiveStreamAdapter *)this;-	struct archive_read *a;-	struct xar *xar;+	struct archive_read *a = asa->a;+	struct xar *xar = a->format->data; 	const void *d = pv; 	size_t outbytes = cb; 	size_t used = 0; 	int r;--	a = asa->a;-	xar = (struct xar *)(a->format->data);  	*pcbRead = 0; 
c/archive_read_support_format_zip.c view
@@ -152,8 +152,6 @@ 	struct archive_string	format_name; 	int64_t			central_directory_offset; 	int64_t			central_directory_offset_adjusted;-	size_t			central_directory_entries_total;-	size_t			central_directory_entries_on_this_disk; 	int			has_encrypted_entries;  	/* List of entries (seekable Zip only) */@@ -261,6 +259,15 @@ /* Many systems define min or MIN, but not all. */ #define	zipmin(a,b) ((a) < (b) ? (a) : (b)) +/* True if this entry has declared a specific uncompressed size. */+static int+zip_entry_size_is_set(const struct zip_entry *zip_entry)+{+	return (0 == (zip_entry->zip_flags & ZIP_LENGTH_AT_END)+	    || (zip_entry->uncompressed_size > 0+		&& zip_entry->uncompressed_size != 0xffffffff));+}+ #ifdef HAVE_ZLIB_H static int zip_read_data_deflate(struct archive_read *a, const void **buff,@@ -284,7 +291,7 @@ ppmd_read(void* p) { 	/* Get the handle to current decompression context. */ 	struct archive_read *a = ((IByteIn*)p)->a;-	struct zip *zip = (struct zip*) a->format->data;+	struct zip *zip = a->format->data;  	/* Fetch next byte. */ 	const uint8_t* data = __archive_read_ahead(a, 1, NULL);@@ -430,7 +437,7 @@ zipx_read_header_and_decrypt(struct archive_read *a, const void **buf, size_t in_len,     size_t *out_len, size_t *consumed) {-	struct zip *zip = (struct zip *)(a->format->data);+	struct zip *zip = a->format->data; 	const void *raw; 	ssize_t bytes_avail; 	size_t to_decrypt;@@ -482,6 +489,13 @@ { 	*sp = compressed_buff; +	/* Safety check to prevent potential OOB reads if something went wrong+	 * previously. We should not have a negative bytes_avail count here.+	 * If we do, set them to zero so that reading the ZIP will fail later,+	 * safely as corrupted instead of crashing. */+	if (bytes_avail < 0)+		bytes_avail = 0;+ 	if (zip->tctx_valid || zip->cctx_valid) { 		if (zip->decrypted_bytes_remaining < (size_t)bytes_avail) { 			size_t buff_remaining =@@ -642,8 +656,8 @@ process_extra(struct archive_read *a, struct archive_entry *entry,      const char *p, size_t extra_length, struct zip_entry* zip_entry) {+	struct zip *zip = a->format->data; 	unsigned offset = 0;-	struct zip *zip = (struct zip *)(a->format->data);  	if (extra_length == 0) { 		return ARCHIVE_OK;@@ -742,6 +756,22 @@ 			 * on which file starts, but we don't handle 			 * multi-volume Zip files. */ 			break;+		case 0x000d:+			/* PKWARE Unix Extra Field fixed metadata. */+			if (datasize >= 12) {+				zip_entry->atime = archive_le32dec(p + offset);+				zip_entry->mtime =+				    archive_le32dec(p + offset + 4);+				zip_entry->uid =+				    archive_le16dec(p + offset + 8);+				zip_entry->gid =+				    archive_le16dec(p + offset + 10);+				/*+				 * APPNOTE.TXT also defines additional data after+				 * this fixed metadata, depending on file type.+				 */+			}+			break; #ifdef DEBUG 		case 0x0017: 		{@@ -1430,10 +1460,7 @@ 			    "Read error skipping symlink target name"); 			return ARCHIVE_FATAL; 		}-	} else if (0 == (zip_entry->zip_flags & ZIP_LENGTH_AT_END)-	   || (zip_entry->uncompressed_size > 0-	       && zip_entry->uncompressed_size != 0xffffffff)) {-		/* Set the size only if it's meaningful. */+	} else if (zip_entry_size_is_set(zip_entry)) { 		archive_entry_set_size(entry, zip_entry->uncompressed_size); 	} 	zip->entry_bytes_remaining = zip_entry->compressed_size;@@ -1456,7 +1483,7 @@ static int check_authentication_code(struct archive_read *a, const void *_p) {-	struct zip *zip = (struct zip *)(a->format->data);+	struct zip *zip = a->format->data;  	/* Check authentication code. */ 	if (zip->hctx_valid) {@@ -1683,6 +1710,26 @@ 		return; 	} +	/* None of the exact patterns matched. If entry size was unknown+	 * (ZIP_LENGTH_AT_END flag), before treating this as+	 * corruption, check whether the next ZIP record follows the data+	 * immediately: a length-at-end entry whose compression format has+	 * its own end-of-stream marker (e.g. PPMd) may be written with no+	 * data descriptor at all.  In that case the byte counts we measured+	 * during decompression are authoritative, so trust them and leave+	 * the stream untouched. */+	if (zip->entry->zip_flags & ZIP_LENGTH_AT_END)+	{+		const uint32_t sig = archive_le32dec(p);+		if (sig == 0x04034b50U     /* Local file header */+		    || sig == 0x02014b50U  /* Central directory record */+		    || sig == 0x06054b50U) /* End of central directory */ {+			zip->entry->compressed_size = compressed_actual;+			zip->entry->uncompressed_size = uncompressed_actual;+			return;+		}+	}+ 	/* If none of the above patterns gives us a full exact match, 	 * then there's something definitely amiss.  The fallback code 	 * below will parse out some plausible values for error@@ -1760,7 +1807,7 @@ zip_read_data_none(struct archive_read *a, const void **_buff,     size_t *size, int64_t *offset) {-	struct zip *zip;+	struct zip *zip = a->format->data; 	const char *buff; 	ssize_t bytes_avail; 	ssize_t trailing_extra;@@ -1768,7 +1815,6 @@  	(void)offset; /* UNUSED */ -	zip = (struct zip *)(a->format->data); 	trailing_extra = zip->hctx_valid ? AUTH_CODE_SIZE : 0;  	if (zip->entry->zip_flags & ZIP_LENGTH_AT_END) {@@ -1986,7 +2032,13 @@ 	 */  	/* Read magic1,magic2,lzma_params from the ZIPX stream. */-	if(zip->entry_bytes_remaining < 9) {+	/* When the compressed size is unknown (e.g. ZIP_LENGTH_AT_END read+	 * from a non-seekable source), entry_bytes_remaining is 0 or negative+	 * here.  We can still attempt to read the 9-byte header; if the data+	 * is truly truncated, the __archive_read_ahead calls below will catch+	 * it. */+	if(zip->entry_bytes_remaining > 0+		&& zip->entry_bytes_remaining < 9) { 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 		    "Truncated lzma data"); 		return (ARCHIVE_FATAL);@@ -2060,8 +2112,10 @@  	/* We've already consumed some bytes, so take this into account. */ 	__archive_read_consume(a, 9);-	zip->entry_bytes_remaining -= 9; 	zip->entry_compressed_bytes_read += 9;+	if (zip->entry_bytes_remaining > 0) {+		zip->entry_bytes_remaining -= 9;+	}  	zip->decompress_init = 1; 	return (ARCHIVE_OK);@@ -2071,12 +2125,12 @@ zip_read_data_zipx_xz(struct archive_read *a, const void **buff, 	size_t *size, int64_t *offset) {-	struct zip* zip = (struct zip *)(a->format->data);+	struct zip *zip = a->format->data; 	int ret; 	lzma_ret lz_ret; 	const void* compressed_buf; 	const void* sp;-	ssize_t bytes_avail, in_bytes, to_consume = 0;+	ssize_t bytes_avail, to_consume = 0;  	(void) offset; /* UNUSED */ @@ -2088,19 +2142,21 @@ 	}  	compressed_buf = sp = __archive_read_ahead(a, 1, &bytes_avail);+	if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)+		&& bytes_avail > zip->entry_bytes_remaining) {+		bytes_avail = (ssize_t)zip->entry_bytes_remaining;+	} 	if (bytes_avail < 0) { 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 		    "Truncated xz file body"); 		return (ARCHIVE_FATAL); 	} -	in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);--	zip_read_decrypt(zip, compressed_buf, in_bytes,-		&compressed_buf, &in_bytes, &sp);+	zip_read_decrypt(zip, compressed_buf, bytes_avail,+		&compressed_buf, &bytes_avail, &sp);  	zip->zipx_lzma_stream.next_in = compressed_buf;-	zip->zipx_lzma_stream.avail_in = in_bytes;+	zip->zipx_lzma_stream.avail_in = bytes_avail; 	zip->zipx_lzma_stream.total_in = 0; 	zip->zipx_lzma_stream.next_out = zip->uncompressed_buffer; 	zip->zipx_lzma_stream.avail_out = zip->uncompressed_buffer_size;@@ -2127,8 +2183,10 @@ 			lzma_end(&zip->zipx_lzma_stream); 			zip->zipx_lzma_valid = 0; -			if((int64_t) zip->zipx_lzma_stream.total_in !=-			    zip->entry_bytes_remaining)+			/* This assertion is only possible if the size of the compressed data+			 * stream is known -> !ZIP_LENGTH_AT_END */+			if((int64_t) zip->zipx_lzma_stream.total_in != zip->entry_bytes_remaining+				&& !(zip->entry->zip_flags & ZIP_LENGTH_AT_END)) 			{ 				archive_set_error(&a->archive, 				    ARCHIVE_ERRNO_MISC,@@ -2167,12 +2225,12 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,     size_t *size, int64_t *offset) {-	struct zip* zip = (struct zip *)(a->format->data);+	struct zip *zip = a->format->data; 	int ret; 	lzma_ret lz_ret; 	const void* compressed_buf; 	const void* sp;-	ssize_t bytes_avail, in_bytes, to_consume;+	ssize_t bytes_avail, to_consume;  	(void) offset; /* UNUSED */ @@ -2192,29 +2250,38 @@ 	 * data. 	 */ 	compressed_buf = __archive_read_ahead(a, 1, &bytes_avail);+	if (zip->entry_bytes_remaining > 0+		&& bytes_avail > zip->entry_bytes_remaining) {+		bytes_avail = (ssize_t)zip->entry_bytes_remaining;+	} 	if (bytes_avail < 0) { 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 		    "Truncated lzma file body"); 		return (ARCHIVE_FATAL); 	} -	/* Set decompressor parameters. */-	in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);--	zip_read_decrypt(zip, compressed_buf, in_bytes,-	    &compressed_buf, &in_bytes, &sp);+	zip_read_decrypt(zip, compressed_buf, bytes_avail,+	    &compressed_buf, &bytes_avail, &sp);  	zip->zipx_lzma_stream.next_in = compressed_buf;-	zip->zipx_lzma_stream.avail_in = in_bytes;+	zip->zipx_lzma_stream.avail_in = bytes_avail; 	zip->zipx_lzma_stream.total_in = 0; 	zip->zipx_lzma_stream.next_out = zip->uncompressed_buffer;-	zip->zipx_lzma_stream.avail_out =-		/* These lzma_alone streams lack end of stream marker, so let's-		 * make sure the unpacker won't try to unpack more than it's-		 * supposed to. */-		(size_t)zipmin((int64_t) zip->uncompressed_buffer_size,-		    zip->entry->uncompressed_size --		    zip->entry_uncompressed_bytes_read);+	/* These lzma_alone streams lack an end of stream marker in some+	 * cases, so when the uncompressed size is known we cap avail_out to+	 * make sure the unpacker won't try to unpack more than it's supposed+	 * to.  When the compressed size is unknown (entry_bytes_remaining <= 0,+	 * e.g. ZIP_LENGTH_AT_END from a non-seekable source) we must use the+	 * full buffer and rely on the LZMA stream end marker to detect the end+	 * of the entry. */+	if (zip->entry_bytes_remaining <= 0) {+		zip->zipx_lzma_stream.avail_out = zip->uncompressed_buffer_size;+	} else {+		zip->zipx_lzma_stream.avail_out =+			(size_t)zipmin((int64_t) zip->uncompressed_buffer_size,+			    zip->entry->uncompressed_size -+			    zip->entry_uncompressed_bytes_read);+	} 	zip->zipx_lzma_stream.total_out = 0;  	/* Perform the decompression. */@@ -2228,8 +2295,11 @@ 		/* This case is optional in lzma alone format. It can happen, 		 * but most of the files don't have it. (GitHub #1257) */ 		case LZMA_STREAM_END:+			/* This assertion is only possible if the size of the+			 * compressed data stream is known. */ 			if((int64_t) zip->zipx_lzma_stream.total_in !=-			    zip->entry_bytes_remaining)+			    zip->entry_bytes_remaining+			    && zip->entry_bytes_remaining > 0) 			{ 				archive_set_error(&a->archive, 				    ARCHIVE_ERRNO_MISC,@@ -2245,7 +2315,13 @@  		case LZMA_BUF_ERROR: 			if (zip->zipx_lzma_stream.avail_out == 0) {-				zip->end_of_entry = 1;+				/* The output buffer was filled exactly.  When+				 * the uncompressed size is known this means we+				 * have decompressed all expected bytes.  When+				 * the size is unknown a full buffer just means+				 * we need another iteration. */+				if (zip->entry_bytes_remaining > 0)+					zip->end_of_entry = 1; 				break; 			} 			/* FALL THROUGH */@@ -2259,14 +2335,16 @@  	/* Update pointers. */ 	__archive_read_consume(a, to_consume);-	zip->entry_bytes_remaining -= to_consume; 	zip->entry_compressed_bytes_read += to_consume; 	zip->entry_uncompressed_bytes_read += zip->zipx_lzma_stream.total_out;  	zip_read_decrypt_update(zip, to_consume, sp); -	if(zip->entry_bytes_remaining == 0) {-		zip->end_of_entry = 1;+	if(zip->entry_bytes_remaining > 0) {+		zip->entry_bytes_remaining -= to_consume;+		if(zip->entry_bytes_remaining == 0) {+			zip->end_of_entry = 1;+		} 	}  	if(zip->end_of_entry && zip->entry_bytes_remaining > 0) {@@ -2417,7 +2495,7 @@ zip_read_data_zipx_ppmd(struct archive_read *a, const void **buff,     size_t *size, int64_t *offset) {-	struct zip* zip = (struct zip *)(a->format->data);+	struct zip *zip = a->format->data; 	int ret; 	size_t consumed_bytes = 0; @@ -2536,8 +2614,8 @@ zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff,     size_t *size, int64_t *offset) {-	struct zip *zip = (struct zip *)(a->format->data);-	ssize_t bytes_avail = 0, in_bytes, to_consume;+	struct zip *zip = a->format->data;+	ssize_t bytes_avail = 0, to_consume; 	const void *compressed_buff; 	const void *sp; 	int r;@@ -2554,30 +2632,26 @@  	/* Fetch more compressed bytes. */ 	compressed_buff = __archive_read_ahead(a, 1, &bytes_avail);-	if(bytes_avail < 0) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Truncated bzip2 file body");-		return (ARCHIVE_FATAL);+	if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)+		&& bytes_avail > zip->entry_bytes_remaining) {+		bytes_avail = (ssize_t)zip->entry_bytes_remaining; 	}--	in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);-	if(in_bytes < 1) {+	if(bytes_avail < 1) { 		/* libbz2 doesn't complain when caller feeds avail_in == 0. 		 * It will actually return success in this case, which is 		 * undesirable. This is why we need to make this check 		 * manually. */- 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 		    "Truncated bzip2 file body"); 		return (ARCHIVE_FATAL); 	} -	zip_read_decrypt(zip, compressed_buff, in_bytes,-	    &compressed_buff, &in_bytes, &sp);+	zip_read_decrypt(zip, compressed_buff, bytes_avail,+	    &compressed_buff, &bytes_avail, &sp);  	/* Setup buffer boundaries. */ 	zip->bzstream.next_in = (char*)(uintptr_t) compressed_buff;-	zip->bzstream.avail_in = (uint32_t)in_bytes;+	zip->bzstream.avail_in = (uint32_t)bytes_avail; 	zip->bzstream.total_in_hi32 = 0; 	zip->bzstream.total_in_lo32 = 0; 	zip->bzstream.next_out = (char*) zip->uncompressed_buffer;@@ -2691,8 +2765,8 @@ zip_read_data_zipx_zstd(struct archive_read *a, const void **buff,     size_t *size, int64_t *offset) {-	struct zip *zip = (struct zip *)(a->format->data);-	ssize_t bytes_avail = 0, in_bytes, to_consume;+	struct zip *zip = a->format->data;+	ssize_t bytes_avail = 0, to_consume; 	const void *compressed_buff; 	const void *sp; 	int r;@@ -2712,14 +2786,11 @@  	/* Fetch more compressed bytes */ 	compressed_buff = sp = __archive_read_ahead(a, 1, &bytes_avail);-	if(bytes_avail < 0) {-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,-		    "Truncated zstd file body");-		return (ARCHIVE_FATAL);+	if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)+		&& bytes_avail > zip->entry_bytes_remaining) {+		bytes_avail = (ssize_t)zip->entry_bytes_remaining; 	}--	in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);-	if(in_bytes < 1) {+	if(bytes_avail < 1) { 		/* zstd doesn't complain when caller feeds avail_in == 0. 		 * It will actually return success in this case, which is 		 * undesirable. This is why we need to make this check@@ -2729,12 +2800,12 @@ 		return (ARCHIVE_FATAL); 	} -	zip_read_decrypt(zip, compressed_buff, in_bytes,-	    &compressed_buff, &in_bytes, &sp);+	zip_read_decrypt(zip, compressed_buff, bytes_avail,+	    &compressed_buff, &bytes_avail, &sp);  	/* Setup buffer boundaries */ 	in.src = compressed_buff;-	in.size = in_bytes;+	in.size = bytes_avail; 	in.pos = 0; 	out = (ZSTD_outBuffer) { zip->uncompressed_buffer, zip->uncompressed_buffer_size, 0 }; @@ -2746,6 +2817,10 @@ 			ZSTD_getErrorName(ret)); 		return (ARCHIVE_FATAL); 	}+	/* End of stream handling for zips with ZIP_LENGTH_AT_END flag */+	if (ret == 0 && (zip->entry->zip_flags & ZIP_LENGTH_AT_END)) {+		zip->end_of_entry = 1;+	}  	/* Check end of the stream. */ 	if (ret == 0) {@@ -2812,7 +2887,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,     size_t *size, int64_t *offset) {-	struct zip *zip;+	struct zip *zip = a->format->data; 	ssize_t bytes_avail, to_consume = 0; 	const void *compressed_buff; 	const void *sp;@@ -2820,8 +2895,6 @@  	(void)offset; /* UNUSED */ -	zip = (struct zip *)(a->format->data);- 	/* If the buffer hasn't been allocated, allocate it now. */ 	if (zip->uncompressed_buffer == NULL) { 		zip->uncompressed_buffer_size = 256 * 1024;@@ -2914,7 +2987,7 @@ static int read_decryption_header(struct archive_read *a) {-	struct zip *zip = (struct zip *)(a->format->data);+	struct zip *zip = a->format->data; 	const char *p; 	unsigned int remaining_size; 	unsigned int ts;@@ -3108,7 +3181,7 @@ static int zip_alloc_decryption_buffer(struct archive_read *a) {-	struct zip *zip = (struct zip *)(a->format->data);+	struct zip *zip = a->format->data; 	size_t bs = 256 * 1024;  	if (zip->decrypted_buffer == NULL) {@@ -3127,7 +3200,7 @@ static int init_traditional_PKWARE_decryption(struct archive_read *a) {-	struct zip *zip = (struct zip *)(a->format->data);+	struct zip *zip = a->format->data; 	const void *p; 	int retry; 	int r;@@ -3199,7 +3272,7 @@ static int init_WinZip_AES_decryption(struct archive_read *a) {-	struct zip *zip = (struct zip *)(a->format->data);+	struct zip *zip = a->format->data; 	const void *p; 	const uint8_t *pv; 	size_t key_len, salt_len;@@ -3293,8 +3366,8 @@ archive_read_format_zip_read_data(struct archive_read *a,     const void **buff, size_t *size, int64_t *offset) {+	struct zip *zip = a->format->data; 	int r;-	struct zip *zip = (struct zip *)(a->format->data);  	if (zip->has_encrypted_entries == 			ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {@@ -3372,6 +3445,25 @@ 	} 	if (r != ARCHIVE_OK) 		return (r);++	/*+	 * FAIL if there are more uncompressed bytes than were+	 * initially advertised.  The end-of-entry check below also+	 * compares these values, but only once decoding reaches its+	 * own natural end. Fail the entry so a caller relying on+	 * archive_entry_size() as a hard boundary is never misled;+	 * later entries in the archive can still be read normally.+	 */+	if (*size > 0 && zip_entry_size_is_set(zip->entry) &&+	    zip->entry_uncompressed_bytes_read > zip->entry->uncompressed_size) {+		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+		    "ZIP uncompressed data is larger than the declared "+		    "entry size (read at least %jd, expected %jd)",+		    (intmax_t)zip->entry_uncompressed_bytes_read,+		    (intmax_t)zip->entry->uncompressed_size);+		return (ARCHIVE_FAILED);+	}+ 	if (*size > 0) { 		zip->computed_crc32 = zip->crc32func(zip->computed_crc32, *buff, 						     (unsigned)*size);@@ -3402,10 +3494,8 @@ 			    (intmax_t)zip->entry->compressed_size); 			return (ARCHIVE_FAILED); 		}-		/* Size field only stores the lower 32 bits of the actual-		 * size. */-		if ((zip->entry->uncompressed_size & UINT32_MAX)-		    != (zip->entry_uncompressed_bytes_read & UINT32_MAX)) {+		if (zip->entry->uncompressed_size !=+		    zip->entry_uncompressed_bytes_read) { 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 			    "ZIP uncompressed data is wrong size " 			    "(read %jd, expected %jd)",@@ -3421,11 +3511,9 @@ static int archive_read_format_zip_cleanup(struct archive_read *a) {-	struct zip *zip;+	struct zip *zip = a->format->data; 	struct zip_entry *zip_entry, *next_zip_entry; -	zip = (struct zip *)(a->format->data);- #ifdef HAVE_ZLIB_H 	if (zip->stream_valid) 		inflateEnd(&zip->stream);@@ -3473,7 +3561,7 @@ 	free(zip->v_data); 	archive_string_free(&zip->format_name); 	free(zip);-	(a->format->data) = NULL;+	a->format->data = NULL; 	return (ARCHIVE_OK); } @@ -3481,7 +3569,7 @@ archive_read_format_zip_has_encrypted_entries(struct archive_read *_a) { 	if (_a && _a->format) {-		struct zip * zip = (struct zip *)_a->format->data;+		struct zip *zip = _a->format->data; 		if (zip) { 			return zip->has_encrypted_entries; 		}@@ -3493,10 +3581,9 @@ archive_read_format_zip_options(struct archive_read *a,     const char *key, const char *val) {-	struct zip *zip;+	struct zip *zip = a->format->data; 	int ret = ARCHIVE_FAILED; -	zip = (struct zip *)(a->format->data); 	if (strcmp(key, "compat-2x")  == 0) { 		/* Handle filenames as libarchive 2.x */ 		zip->init_default_conversion = (val != NULL) ? 1 : 0;@@ -3603,14 +3690,12 @@ archive_read_format_zip_streamable_read_header(struct archive_read *a,     struct archive_entry *entry) {-	struct zip *zip;+	struct zip *zip = a->format->data;  	a->archive.archive_format = ARCHIVE_FORMAT_ZIP; 	if (a->archive.archive_format_name == NULL) 		a->archive.archive_format_name = "ZIP"; -	zip = (struct zip *)(a->format->data);- 	/* 	 * It should be sufficient to call archive_read_next_header() for 	 * a reader to determine if an entry is encrypted or not. If the@@ -3696,10 +3781,9 @@ static int archive_read_format_zip_read_data_skip_streamable(struct archive_read *a) {-	struct zip *zip;+	struct zip *zip = a->format->data; 	int64_t bytes_skipped; -	zip = (struct zip *)(a->format->data); 	bytes_skipped = __archive_read_consume(a, zip->unconsumed); 	zip->unconsumed = 0; 	if (bytes_skipped < 0)@@ -3941,7 +4025,7 @@ static int archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid) {-	struct zip *zip = (struct zip *)a->format->data;+	struct zip *zip = a->format->data; 	int64_t file_size, current_offset; 	const char *p; 	int i, tail;@@ -4147,7 +4231,6 @@ 	__archive_rb_tree_init(&zip->tree, &rb_ops); 	__archive_rb_tree_init(&zip->tree_rsrc, &rb_rsrc_ops); -	zip->central_directory_entries_total = 0; 	while (1) { 		struct zip_entry *zip_entry; 		size_t filename_length, extra_length, comment_length;@@ -4176,7 +4259,6 @@ 		zip_entry->next = zip->zip_entries; 		zip_entry->flags |= LA_FROM_CENTRAL_DIRECTORY; 		zip->zip_entries = zip_entry;-		zip->central_directory_entries_total++;  		/* version = p[4]; */ 		zip_entry->system = p[5];@@ -4256,12 +4338,14 @@ 			r = rsrc_basename(name, filename_length); 			if (filename_length >= 9 && 			    strncmp("__MACOSX/", name, 9) == 0) {+				const char *name_end;++				name_end = name + filename_length; 				/* If this file is not a resource fork nor 				 * a directory. We should treat it as a non 				 * resource fork file to expose it. */ 				if (name[filename_length-1] != '/' &&-				    (r - name < 3 || r[0] != '.' ||-				     r[1] != '_')) {+				    (name_end - r < 2 || r[0] != '.' || r[1] != '_')) { 					__archive_rb_tree_insert_node( 					    &zip->tree, &zip_entry->node); 					/* Expose its parent directories. */@@ -4339,7 +4423,7 @@ zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,     struct zip_entry *rsrc) {-	struct zip *zip = (struct zip *)a->format->data;+	struct zip *zip = a->format->data; 	unsigned char *metadata, *mp; 	int64_t offset = archive_filter_bytes(&a->archive, 0); 	size_t remaining_bytes, metadata_bytes;@@ -4490,7 +4574,7 @@ archive_read_format_zip_seekable_read_header(struct archive_read *a, 	struct archive_entry *entry) {-	struct zip *zip = (struct zip *)a->format->data;+	struct zip *zip = a->format->data; 	struct zip_entry *rsrc; 	int64_t offset; 	int r, ret = ARCHIVE_OK;@@ -4570,8 +4654,7 @@ static int archive_read_format_zip_read_data_skip_seekable(struct archive_read *a) {-	struct zip *zip;-	zip = (struct zip *)(a->format->data);+	struct zip *zip = a->format->data;  	zip->unconsumed = 0; 	return (ARCHIVE_OK);
c/archive_string.c view
@@ -450,6 +450,8 @@ 	return locale_charset(); #elif HAVE_NL_LANGINFO 	return nl_langinfo(CODESET);+#elif defined(__BIONIC__)+	return "UTF-8"; #else 	return ""; #endif@@ -2325,7 +2327,7 @@  	remaining = length; 	itp = (const uint8_t *)_p;-	while (*itp && remaining > 0) {+	while (remaining > 0 && *itp) { 		if (*itp > 127) { 			// Non-ASCII: Substitute with suitable replacement 			if (sc->flag & SCONV_TO_UTF8) {@@ -2340,6 +2342,7 @@ 			archive_strappend_char(as, *itp); 		} 		++itp;+		--remaining; 	} 	return (return_value); }
c/archive_write.c view
@@ -69,7 +69,7 @@ static int	_archive_write_finish_entry(struct archive *); static ssize_t	_archive_write_data(struct archive *, const void *, size_t); -struct archive_none {+struct client { 	size_t buffer_size; 	size_t avail; 	char *buffer;@@ -135,7 +135,7 @@  	if (bytes_per_block < 0) { 		// Do nothing if the bytes_per_block is negative-		return 0;+		return ARCHIVE_OK; 	} 	a->bytes_per_block = bytes_per_block; 	return (ARCHIVE_OK);@@ -240,8 +240,10 @@ 		/* If unset, a fatal error has already occurred, so this filter 		 * didn't open. We cannot write anything. */ 		return(ARCHIVE_FATAL);+	if (length > (uint64_t)(INT64_MAX - f->bytes_written))+		return(ARCHIVE_FATAL); 	r = (f->write)(f, buff, length);-	f->bytes_written += length;+	f->bytes_written += (int64_t)length; 	return (r); } @@ -338,7 +340,7 @@ }  int-__archive_write_nulls(struct archive_write *a, size_t length)+__archive_write_nulls(struct archive_write *a, uint64_t length) { 	if (length == 0) 		return (ARCHIVE_OK);@@ -357,7 +359,7 @@ archive_write_client_open(struct archive_write_filter *f) { 	struct archive_write *a = (struct archive_write *)f->archive;-	struct archive_none *state;+	struct client *client; 	void *buffer; 	size_t buffer_size; @@ -366,21 +368,21 @@ 	    archive_write_get_bytes_in_last_block(f->archive); 	buffer_size = f->bytes_per_block; -	state = calloc(1, sizeof(*state));+	client = calloc(1, sizeof(*client)); 	buffer = malloc(buffer_size);-	if (state == NULL || buffer == NULL) {-		free(state);+	if (client == NULL || buffer == NULL) {+		free(client); 		free(buffer); 		archive_set_error(f->archive, ENOMEM, 		    "Can't allocate data for output buffering"); 		return (ARCHIVE_FATAL); 	} -	state->buffer_size = buffer_size;-	state->buffer = buffer;-	state->next = state->buffer;-	state->avail = state->buffer_size;-	f->data = state;+	client->buffer_size = buffer_size;+	client->buffer = buffer;+	client->next = client->buffer;+	client->avail = client->buffer_size;+	f->data = client;  	if (a->client_opener == NULL) 		return (ARCHIVE_OK);@@ -392,7 +394,7 @@     const void *_buff, size_t length) { 	struct archive_write *a = (struct archive_write *)f->archive;-        struct archive_none *state = (struct archive_none *)f->data;+	struct client *client = f->data; 	const char *buff = (const char *)_buff; 	ssize_t remaining, to_copy; 	ssize_t bytes_written;@@ -405,7 +407,7 @@ 	 * particular, this supports "no write delay" operation for 	 * special applications.  Just set the block size to zero. 	 */-	if (state->buffer_size == 0) {+	if (client->buffer_size == 0) { 		while (remaining > 0) { 			bytes_written = (a->client_writer)(&a->archive, 			    a->client_data, buff, remaining);@@ -418,20 +420,20 @@ 	}  	/* If the copy buffer isn't empty, try to fill it. */-	if (state->avail < state->buffer_size) {+	if (client->avail < client->buffer_size) { 		/* If buffer is not empty... */ 		/* ... copy data into buffer ... */-		to_copy = ((size_t)remaining > state->avail) ?-			state->avail : (size_t)remaining;-		memcpy(state->next, buff, to_copy);-		state->next += to_copy;-		state->avail -= to_copy;+		to_copy = ((size_t)remaining > client->avail) ?+			client->avail : (size_t)remaining;+		memcpy(client->next, buff, to_copy);+		client->next += to_copy;+		client->avail -= to_copy; 		buff += to_copy; 		remaining -= to_copy; 		/* ... if it's full, write it out. */-		if (state->avail == 0) {-			char *p = state->buffer;-			size_t to_write = state->buffer_size;+		if (client->avail == 0) {+			char *p = client->buffer;+			size_t to_write = client->buffer_size; 			while (to_write > 0) { 				bytes_written = (a->client_writer)(&a->archive, 				    a->client_data, p, to_write);@@ -445,15 +447,15 @@ 				p += bytes_written; 				to_write -= bytes_written; 			}-			state->next = state->buffer;-			state->avail = state->buffer_size;+			client->next = client->buffer;+			client->avail = client->buffer_size; 		} 	} -	while ((size_t)remaining >= state->buffer_size) {+	while ((size_t)remaining >= client->buffer_size) { 		/* Write out full blocks directly to client. */ 		bytes_written = (a->client_writer)(&a->archive,-		    a->client_data, buff, state->buffer_size);+		    a->client_data, buff, client->buffer_size); 		if (bytes_written <= 0) 			return (ARCHIVE_FATAL); 		buff += bytes_written;@@ -462,9 +464,9 @@  	if (remaining > 0) { 		/* Copy last bit into copy buffer. */-		memcpy(state->next, buff, remaining);-		state->next += remaining;-		state->avail -= remaining;+		memcpy(client->next, buff, remaining);+		client->next += remaining;+		client->avail -= remaining; 	} 	return (ARCHIVE_OK); }@@ -473,7 +475,7 @@ archive_write_client_free(struct archive_write_filter *f) { 	struct archive_write *a = (struct archive_write *)f->archive;-	struct archive_none *state = (struct archive_none *)f->data;+	struct client *client = f->data;  	if (a->client_freer) 		(*a->client_freer)(&a->archive, a->client_data);@@ -487,9 +489,9 @@ 	}  	/* Free state. */-	if (state != NULL) {-		free(state->buffer);-		free(state);+	if (client != NULL) {+		free(client->buffer);+		free(client); 		f->data = NULL; 	} @@ -500,7 +502,7 @@ archive_write_client_close(struct archive_write_filter *f) { 	struct archive_write *a = (struct archive_write *)f->archive;-	struct archive_none *state = (struct archive_none *)f->data;+	struct client *client = f->data; 	ssize_t block_length; 	ssize_t target_block_length; 	ssize_t bytes_written;@@ -509,8 +511,8 @@ 	int ret = ARCHIVE_OK;  	/* If there's pending data, pad and write the last block */-	if (state->next != state->buffer) {-		block_length = state->buffer_size - state->avail;+	if (client->next != client->buffer) {+		block_length = client->buffer_size - client->avail;  		/* Tricky calculation to determine size of last block */ 		if (a->bytes_in_last_block <= 0)@@ -524,11 +526,11 @@ 		if (target_block_length > a->bytes_per_block) 			target_block_length = a->bytes_per_block; 		if (block_length < target_block_length) {-			memset(state->next, 0,+			memset(client->next, 0, 			    target_block_length - block_length); 			block_length = target_block_length; 		}-		p = state->buffer;+		p = client->buffer; 		to_write = block_length; 		while (to_write > 0) { 			bytes_written = (a->client_writer)(&a->archive,@@ -683,6 +685,29 @@ 	a->filter_last = NULL; } +int+__archive_write_unregister_format(struct archive_write *a)+{+	int r = ARCHIVE_OK;++	if (a->format_free != NULL)+		r = (a->format_free)(a);++	a->format_data = NULL;+	a->format_name = NULL;+	a->format_init = NULL;+	a->format_options = NULL;+	a->format_finish_entry = NULL;+	a->format_write_header = NULL;+	a->format_write_data = NULL;+	a->format_close = NULL;+	a->format_free = NULL;+	a->archive.archive_format = 0;+	a->archive.archive_format_name = NULL;++	return (r);+}+ /*  * Destroy the archive structure.  *@@ -705,11 +730,9 @@ 		r = archive_write_close(&a->archive);  	/* Release format resources. */-	if (a->format_free != NULL) {-		r1 = (a->format_free)(a);-		if (r1 < r)-			r = r1;-	}+	r1 = __archive_write_unregister_format(a);+	if (r1 < r)+		r = r1;  	__archive_write_filters_free(_a); 
c/archive_write_add_filter_b64encode.c view
@@ -46,7 +46,7 @@  #define LBYTES	57 -struct private_b64encode {+struct b64encode { 	int			mode; 	struct archive_string	name; 	struct archive_string	encoded_buff;@@ -64,6 +64,7 @@ static int archive_filter_b64encode_free(struct archive_write_filter *); static void la_b64_encode(struct archive_string *, const unsigned char *, size_t); static int64_t atol8(const char *, size_t);+static void free_data(struct b64encode *);  static const char base64[] = { 	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',@@ -80,34 +81,38 @@  * Add a compress filter to this write handle.  */ int-archive_write_add_filter_b64encode(struct archive *_a)+archive_write_add_filter_b64encode(struct archive *a) {-	struct archive_write *a = (struct archive_write *)_a;-	struct archive_write_filter *f = __archive_write_allocate_filter(_a);-	struct private_b64encode *state;+	struct archive_write_filter *f;+	struct b64encode *b64encode; -	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,+	archive_check_magic(a, ARCHIVE_WRITE_MAGIC, 	    ARCHIVE_STATE_NEW, "archive_write_add_filter_b64encode"); -	state = calloc(1, sizeof(*state));-	if (state == NULL) {-		archive_set_error(f->archive, ENOMEM,-		    "Can't allocate data for b64encode filter");-		return (ARCHIVE_FATAL);-	}-	archive_strcpy(&state->name, "-");-	state->mode = 0644;+	b64encode = calloc(1, sizeof(*b64encode));+	if (b64encode == NULL)+		goto memerr;+	archive_strcpy(&b64encode->name, "-");+	b64encode->mode = 0644; -	f->data = state;+	f = __archive_write_allocate_filter(a);+	if (f == NULL)+		goto memerr; 	f->name = "b64encode"; 	f->code = ARCHIVE_FILTER_UU;-	f->open = archive_filter_b64encode_open;+	f->data = b64encode; 	f->options = archive_filter_b64encode_options;+	f->open = archive_filter_b64encode_open; 	f->write = archive_filter_b64encode_write; 	f->close = archive_filter_b64encode_close; 	f->free = archive_filter_b64encode_free;  	return (ARCHIVE_OK);+memerr:+	free_data(b64encode);+	archive_set_error(a, ENOMEM,+	    "Can't allocate data for b64encode filter");+	return (ARCHIVE_FATAL); }  /*@@ -117,7 +122,7 @@ archive_filter_b64encode_options(struct archive_write_filter *f, const char *key,     const char *value) {-	struct private_b64encode *state = (struct private_b64encode *)f->data;+	struct b64encode *b64encode = f->data;  	if (strcmp(key, "mode") == 0) { 		int64_t val;@@ -133,7 +138,7 @@ 			    "invalid mode option"); 			return (ARCHIVE_FAILED); 		}-		state->mode = (int)val & 0777;+		b64encode->mode = (int)val & 0777; 		return (ARCHIVE_OK); 	} else if (strcmp(key, "name") == 0) { 		if (value == NULL) {@@ -141,7 +146,7 @@ 			    "name option requires a string"); 			return (ARCHIVE_FAILED); 		}-		archive_strcpy(&state->name, value);+		archive_strcpy(&b64encode->name, value); 		return (ARCHIVE_OK); 	} @@ -157,7 +162,7 @@ static int archive_filter_b64encode_open(struct archive_write_filter *f) {-	struct private_b64encode *state = (struct private_b64encode *)f->data;+	struct b64encode *b64encode = f->data; 	size_t bs = 65536, bpb;  	if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {@@ -170,18 +175,17 @@ 			bs -= bs % bpb; 	} -	state->bs = bs;-	if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) {+	b64encode->bs = bs;+	if (archive_string_ensure(&b64encode->encoded_buff, bs + 512) == NULL) { 		archive_set_error(f->archive, ENOMEM, 		    "Can't allocate data for b64encode buffer"); 		return (ARCHIVE_FATAL); 	} -	archive_string_sprintf(&state->encoded_buff, "begin-base64 %o %s\n",-	    (unsigned int)state->mode, state->name.s);+	archive_string_sprintf(&b64encode->encoded_buff, "begin-base64 %o %s\n",+	    (unsigned int)b64encode->mode, b64encode->name.s); -	f->data = state;-	return (0);+	return (ARCHIVE_OK); }  static void@@ -225,39 +229,39 @@ archive_filter_b64encode_write(struct archive_write_filter *f, const void *buff,     size_t length) {-	struct private_b64encode *state = (struct private_b64encode *)f->data;+	struct b64encode *b64encode = f->data; 	const unsigned char *p = buff; 	int ret = ARCHIVE_OK;  	if (length == 0) 		return (ret); -	if (state->hold_len) {-		while (state->hold_len < LBYTES && length > 0) {-			state->hold[state->hold_len++] = *p++;+	if (b64encode->hold_len) {+		while (b64encode->hold_len < LBYTES && length > 0) {+			b64encode->hold[b64encode->hold_len++] = *p++; 			length--; 		}-		if (state->hold_len < LBYTES)+		if (b64encode->hold_len < LBYTES) 			return (ret);-		la_b64_encode(&state->encoded_buff, state->hold, LBYTES);-		state->hold_len = 0;+		la_b64_encode(&b64encode->encoded_buff, b64encode->hold, LBYTES);+		b64encode->hold_len = 0; 	}  	for (; length >= LBYTES; length -= LBYTES, p += LBYTES)-		la_b64_encode(&state->encoded_buff, p, LBYTES);+		la_b64_encode(&b64encode->encoded_buff, p, LBYTES);  	/* Save remaining bytes. */ 	if (length > 0) {-		memcpy(state->hold, p, length);-		state->hold_len = length;+		memcpy(b64encode->hold, p, length);+		b64encode->hold_len = length; 	}-	while (archive_strlen(&state->encoded_buff) >= state->bs) {+	while (archive_strlen(&b64encode->encoded_buff) >= b64encode->bs) { 		ret = __archive_write_filter(f->next_filter,-		    state->encoded_buff.s, state->bs);-		memmove(state->encoded_buff.s,-		    state->encoded_buff.s + state->bs,-		    state->encoded_buff.length - state->bs);-		state->encoded_buff.length -= state->bs;+		    b64encode->encoded_buff.s, b64encode->bs);+		memmove(b64encode->encoded_buff.s,+		    b64encode->encoded_buff.s + b64encode->bs,+		    b64encode->encoded_buff.length - b64encode->bs);+		b64encode->encoded_buff.length -= b64encode->bs; 	}  	return (ret);@@ -270,26 +274,24 @@ static int archive_filter_b64encode_close(struct archive_write_filter *f) {-	struct private_b64encode *state = (struct private_b64encode *)f->data;+	struct b64encode *b64encode = f->data;  	/* Flush remaining bytes. */-	if (state->hold_len != 0)-		la_b64_encode(&state->encoded_buff, state->hold, state->hold_len);-	archive_string_sprintf(&state->encoded_buff, "====\n");+	if (b64encode->hold_len != 0)+		la_b64_encode(&b64encode->encoded_buff, b64encode->hold,+		    b64encode->hold_len);+	archive_string_sprintf(&b64encode->encoded_buff, "====\n"); 	/* Write the last block */ 	archive_write_set_bytes_in_last_block(f->archive, 1); 	return __archive_write_filter(f->next_filter,-	    state->encoded_buff.s, archive_strlen(&state->encoded_buff));+	    b64encode->encoded_buff.s, archive_strlen(&b64encode->encoded_buff)); }  static int archive_filter_b64encode_free(struct archive_write_filter *f) {-	struct private_b64encode *state = (struct private_b64encode *)f->data;--	archive_string_free(&state->name);-	archive_string_free(&state->encoded_buff);-	free(state);+	free_data(f->data);+	f->data = NULL; 	return (ARCHIVE_OK); } @@ -316,3 +318,12 @@ 	return (l); } +static void+free_data(struct b64encode *b64encode)+{+	if (b64encode != NULL) {+		archive_string_free(&b64encode->name);+		archive_string_free(&b64encode->encoded_buff);+		free(b64encode);+	}+}
c/archive_write_add_filter_bzip2.c view
@@ -53,7 +53,7 @@ } #endif -struct private_data {+struct bzip2 { 	int		 compression_level; #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR) 	bz_stream	 stream;@@ -71,50 +71,66 @@ 		    const char *, const char *); static int archive_compressor_bzip2_write(struct archive_write_filter *, 		    const void *, size_t);+static void free_data(struct bzip2 *);  /*  * Add a bzip2 compression filter to this write handle.  */ int-archive_write_add_filter_bzip2(struct archive *_a)+archive_write_add_filter_bzip2(struct archive *a) {-	struct archive_write *a = (struct archive_write *)_a;-	struct archive_write_filter *f = __archive_write_allocate_filter(_a);-	struct private_data *data;+	struct archive_write_filter *f;+	struct bzip2 *bzip2;+	int r; -	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,+	archive_check_magic(a, ARCHIVE_WRITE_MAGIC, 	    ARCHIVE_STATE_NEW, "archive_write_add_filter_bzip2"); -	data = calloc(1, sizeof(*data));-	if (data == NULL) {-		archive_set_error(&a->archive, ENOMEM, "Out of memory");-		return (ARCHIVE_FATAL);-	}-	data->compression_level = 9; /* default */--	f->data = data;-	f->options = &archive_compressor_bzip2_options;-	f->close = &archive_compressor_bzip2_close;-	f->free = &archive_compressor_bzip2_free;-	f->open = &archive_compressor_bzip2_open;-	f->code = ARCHIVE_FILTER_BZIP2;-	f->name = "bzip2";+	bzip2 = calloc(1, sizeof(*bzip2));+	if (bzip2 == NULL)+		goto memerr; #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)-	return (ARCHIVE_OK);+	bzip2->compression_level = 9;++	r = ARCHIVE_OK; #else-	data->pdata = __archive_write_program_allocate("bzip2");-	if (data->pdata == NULL) {-		free(data);-		archive_set_error(&a->archive, ENOMEM, "Out of memory");-		return (ARCHIVE_FATAL);-	}-	data->compression_level = 0;-	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+	bzip2->pdata = __archive_write_program_allocate("bzip2");+	if (bzip2->pdata == NULL)+		goto memerr;+	bzip2->compression_level = 0;++	archive_set_error(a, ARCHIVE_ERRNO_MISC, 	    "Using external bzip2 program");-	return (ARCHIVE_WARN);+	r = ARCHIVE_WARN; #endif++	f = __archive_write_allocate_filter(a);+	if (f == NULL)+		goto memerr;+	f->name = "bzip2";+	f->code = ARCHIVE_FILTER_BZIP2;+	f->data = bzip2;+	f->options = archive_compressor_bzip2_options;+	f->open = archive_compressor_bzip2_open;+	f->write = archive_compressor_bzip2_write;+	f->close = archive_compressor_bzip2_close;+	f->free = archive_compressor_bzip2_free;++	return (r);+memerr:+	free_data(bzip2);+	archive_set_error(a, ENOMEM, "Out of memory");+	return (ARCHIVE_FATAL); } +static int+archive_compressor_bzip2_free(struct archive_write_filter *f)+{+	free_data(f->data);+	f->data = NULL;+	return (ARCHIVE_OK);+}+ /*  * Set write options.  */@@ -122,7 +138,7 @@ archive_compressor_bzip2_options(struct archive_write_filter *f,     const char *key, const char *value) {-	struct private_data *data = (struct private_data *)f->data;+	struct bzip2 *bzip2 = f->data;  	if (strcmp(key, "compression-level") == 0) { 		if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||@@ -131,12 +147,12 @@ 			    "compression-level invalid"); 			return (ARCHIVE_FAILED); 		}-		data->compression_level = value[0] - '0';+		bzip2->compression_level = value[0] - '0'; 		/* Make '0' be a synonym for '1'. */ 		/* This way, bzip2 compressor supports the same 0..9 		 * range of levels as gzip. */-		if (data->compression_level < 1)-			data->compression_level = 1;+		if (bzip2->compression_level < 1)+			bzip2->compression_level = 1; 		return (ARCHIVE_OK); 	} @@ -156,7 +172,7 @@ #define	SET_NEXT_IN(st,src)					\ 	(st)->stream.next_in = (char *)(uintptr_t)(const void *)(src) static int drive_compressor(struct archive_write_filter *,-		    struct private_data *, int finishing);+		    struct bzip2 *, int finishing);  /*  * Setup callback.@@ -164,10 +180,10 @@ static int archive_compressor_bzip2_open(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct bzip2 *bzip2 = f->data; 	int ret; -	if (data->compressed == NULL) {+	if (bzip2->compressed == NULL) { 		size_t bs = 65536, bpb; 		if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { 			/* Buffer size should be a multiple number of the bytes@@ -178,25 +194,23 @@ 			else if (bpb != 0) 				bs -= bs % bpb; 		}-		data->compressed_buffer_size = bs;-		data->compressed = malloc(data->compressed_buffer_size);-		if (data->compressed == NULL) {+		bzip2->compressed_buffer_size = bs;+		bzip2->compressed = malloc(bzip2->compressed_buffer_size);+		if (bzip2->compressed == NULL) { 			archive_set_error(f->archive, ENOMEM, 			    "Can't allocate data for compression buffer"); 			return (ARCHIVE_FATAL); 		} 	} -	memset(&data->stream, 0, sizeof(data->stream));-	data->stream.next_out = data->compressed;-	data->stream.avail_out = (uint32_t)data->compressed_buffer_size;-	f->write = archive_compressor_bzip2_write;+	memset(&bzip2->stream, 0, sizeof(bzip2->stream));+	bzip2->stream.next_out = bzip2->compressed;+	bzip2->stream.avail_out = (uint32_t)bzip2->compressed_buffer_size;  	/* Initialize compression library */-	ret = BZ2_bzCompressInit(&(data->stream),-	    data->compression_level, 0, 30);+	ret = BZ2_bzCompressInit(&(bzip2->stream),+	    bzip2->compression_level, 0, 30); 	if (ret == BZ_OK) {-		f->data = data; 		return (ARCHIVE_OK); 	} @@ -236,12 +250,12 @@ archive_compressor_bzip2_write(struct archive_write_filter *f,     const void *buff, size_t length) {-	struct private_data *data = (struct private_data *)f->data;+	struct bzip2 *bzip2 = f->data;  	/* Compress input data to output buffer */-	SET_NEXT_IN(data, buff);-	data->stream.avail_in = (uint32_t)length;-	if (drive_compressor(f, data, 0))+	SET_NEXT_IN(bzip2, buff);+	bzip2->stream.avail_in = (uint32_t)length;+	if (drive_compressor(f, bzip2, 0)) 		return (ARCHIVE_FATAL); 	return (ARCHIVE_OK); }@@ -253,19 +267,19 @@ static int archive_compressor_bzip2_close(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct bzip2 *bzip2 = f->data; 	int ret;  	/* Finish compression cycle. */-	ret = drive_compressor(f, data, 1);+	ret = drive_compressor(f, bzip2, 1); 	if (ret == ARCHIVE_OK) { 		/* Write the last block */ 		ret = __archive_write_filter(f->next_filter,-		    data->compressed,-		    data->compressed_buffer_size - data->stream.avail_out);+		    bzip2->compressed,+		    bzip2->compressed_buffer_size - bzip2->stream.avail_out); 	} -	switch (BZ2_bzCompressEnd(&(data->stream))) {+	switch (BZ2_bzCompressEnd(&(bzip2->stream))) { 	case BZ_OK: 		break; 	default:@@ -276,20 +290,6 @@ 	return ret; } -static int-archive_compressor_bzip2_free(struct archive_write_filter *f)-{-	struct private_data *data = (struct private_data *)f->data;--	/* May already have been called, but not necessarily. */-	(void)BZ2_bzCompressEnd(&(data->stream));--	free(data->compressed);-	free(data);-	f->data = NULL;-	return (ARCHIVE_OK);-}- /*  * Utility function to push input data through compressor, writing  * full output blocks as necessary.@@ -299,35 +299,35 @@  */ static int drive_compressor(struct archive_write_filter *f,-    struct private_data *data, int finishing)+    struct bzip2 *bzip2, int finishing) { 	int ret;  	for (;;) {-		if (data->stream.avail_out == 0) {+		if (bzip2->stream.avail_out == 0) { 			ret = __archive_write_filter(f->next_filter,-			    data->compressed,-			    data->compressed_buffer_size);+			    bzip2->compressed,+			    bzip2->compressed_buffer_size); 			if (ret != ARCHIVE_OK) { 				/* TODO: Handle this write failure */ 				return (ARCHIVE_FATAL); 			}-			data->stream.next_out = data->compressed;-			data->stream.avail_out = (uint32_t)data->compressed_buffer_size;+			bzip2->stream.next_out = bzip2->compressed;+			bzip2->stream.avail_out = (uint32_t)bzip2->compressed_buffer_size; 		}  		/* If there's nothing to do, we're done. */-		if (!finishing && data->stream.avail_in == 0)+		if (!finishing && bzip2->stream.avail_in == 0) 			return (ARCHIVE_OK); -		ret = BZ2_bzCompress(&(data->stream),+		ret = BZ2_bzCompress(&(bzip2->stream), 		    finishing ? BZ_FINISH : BZ_RUN);  		switch (ret) { 		case BZ_RUN_OK: 			/* In non-finishing case, did compressor 			 * consume everything? */-			if (!finishing && data->stream.avail_in == 0)+			if (!finishing && bzip2->stream.avail_in == 0) 				return (ARCHIVE_OK); 			break; 		case BZ_FINISH_OK:  /* Finishing: There's more work to do */@@ -347,12 +347,24 @@ 	} } +static void+free_data(struct bzip2 *bzip2)+{+	if (bzip2 != NULL) {+		/* May already have been called, but not necessarily. */+		(void)BZ2_bzCompressEnd(&(bzip2->stream));++		free(bzip2->compressed);+		free(bzip2);+	}+}+ #else /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */  static int archive_compressor_bzip2_open(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct bzip2 *bzip2 = f->data; 	struct archive_string as; 	int r; @@ -360,13 +372,12 @@ 	archive_strcpy(&as, "bzip2");  	/* Specify compression level. */-	if (data->compression_level > 0) {+	if (bzip2->compression_level > 0) { 		archive_strcat(&as, " -");-		archive_strappend_char(&as, '0' + data->compression_level);+		archive_strappend_char(&as, '0' + bzip2->compression_level); 	}-	f->write = archive_compressor_bzip2_write; -	r = __archive_write_program_open(f, data->pdata, as.s);+	r = __archive_write_program_open(f, bzip2->pdata, as.s); 	archive_string_free(&as); 	return (r); }@@ -375,27 +386,26 @@ archive_compressor_bzip2_write(struct archive_write_filter *f, const void *buff,     size_t length) {-	struct private_data *data = (struct private_data *)f->data;+	struct bzip2 *bzip2 = f->data; -	return __archive_write_program_write(f, data->pdata, buff, length);+	return __archive_write_program_write(f, bzip2->pdata, buff, length); }  static int archive_compressor_bzip2_close(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct bzip2 *bzip2 = f->data; -	return __archive_write_program_close(f, data->pdata);+	return __archive_write_program_close(f, bzip2->pdata); } -static int-archive_compressor_bzip2_free(struct archive_write_filter *f)+static void+free_data(struct bzip2 *bzip2) {-	struct private_data *data = (struct private_data *)f->data;--	__archive_write_program_free(data->pdata);-	free(data);-	return (ARCHIVE_OK);+	if (bzip2 != NULL) {+		__archive_write_program_free(bzip2->pdata);+		free(bzip2);+	} }  #endif /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */
c/archive_write_add_filter_compress.c view
@@ -85,7 +85,7 @@ #define	FIRST	257		/* First free entry. */ #define	CLEAR	256		/* Table clear output code. */ -struct private_data {+struct compress { 	int64_t in_count, out_count, checkpoint;  	int code_len;			/* Number of bits/code. */@@ -111,6 +111,7 @@ 		    const void *, size_t); static int archive_compressor_compress_close(struct archive_write_filter *); static int archive_compressor_compress_free(struct archive_write_filter *);+static void free_data(struct compress *);  #if ARCHIVE_VERSION_NUMBER < 4000000 int@@ -125,17 +126,35 @@  * Add a compress filter to this write handle.  */ int-archive_write_add_filter_compress(struct archive *_a)+archive_write_add_filter_compress(struct archive *a) {-	struct archive_write *a = (struct archive_write *)_a;-	struct archive_write_filter *f = __archive_write_allocate_filter(_a);+	struct archive_write_filter *f;+	struct compress *compress; -	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,+	archive_check_magic(a, ARCHIVE_WRITE_MAGIC, 	    ARCHIVE_STATE_NEW, "archive_write_add_filter_compress");-	f->open = &archive_compressor_compress_open;-	f->code = ARCHIVE_FILTER_COMPRESS;++	compress = calloc(1, sizeof(*compress));+	if (compress == NULL)+		goto memerr;++	f = __archive_write_allocate_filter(a);+	if (f == NULL)+		goto memerr; 	f->name = "compress";+	f->code = ARCHIVE_FILTER_COMPRESS;+	f->data = compress;+	f->open = archive_compressor_compress_open;+	f->write = archive_compressor_compress_write;+	f->close = archive_compressor_compress_close;+	f->free = archive_compressor_compress_free;+ 	return (ARCHIVE_OK);+memerr:+	free_data(compress);+	archive_set_error(a, ENOMEM,+	    "Can't allocate data for compression");+	return (ARCHIVE_FATAL); }  /*@@ -144,19 +163,9 @@ static int archive_compressor_compress_open(struct archive_write_filter *f) {-	struct private_data *state;+	struct compress *compress = f->data; 	size_t bs = 65536, bpb; -	f->code = ARCHIVE_FILTER_COMPRESS;-	f->name = "compress";--	state = calloc(1, sizeof(*state));-	if (state == NULL) {-		archive_set_error(f->archive, ENOMEM,-		    "Can't allocate data for compression");-		return (ARCHIVE_FATAL);-	}- 	if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { 		/* Buffer size should be a multiple number of the bytes 		 * per block for performance. */@@ -166,41 +175,38 @@ 		else if (bpb != 0) 			bs -= bs % bpb; 	}-	state->compressed_buffer_size = bs;-	state->compressed = malloc(state->compressed_buffer_size);+	compress->compressed_buffer_size = bs;+	compress->compressed = malloc(compress->compressed_buffer_size); -	if (state->compressed == NULL) {+	if (compress->compressed == NULL) { 		archive_set_error(f->archive, ENOMEM, 		    "Can't allocate data for compression buffer");-		free(state); 		return (ARCHIVE_FATAL); 	} -	f->write = archive_compressor_compress_write;-	f->close = archive_compressor_compress_close;-	f->free = archive_compressor_compress_free;--	state->max_maxcode = 0x10000;	/* Should NEVER generate this code. */-	state->in_count = 0;		/* Length of input. */-	state->bit_buf = 0;-	state->bit_offset = 0;-	state->out_count = 3;		/* Includes 3-byte header mojo. */-	state->compress_ratio = 0;-	state->checkpoint = CHECK_GAP;-	state->code_len = 9;-	state->cur_maxcode = MAXCODE(state->code_len);-	state->first_free = FIRST;+	/* Should NEVER generate this code. */+	compress->max_maxcode = 0x10000;+	/* Length of input. */+	compress->in_count = 0;+	compress->bit_buf = 0;+	compress->bit_offset = 0;+	/* Includes 3-byte header mojo. */+	compress->out_count = 3;+	compress->compress_ratio = 0;+	compress->checkpoint = CHECK_GAP;+	compress->code_len = 9;+	compress->cur_maxcode = MAXCODE(compress->code_len);+	compress->first_free = FIRST; -	memset(state->hashtab, 0xff, sizeof(state->hashtab));+	memset(compress->hashtab, 0xff, sizeof(compress->hashtab));  	/* Prime output buffer with a gzip header. */-	state->compressed[0] = 0x1f; /* Compress */-	state->compressed[1] = 0x9d;-	state->compressed[2] = 0x90; /* Block mode, 16bit max */-	state->compressed_offset = 3;+	compress->compressed[0] = 0x1f; /* Compress */+	compress->compressed[1] = 0x9d;+	compress->compressed[2] = 0x90; /* Block mode, 16bit max */+	compress->compressed_offset = 3; -	f->data = state;-	return (0);+	return (ARCHIVE_OK); }  /*-@@ -224,17 +230,17 @@ static int output_byte(struct archive_write_filter *f, unsigned char c) {-	struct private_data *state = f->data;+	struct compress *compress = f->data; -	state->compressed[state->compressed_offset++] = c;-	++state->out_count;+	compress->compressed[compress->compressed_offset++] = c;+	++compress->out_count; -	if (state->compressed_buffer_size == state->compressed_offset) {+	if (compress->compressed_buffer_size == compress->compressed_offset) { 		int ret = __archive_write_filter(f->next_filter,-		    state->compressed, state->compressed_buffer_size);+		    compress->compressed, compress->compressed_buffer_size); 		if (ret != ARCHIVE_OK) 			return ARCHIVE_FATAL;-		state->compressed_offset = 0;+		compress->compressed_offset = 0; 	}  	return ARCHIVE_OK;@@ -243,7 +249,7 @@ static int output_code(struct archive_write_filter *f, int ocode) {-	struct private_data *state = f->data;+	struct compress *compress = f->data; 	int bits, ret, clear_flg, bit_offset;  	clear_flg = ocode == CLEAR;@@ -252,11 +258,11 @@ 	 * Since ocode is always >= 8 bits, only need to mask the first 	 * hunk on the left. 	 */-	bit_offset = state->bit_offset % 8;-	state->bit_buf |= (ocode << bit_offset) & 0xff;-	output_byte(f, state->bit_buf);+	bit_offset = compress->bit_offset % 8;+	compress->bit_buf |= (ocode << bit_offset) & 0xff;+	output_byte(f, compress->bit_buf); -	bits = state->code_len - (8 - bit_offset);+	bits = compress->code_len - (8 - bit_offset); 	ocode >>= 8 - bit_offset; 	/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ 	if (bits >= 8) {@@ -265,41 +271,41 @@ 		bits -= 8; 	} 	/* Last bits. */-	state->bit_offset += state->code_len;-	state->bit_buf = ocode & rmask[bits];-	if (state->bit_offset == state->code_len * 8)-		state->bit_offset = 0;+	compress->bit_offset += compress->code_len;+	compress->bit_buf = ocode & rmask[bits];+	if (compress->bit_offset == compress->code_len * 8)+		compress->bit_offset = 0;  	/* 	 * If the next entry is going to be too big for the ocode size, 	 * then increase it, if possible. 	 */-	if (clear_flg || state->first_free > state->cur_maxcode) {+	if (clear_flg || compress->first_free > compress->cur_maxcode) { 	       /* 		* Write the whole buffer, because the input side won't 		* discover the size increase until after it has read it. 		*/-		if (state->bit_offset > 0) {-			while (state->bit_offset < state->code_len * 8) {-				ret = output_byte(f, state->bit_buf);+		if (compress->bit_offset > 0) {+			while (compress->bit_offset < compress->code_len * 8) {+				ret = output_byte(f, compress->bit_buf); 				if (ret != ARCHIVE_OK) 					return ret;-				state->bit_offset += 8;-				state->bit_buf = 0;+				compress->bit_offset += 8;+				compress->bit_buf = 0; 			} 		}-		state->bit_buf = 0;-		state->bit_offset = 0;+		compress->bit_buf = 0;+		compress->bit_offset = 0;  		if (clear_flg) {-			state->code_len = 9;-			state->cur_maxcode = MAXCODE(state->code_len);+			compress->code_len = 9;+			compress->cur_maxcode = MAXCODE(compress->code_len); 		} else {-			state->code_len++;-			if (state->code_len == 16)-				state->cur_maxcode = state->max_maxcode;+			compress->code_len++;+			if (compress->code_len == 16)+				compress->cur_maxcode = compress->max_maxcode; 			else-				state->cur_maxcode = MAXCODE(state->code_len);+				compress->cur_maxcode = MAXCODE(compress->code_len); 		} 	} @@ -309,13 +315,13 @@ static int output_flush(struct archive_write_filter *f) {-	struct private_data *state = f->data;+	struct compress *compress = f->data; 	int ret;  	/* At EOF, write the rest of the buffer. */-	if (state->bit_offset % 8) {-		state->code_len = (state->bit_offset % 8 + 7) / 8;-		ret = output_byte(f, state->bit_buf);+	if (compress->bit_offset % 8) {+		compress->code_len = (compress->bit_offset % 8 + 7) / 8;+		ret = output_byte(f, compress->bit_buf); 		if (ret != ARCHIVE_OK) 			return ret; 	}@@ -330,7 +336,7 @@ archive_compressor_compress_write(struct archive_write_filter *f,     const void *buff, size_t length) {-	struct private_data *state = (struct private_data *)f->data;+	struct compress *compress = f->data; 	int i; 	int ratio; 	int c, disp, ret;@@ -341,23 +347,24 @@  	bp = buff; -	if (state->in_count == 0) {-		state->cur_code = *bp++;-		++state->in_count;+	if (compress->in_count == 0) {+		compress->cur_code = *bp++;+		++compress->in_count; 		--length; 	}  	while (length--) { 		c = *bp++;-		state->in_count++;-		state->cur_fcode = (c << 16) | state->cur_code;-		i = ((c << HSHIFT) ^ state->cur_code);	/* Xor hashing. */+		compress->in_count++;+		compress->cur_fcode = (c << 16) | compress->cur_code;+		/* Xor hashing. */+		i = ((c << HSHIFT) ^ compress->cur_code); -		if (state->hashtab[i] == state->cur_fcode) {-			state->cur_code = state->codetab[i];+		if (compress->hashtab[i] == compress->cur_fcode) {+			compress->cur_code = compress->codetab[i]; 			continue; 		}-		if (state->hashtab[i] < 0)	/* Empty slot. */+		if (compress->hashtab[i] < 0)	/* Empty slot. */ 			goto nomatch; 		/* Secondary hash (after G. Knott). */ 		if (i == 0)@@ -368,40 +375,40 @@ 		if ((i -= disp) < 0) 			i += HSIZE; -		if (state->hashtab[i] == state->cur_fcode) {-			state->cur_code = state->codetab[i];+		if (compress->hashtab[i] == compress->cur_fcode) {+			compress->cur_code = compress->codetab[i]; 			continue; 		}-		if (state->hashtab[i] >= 0)+		if (compress->hashtab[i] >= 0) 			goto probe;  nomatch:-		ret = output_code(f, state->cur_code);+		ret = output_code(f, compress->cur_code); 		if (ret != ARCHIVE_OK) 			return ret;-		state->cur_code = c;-		if (state->first_free < state->max_maxcode) {-			state->codetab[i] = state->first_free++;	/* code -> hashtable */-			state->hashtab[i] = state->cur_fcode;+		compress->cur_code = c;+		if (compress->first_free < compress->max_maxcode) {+			compress->codetab[i] = compress->first_free++;	/* code -> hashtable */+			compress->hashtab[i] = compress->cur_fcode; 			continue; 		}-		if (state->in_count < state->checkpoint)+		if (compress->in_count < compress->checkpoint) 			continue; -		state->checkpoint = state->in_count + CHECK_GAP;+		compress->checkpoint = compress->in_count + CHECK_GAP; -		if (state->in_count <= 0x007fffff && state->out_count != 0)-			ratio = (int)(state->in_count * 256 / state->out_count);-		else if ((ratio = (int)(state->out_count / 256)) == 0)+		if (compress->in_count <= 0x007fffff && compress->out_count != 0)+			ratio = (int)(compress->in_count * 256 / compress->out_count);+		else if ((ratio = (int)(compress->out_count / 256)) == 0) 			ratio = 0x7fffffff; 		else-			ratio = (int)(state->in_count / ratio);+			ratio = (int)(compress->in_count / ratio); -		if (ratio > state->compress_ratio)-			state->compress_ratio = ratio;+		if (ratio > compress->compress_ratio)+			compress->compress_ratio = ratio; 		else {-			state->compress_ratio = 0;-			memset(state->hashtab, 0xff, sizeof(state->hashtab));-			state->first_free = FIRST;+			compress->compress_ratio = 0;+			memset(compress->hashtab, 0xff, sizeof(compress->hashtab));+			compress->first_free = FIRST; 			ret = output_code(f, CLEAR); 			if (ret != ARCHIVE_OK) 				return ret;@@ -418,10 +425,10 @@ static int archive_compressor_compress_close(struct archive_write_filter *f) {-	struct private_data *state = (struct private_data *)f->data;+	struct compress *compress = f->data; 	int ret; -	ret = output_code(f, state->cur_code);+	ret = output_code(f, compress->cur_code); 	if (ret != ARCHIVE_OK) 		return ret; 	ret = output_flush(f);@@ -430,16 +437,23 @@  	/* Write the last block */ 	ret = __archive_write_filter(f->next_filter,-	    state->compressed, state->compressed_offset);+	    compress->compressed, compress->compressed_offset); 	return (ret); }  static int archive_compressor_compress_free(struct archive_write_filter *f) {-	struct private_data *state = (struct private_data *)f->data;--	free(state->compressed);-	free(state);+	free_data(f->data);+	f->data = NULL; 	return (ARCHIVE_OK);+}++static void+free_data(struct compress *compress)+{+	if (compress != NULL) {+		free(compress->compressed);+		free(compress);+	} }
c/archive_write_add_filter_grzip.c view
@@ -35,7 +35,7 @@ #include "archive.h" #include "archive_write_private.h" -struct write_grzip {+struct grzip { 	struct archive_write_program_data *pdata; }; @@ -46,42 +46,45 @@ 		    const void *, size_t); static int archive_write_grzip_close(struct archive_write_filter *); static int archive_write_grzip_free(struct archive_write_filter *);+static void free_data(struct grzip *);  int-archive_write_add_filter_grzip(struct archive *_a)+archive_write_add_filter_grzip(struct archive *a) {-	struct archive_write_filter *f = __archive_write_allocate_filter(_a);-	struct write_grzip *data;+	struct archive_write_filter *f;+	struct grzip *grzip; -	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,+	archive_check_magic(a, ARCHIVE_WRITE_MAGIC, 	    ARCHIVE_STATE_NEW, "archive_write_add_filter_grzip"); -	data = calloc(1, sizeof(*data));-	if (data == NULL) {-		archive_set_error(_a, ENOMEM, "Can't allocate memory");-		return (ARCHIVE_FATAL);-	}-	data->pdata = __archive_write_program_allocate("grzip");-	if (data->pdata == NULL) {-		free(data);-		archive_set_error(_a, ENOMEM, "Can't allocate memory");-		return (ARCHIVE_FATAL);-	}+	grzip = calloc(1, sizeof(*grzip));+	if (grzip == NULL)+		goto memerr;+	grzip->pdata = __archive_write_program_allocate("grzip");+	if (grzip->pdata == NULL)+		goto memerr; +	f = __archive_write_allocate_filter(a);+	if (f == NULL)+		goto memerr; 	f->name = "grzip"; 	f->code = ARCHIVE_FILTER_GRZIP;-	f->data = data;-	f->open = archive_write_grzip_open;+	f->data = grzip; 	f->options = archive_write_grzip_options;+	f->open = archive_write_grzip_open; 	f->write = archive_write_grzip_write; 	f->close = archive_write_grzip_close; 	f->free = archive_write_grzip_free;  	/* Note: This filter always uses an external program, so we 	 * return "warn" to inform of the fact. */-	archive_set_error(_a, ARCHIVE_ERRNO_MISC,+	archive_set_error(a, ARCHIVE_ERRNO_MISC, 	    "Using external grzip program for grzip compression"); 	return (ARCHIVE_WARN);+memerr:+	free_data(grzip);+	archive_set_error(a, ENOMEM, "Can't allocate memory");+	return (ARCHIVE_FATAL); }  static int@@ -100,34 +103,41 @@ static int archive_write_grzip_open(struct archive_write_filter *f) {-	struct write_grzip *data = (struct write_grzip *)f->data;+	struct grzip *grzip = f->data; -	return __archive_write_program_open(f, data->pdata, "grzip");+	return __archive_write_program_open(f, grzip->pdata, "grzip"); }  static int archive_write_grzip_write(struct archive_write_filter *f,     const void *buff, size_t length) {-	struct write_grzip *data = (struct write_grzip *)f->data;+	struct grzip *grzip = f->data; -	return __archive_write_program_write(f, data->pdata, buff, length);+	return __archive_write_program_write(f, grzip->pdata, buff, length); }  static int archive_write_grzip_close(struct archive_write_filter *f) {-	struct write_grzip *data = (struct write_grzip *)f->data;+	struct grzip *grzip = f->data; -	return __archive_write_program_close(f, data->pdata);+	return __archive_write_program_close(f, grzip->pdata); }  static int archive_write_grzip_free(struct archive_write_filter *f) {-	struct write_grzip *data = (struct write_grzip *)f->data;--	__archive_write_program_free(data->pdata);-	free(data);+	free_data(f->data);+	f->data = NULL; 	return (ARCHIVE_OK);+}++static void+free_data(struct grzip *grzip)+{+	if (grzip != NULL) {+		__archive_write_program_free(grzip->pdata);+		free(grzip);+	} }
c/archive_write_add_filter_gzip.c view
@@ -56,7 +56,7 @@  /* Don't compile this if we don't have zlib. */ -struct private_data {+struct gzip { 	int		 compression_level; 	int		 timestamp; 	char	*original_filename;@@ -87,65 +87,66 @@ static int archive_compressor_gzip_free(struct archive_write_filter *); #ifdef HAVE_ZLIB_H static int drive_compressor(struct archive_write_filter *,-		    struct private_data *, int finishing);+		    struct gzip *, int finishing); #endif+static void free_data(struct gzip *);   /*  * Add a gzip compression filter to this write handle.  */ int-archive_write_add_filter_gzip(struct archive *_a)+archive_write_add_filter_gzip(struct archive *a) {-	struct archive_write *a = (struct archive_write *)_a;-	struct archive_write_filter *f = __archive_write_allocate_filter(_a);-	struct private_data *data;-	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,-	    ARCHIVE_STATE_NEW, "archive_write_add_filter_gzip");+	struct archive_write_filter *f;+	struct gzip *gzip;+	int r; -	data = calloc(1, sizeof(*data));-	if (data == NULL) {-		archive_set_error(&a->archive, ENOMEM, "Out of memory");-		return (ARCHIVE_FATAL);-	}-	f->data = data;-	f->open = &archive_compressor_gzip_open;-	f->options = &archive_compressor_gzip_options;-	f->close = &archive_compressor_gzip_close;-	f->free = &archive_compressor_gzip_free;-	f->code = ARCHIVE_FILTER_GZIP;-	f->name = "gzip";+	archive_check_magic(a, ARCHIVE_WRITE_MAGIC,+	    ARCHIVE_STATE_NEW, "archive_write_add_filter_gzip"); -	data->original_filename = NULL;+	gzip = calloc(1, sizeof(*gzip));+	if (gzip == NULL)+		goto memerr;+	gzip->original_filename = NULL; #ifdef HAVE_ZLIB_H-	data->compression_level = Z_DEFAULT_COMPRESSION;-	return (ARCHIVE_OK);+	gzip->compression_level = Z_DEFAULT_COMPRESSION;++	r = ARCHIVE_OK; #else-	data->pdata = __archive_write_program_allocate("gzip");-	if (data->pdata == NULL) {-		free(data);-		archive_set_error(&a->archive, ENOMEM, "Out of memory");-		return (ARCHIVE_FATAL);-	}-	data->compression_level = 0;-	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+	gzip->pdata = __archive_write_program_allocate("gzip");+	if (gzip->pdata == NULL)+		goto memerr;+	gzip->compression_level = 0;++	archive_set_error(a, ARCHIVE_ERRNO_MISC, 	    "Using external gzip program");-	return (ARCHIVE_WARN);+	r = ARCHIVE_WARN; #endif++	f = __archive_write_allocate_filter(a);+	if (f == NULL)+		goto memerr;+	f->name = "gzip";+	f->code = ARCHIVE_FILTER_GZIP;+	f->data = gzip;+	f->options = archive_compressor_gzip_options;+	f->open = archive_compressor_gzip_open;+	f->write = archive_compressor_gzip_write;+	f->close = archive_compressor_gzip_close;+	f->free = archive_compressor_gzip_free;++	return (r);+memerr:+	free_data(gzip);+	archive_set_error(a, ENOMEM, "Out of memory");+	return (ARCHIVE_FATAL); }  static int archive_compressor_gzip_free(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;--#ifdef HAVE_ZLIB_H-	free(data->compressed);-#else-	__archive_write_program_free(data->pdata);-#endif-	free((void*)data->original_filename);-	free(data);+	free_data(f->data); 	f->data = NULL; 	return (ARCHIVE_OK); }@@ -157,7 +158,7 @@ archive_compressor_gzip_options(struct archive_write_filter *f, const char *key,     const char *value) {-	struct private_data *data = (struct private_data *)f->data;+	struct gzip *gzip = f->data;  	if (strcmp(key, "compression-level") == 0) { 		if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||@@ -166,19 +167,19 @@ 			    "compression-level invalid"); 			return (ARCHIVE_FAILED); 		}-		data->compression_level = value[0] - '0';+		gzip->compression_level = value[0] - '0'; 		return (ARCHIVE_OK); 	} 	if (strcmp(key, "timestamp") == 0) {-		data->timestamp = (value == NULL)?-1:1;+		gzip->timestamp = (value == NULL)?-1:1; 		return (ARCHIVE_OK); 	} 	if (strcmp(key, "original-filename") == 0) {-		free((void*)data->original_filename);-		data->original_filename = NULL;+		free((void*)gzip->original_filename);+		gzip->original_filename = NULL; 		if (value) {-			data->original_filename = strdup(value);-			if (data->original_filename == NULL)+			gzip->original_filename = strdup(value);+			if (gzip->original_filename == NULL) 				return (ARCHIVE_FAILED); 		} 		return (ARCHIVE_OK);@@ -197,11 +198,11 @@ static int archive_compressor_gzip_open(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct gzip *gzip = f->data; 	int ret = ARCHIVE_OK; 	int init_success; -	if (data->compressed == NULL) {+	if (gzip->compressed == NULL) { 		size_t bs = 65536, bpb; 		if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { 			/* Buffer size should be a multiple number of@@ -212,60 +213,60 @@ 			else if (bpb != 0) 				bs -= bs % bpb; 		}-		data->compressed_buffer_size = bs;-		data->compressed = malloc(data->compressed_buffer_size);-		if (data->compressed == NULL) {+		gzip->compressed_buffer_size = bs;+		gzip->compressed = malloc(gzip->compressed_buffer_size);+		if (gzip->compressed == NULL) { 			archive_set_error(f->archive, ENOMEM, 			    "Can't allocate data for compression buffer"); 			return (ARCHIVE_FATAL); 		} 	} -	data->crc = crc32(0L, NULL, 0);-	data->stream.next_out = data->compressed;-	data->stream.avail_out = (uInt)data->compressed_buffer_size;+	gzip->crc = crc32(0L, NULL, 0);+	gzip->stream.next_out = gzip->compressed;+	gzip->stream.avail_out = (uInt)gzip->compressed_buffer_size;  	/* Prime output buffer with a gzip header. */-	data->compressed[0] = 0x1f; /* GZip signature bytes */-	data->compressed[1] = 0x8b;-	data->compressed[2] = 0x08; /* "Deflate" compression */-	data->compressed[3] = 0x00; /* Flags */-	if (data->timestamp >= 0) {+	gzip->compressed[0] = 0x1f; /* GZip signature bytes */+	gzip->compressed[1] = 0x8b;+	gzip->compressed[2] = 0x08; /* "Deflate" compression */+	gzip->compressed[3] = 0x00; /* Flags */+	if (gzip->timestamp >= 0) { 		uint32_t t = (uint32_t)time(NULL);-		archive_le32enc(data->compressed + 4, t); /* Timestamp */+		archive_le32enc(gzip->compressed + 4, t); /* Timestamp */ 	} else {-		memset(&data->compressed[4], 0, 4);+		memset(&gzip->compressed[4], 0, 4); 	}-	if (data->compression_level == 9) {-		data->compressed[8] = 2;-	} else if(data->compression_level == 1) {-		data->compressed[8] = 4;+	if (gzip->compression_level == 9) {+		gzip->compressed[8] = 2;+	} else if(gzip->compression_level == 1) {+		gzip->compressed[8] = 4; 	} else {-		data->compressed[8] = 0;+		gzip->compressed[8] = 0; 	}-	data->compressed[9] = 3; /* OS=Unix */-	data->stream.next_out += 10;-	data->stream.avail_out -= 10;+	gzip->compressed[9] = 3; /* OS=Unix */+	gzip->stream.next_out += 10;+	gzip->stream.avail_out -= 10; -	if (data->original_filename != NULL) {+	if (gzip->original_filename != NULL) { 		/* Limit "original filename" to 32k or the 		 * remaining space in the buffer, whichever is smaller. 		 */-		size_t ofn_length = strlen(data->original_filename);+		size_t ofn_length = strlen(gzip->original_filename); 		size_t ofn_max_length = 32768;-		size_t ofn_space_available = data->compressed-			+ data->compressed_buffer_size-			- data->stream.next_out+		size_t ofn_space_available = gzip->compressed+			+ gzip->compressed_buffer_size+			- gzip->stream.next_out 			- 1; 		if (ofn_max_length > ofn_space_available) { 			ofn_max_length = ofn_space_available; 		} 		if (ofn_length < ofn_max_length) {-			data->compressed[3] |= 0x8;-			strcpy((char*)data->compressed + 10,-			       data->original_filename);-			data->stream.next_out += ofn_length + 1;-			data->stream.avail_out -= ofn_length + 1;+			gzip->compressed[3] |= 0x8;+			strcpy((char*)gzip->compressed + 10,+			       gzip->original_filename);+			gzip->stream.next_out += ofn_length + 1;+			gzip->stream.avail_out -= ofn_length + 1; 		} else { 			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 					  "Gzip 'Original Filename' ignored because it is too long");@@ -273,18 +274,15 @@ 		} 	} -	f->write = archive_compressor_gzip_write;- 	/* Initialize compression library. */-	init_success = deflateInit2(&(data->stream),-	    data->compression_level,+	init_success = deflateInit2(&(gzip->stream),+	    gzip->compression_level, 	    Z_DEFLATED, 	    -15 /* < 0 to suppress zlib header */, 	    8, 	    Z_DEFAULT_STRATEGY);  	if (init_success == Z_OK) {-		f->data = data; 		return (ret); 	} @@ -320,17 +318,17 @@ archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff,     size_t length) {-	struct private_data *data = (struct private_data *)f->data;+	struct gzip *gzip = f->data; 	int ret;  	/* Update statistics */-	data->crc = crc32(data->crc, (const Bytef *)buff, (uInt)length);-	data->total_in += length;+	gzip->crc = crc32(gzip->crc, (const Bytef *)buff, (uInt)length);+	gzip->total_in += length;  	/* Compress input data to output buffer */-	SET_NEXT_IN(data, buff);-	data->stream.avail_in = (uInt)length;-	if ((ret = drive_compressor(f, data, 0)) != ARCHIVE_OK)+	SET_NEXT_IN(gzip, buff);+	gzip->stream.avail_in = (uInt)length;+	if ((ret = drive_compressor(f, gzip, 0)) != ARCHIVE_OK) 		return (ret);  	return (ARCHIVE_OK);@@ -342,26 +340,26 @@ static int archive_compressor_gzip_close(struct archive_write_filter *f) {+	struct gzip *gzip = f->data; 	unsigned char trailer[8];-	struct private_data *data = (struct private_data *)f->data; 	int ret;  	/* Finish compression cycle */-	ret = drive_compressor(f, data, 1);+	ret = drive_compressor(f, gzip, 1); 	if (ret == ARCHIVE_OK) { 		/* Write the last compressed data. */ 		ret = __archive_write_filter(f->next_filter,-		    data->compressed,-		    data->compressed_buffer_size - data->stream.avail_out);+		    gzip->compressed,+		    gzip->compressed_buffer_size - gzip->stream.avail_out); 	} 	if (ret == ARCHIVE_OK) { 		/* Build and write out 8-byte trailer. */-		archive_le32enc(trailer, data->crc);-		archive_le32enc(trailer + 4, data->total_in);+		archive_le32enc(trailer, gzip->crc);+		archive_le32enc(trailer + 4, gzip->total_in); 		ret = __archive_write_filter(f->next_filter, trailer, 8); 	} -	switch (deflateEnd(&(data->stream))) {+	switch (deflateEnd(&(gzip->stream))) { 	case Z_OK: 		break; 	default:@@ -381,34 +379,34 @@  */ static int drive_compressor(struct archive_write_filter *f,-    struct private_data *data, int finishing)+    struct gzip *gzip, int finishing) { 	int ret;  	for (;;) {-		if (data->stream.avail_out == 0) {+		if (gzip->stream.avail_out == 0) { 			ret = __archive_write_filter(f->next_filter,-			    data->compressed,-			    data->compressed_buffer_size);+			    gzip->compressed,+			    gzip->compressed_buffer_size); 			if (ret != ARCHIVE_OK) 				return (ARCHIVE_FATAL);-			data->stream.next_out = data->compressed;-			data->stream.avail_out =-			    (uInt)data->compressed_buffer_size;+			gzip->stream.next_out = gzip->compressed;+			gzip->stream.avail_out =+			    (uInt)gzip->compressed_buffer_size; 		}  		/* If there's nothing to do, we're done. */-		if (!finishing && data->stream.avail_in == 0)+		if (!finishing && gzip->stream.avail_in == 0) 			return (ARCHIVE_OK); -		ret = deflate(&(data->stream),+		ret = deflate(&(gzip->stream), 		    finishing ? Z_FINISH : Z_NO_FLUSH );  		switch (ret) { 		case Z_OK: 			/* In non-finishing case, check if compressor 			 * consumed everything */-			if (!finishing && data->stream.avail_in == 0)+			if (!finishing && gzip->stream.avail_in == 0) 				return (ARCHIVE_OK); 			/* In finishing case, this return always means 			 * there's more work */@@ -427,12 +425,22 @@ 	} } +static void+free_data(struct gzip *gzip)+{+	if (gzip != NULL) {+		free(gzip->compressed);+		free(gzip->original_filename);+		free(gzip);+	}+}+ #else /* HAVE_ZLIB_H */  static int archive_compressor_gzip_open(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct gzip *gzip = f->data; 	struct archive_string as; 	int r; @@ -440,19 +448,18 @@ 	archive_strcpy(&as, "gzip");  	/* Specify compression level. */-	if (data->compression_level > 0) {+	if (gzip->compression_level > 0) { 		archive_strcat(&as, " -");-		archive_strappend_char(&as, '0' + data->compression_level);+		archive_strappend_char(&as, '0' + gzip->compression_level); 	}-	if (data->timestamp < 0)+	if (gzip->timestamp < 0) 		/* Do not save timestamp. */ 		archive_strcat(&as, " -n");-	else if (data->timestamp > 0)+	else if (gzip->timestamp > 0) 		/* Save timestamp. */ 		archive_strcat(&as, " -N"); -	f->write = archive_compressor_gzip_write;-	r = __archive_write_program_open(f, data->pdata, as.s);+	r = __archive_write_program_open(f, gzip->pdata, as.s); 	archive_string_free(&as); 	return (r); }@@ -461,17 +468,26 @@ archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff,     size_t length) {-	struct private_data *data = (struct private_data *)f->data;+	struct gzip *gzip = f->data; -	return __archive_write_program_write(f, data->pdata, buff, length);+	return __archive_write_program_write(f, gzip->pdata, buff, length); }  static int archive_compressor_gzip_close(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct gzip *gzip = f->data; -	return __archive_write_program_close(f, data->pdata);+	return __archive_write_program_close(f, gzip->pdata); } +static void+free_data(struct gzip *gzip)+{+	if (gzip != NULL) {+		__archive_write_program_free(gzip->pdata);+		free(gzip->original_filename);+		free(gzip);+	}+} #endif /* HAVE_ZLIB_H */
c/archive_write_add_filter_lrzip.c view
@@ -39,7 +39,7 @@ #include "archive_string.h" #include "archive_write_private.h" -struct write_lrzip {+struct lrzip { 	struct archive_write_program_data *pdata; 	int	compression_level; 	enum { lzma = 0, bzip2, gzip, lzo, none, zpaq } compression;@@ -52,49 +52,52 @@ 		    const void *, size_t); static int archive_write_lrzip_close(struct archive_write_filter *); static int archive_write_lrzip_free(struct archive_write_filter *);+static void free_data(struct lrzip *);  int-archive_write_add_filter_lrzip(struct archive *_a)+archive_write_add_filter_lrzip(struct archive *a) {-	struct archive_write_filter *f = __archive_write_allocate_filter(_a);-	struct write_lrzip *data;+	struct archive_write_filter *f;+	struct lrzip *lrzip; -	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,+	archive_check_magic(a, ARCHIVE_WRITE_MAGIC, 	    ARCHIVE_STATE_NEW, "archive_write_add_filter_lrzip"); -	data = calloc(1, sizeof(*data));-	if (data == NULL) {-		archive_set_error(_a, ENOMEM, "Can't allocate memory");-		return (ARCHIVE_FATAL);-	}-	data->pdata = __archive_write_program_allocate("lrzip");-	if (data->pdata == NULL) {-		free(data);-		archive_set_error(_a, ENOMEM, "Can't allocate memory");-		return (ARCHIVE_FATAL);-	}+	lrzip = calloc(1, sizeof(*lrzip));+	if (lrzip == NULL)+		goto memerr;+	lrzip->pdata = __archive_write_program_allocate("lrzip");+	if (lrzip->pdata == NULL)+		goto memerr; +	f = __archive_write_allocate_filter(a);+	if (f == NULL)+		goto memerr; 	f->name = "lrzip"; 	f->code = ARCHIVE_FILTER_LRZIP;-	f->data = data;-	f->open = archive_write_lrzip_open;+	f->data = lrzip; 	f->options = archive_write_lrzip_options;+	f->open = archive_write_lrzip_open; 	f->write = archive_write_lrzip_write; 	f->close = archive_write_lrzip_close; 	f->free = archive_write_lrzip_free;  	/* Note: This filter always uses an external program, so we 	 * return "warn" to inform of the fact. */-	archive_set_error(_a, ARCHIVE_ERRNO_MISC,+	archive_set_error(a, ARCHIVE_ERRNO_MISC, 	    "Using external lrzip program for lrzip compression"); 	return (ARCHIVE_WARN);+memerr:+	free_data(lrzip);+	archive_set_error(a, ENOMEM, "Can't allocate memory");+	return (ARCHIVE_FATAL); }  static int archive_write_lrzip_options(struct archive_write_filter *f, const char *key,     const char *value) {-	struct write_lrzip *data = (struct write_lrzip *)f->data;+	struct lrzip *lrzip = f->data;  	if (strcmp(key, "compression") == 0) { 		if (value == NULL) {@@ -103,15 +106,15 @@ 			return (ARCHIVE_FAILED); 		} 		else if (strcmp(value, "bzip2") == 0)-			data->compression = bzip2;+			lrzip->compression = bzip2; 		else if (strcmp(value, "gzip") == 0)-			data->compression = gzip;+			lrzip->compression = gzip; 		else if (strcmp(value, "lzo") == 0)-			data->compression = lzo;+			lrzip->compression = lzo; 		else if (strcmp(value, "none") == 0)-			data->compression = none;+			lrzip->compression = none; 		else if (strcmp(value, "zpaq") == 0)-			data->compression = zpaq;+			lrzip->compression = zpaq; 		else { 			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 			    "compression invalid");@@ -125,7 +128,7 @@ 			    "compression-level invalid"); 			return (ARCHIVE_FAILED); 		}-		data->compression_level = value[0] - '0';+		lrzip->compression_level = value[0] - '0'; 		return (ARCHIVE_OK); 	} 	/* Note: The "warn" return is just to inform the options@@ -137,7 +140,7 @@ static int archive_write_lrzip_open(struct archive_write_filter *f) {-	struct write_lrzip *data = (struct write_lrzip *)f->data;+	struct lrzip *lrzip = f->data; 	struct archive_string as; 	int r; @@ -145,7 +148,7 @@ 	archive_strcpy(&as, "lrzip -q");  	/* Specify compression type. */-	switch (data->compression) {+	switch (lrzip->compression) { 	case lzma:/* default compression */ 		break; 	case bzip2:@@ -166,12 +169,12 @@ 	}  	/* Specify compression level. */-	if (data->compression_level > 0) {+	if (lrzip->compression_level > 0) { 		archive_strcat(&as, " -L ");-		archive_strappend_char(&as, '0' + data->compression_level);+		archive_strappend_char(&as, '0' + lrzip->compression_level); 	} -	r = __archive_write_program_open(f, data->pdata, as.s);+	r = __archive_write_program_open(f, lrzip->pdata, as.s); 	archive_string_free(&as); 	return (r); }@@ -180,25 +183,32 @@ archive_write_lrzip_write(struct archive_write_filter *f,     const void *buff, size_t length) {-	struct write_lrzip *data = (struct write_lrzip *)f->data;+	struct lrzip *lrzip = f->data; -	return __archive_write_program_write(f, data->pdata, buff, length);+	return __archive_write_program_write(f, lrzip->pdata, buff, length); }  static int archive_write_lrzip_close(struct archive_write_filter *f) {-	struct write_lrzip *data = (struct write_lrzip *)f->data;+	struct lrzip *lrzip = f->data; -	return __archive_write_program_close(f, data->pdata);+	return __archive_write_program_close(f, lrzip->pdata); }  static int archive_write_lrzip_free(struct archive_write_filter *f) {-	struct write_lrzip *data = (struct write_lrzip *)f->data;--	__archive_write_program_free(data->pdata);-	free(data);+	free_data(f->data);+	f->data = NULL; 	return (ARCHIVE_OK);+}++static void+free_data(struct lrzip *lrzip)+{+	if (lrzip != NULL) {+		__archive_write_program_free(lrzip->pdata);+		free(lrzip);+	} }
c/archive_write_add_filter_lz4.c view
@@ -50,7 +50,7 @@  #define LZ4_MAGICNUMBER	0x184d2204 -struct private_data {+struct lz4 { 	int		 compression_level; 	unsigned	 header_written:1; 	unsigned	 version_number:1;@@ -85,68 +85,83 @@ 		    const char *, const char *); static int archive_filter_lz4_write(struct archive_write_filter *, 		    const void *, size_t);+static void free_data(struct lz4 *);  /*  * Add an lz4 compression filter to this write handle.  */ int-archive_write_add_filter_lz4(struct archive *_a)+archive_write_add_filter_lz4(struct archive *a) {-	struct archive_write *a = (struct archive_write *)_a;-	struct archive_write_filter *f = __archive_write_allocate_filter(_a);-	struct private_data *data;+	struct archive_write_filter *f;+	struct lz4 *lz4;+	int r; -	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,+	archive_check_magic(a, ARCHIVE_WRITE_MAGIC, 	    ARCHIVE_STATE_NEW, "archive_write_add_filter_lz4"); -	data = calloc(1, sizeof(*data));-	if (data == NULL) {-		archive_set_error(&a->archive, ENOMEM, "Out of memory");-		return (ARCHIVE_FATAL);-	}-+	lz4 = calloc(1, sizeof(*lz4));+	if (lz4 == NULL)+		goto memerr; 	/* 	 * Setup default settings. 	 */-	data->compression_level = 1;-	data->version_number = 0x01;-	data->block_independence = 1;-	data->block_checksum = 0;-	data->stream_size = 0;-	data->stream_checksum = 1;-	data->preset_dictionary = 0;-	data->block_maximum_size = 7;--	/*-	 * Setup a filter setting.-	 */-	f->data = data;-	f->options = &archive_filter_lz4_options;-	f->close = &archive_filter_lz4_close;-	f->free = &archive_filter_lz4_free;-	f->open = &archive_filter_lz4_open;-	f->code = ARCHIVE_FILTER_LZ4;-	f->name = "lz4";+	lz4->version_number = 0x01;+	lz4->block_independence = 1;+	lz4->block_checksum = 0;+	lz4->stream_size = 0;+	lz4->stream_checksum = 1;+	lz4->preset_dictionary = 0;+	lz4->block_maximum_size = 7; #if defined(HAVE_LIBLZ4) && LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 2-	return (ARCHIVE_OK);+	lz4->compression_level = 1;++	r = ARCHIVE_OK; #else 	/* 	 * We don't have lz4 library, and execute external lz4 program 	 * instead. 	 */-	data->pdata = __archive_write_program_allocate("lz4");-	if (data->pdata == NULL) {-		free(data);-		archive_set_error(&a->archive, ENOMEM, "Out of memory");-		return (ARCHIVE_FATAL);-	}-	data->compression_level = 0;-	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+	lz4->pdata = __archive_write_program_allocate("lz4");+	if (lz4->pdata == NULL)+		goto memerr;+	lz4->compression_level = 0;++	archive_set_error(a, ARCHIVE_ERRNO_MISC, 	    "Using external lz4 program");-	return (ARCHIVE_WARN);+	r = ARCHIVE_WARN; #endif++	/*+	 * Setup a filter setting.+	 */+	f = __archive_write_allocate_filter(a);+	if (f == NULL)+		goto memerr;+	f->name = "lz4";+	f->code = ARCHIVE_FILTER_LZ4;+	f->data = lz4;+	f->options = archive_filter_lz4_options;+	f->open = archive_filter_lz4_open;+	f->write = archive_filter_lz4_write;+	f->close = archive_filter_lz4_close;+	f->free = archive_filter_lz4_free;++	return (r);+memerr:+	free_data(lz4);+	archive_set_error(a, ENOMEM, "Out of memory");+	return (ARCHIVE_FATAL); } +static int+archive_filter_lz4_free(struct archive_write_filter *f)+{+	free_data(f->data);+	f->data = NULL;+	return (ARCHIVE_OK);+}+ /*  * Set write options.  */@@ -154,7 +169,7 @@ archive_filter_lz4_options(struct archive_write_filter *f,     const char *key, const char *value) {-	struct private_data *data = (struct private_data *)f->data;+	struct lz4 *lz4 = f->data;  	if (strcmp(key, "compression-level") == 0) { 		int val;@@ -173,15 +188,15 @@ 			return (ARCHIVE_FATAL); 		} #endif-		data->compression_level = val;+		lz4->compression_level = val; 		return (ARCHIVE_OK); 	} 	if (strcmp(key, "stream-checksum") == 0) {-		data->stream_checksum = value != NULL;+		lz4->stream_checksum = value != NULL; 		return (ARCHIVE_OK); 	} 	if (strcmp(key, "block-checksum") == 0) {-		data->block_checksum = value != NULL;+		lz4->block_checksum = value != NULL; 		return (ARCHIVE_OK); 	} 	if (strcmp(key, "block-size") == 0) {@@ -191,11 +206,11 @@ 			    "block-size invalid"); 			return (ARCHIVE_FAILED); 		}-		data->block_maximum_size = value[0] - '0';+		lz4->block_maximum_size = value[0] - '0'; 		return (ARCHIVE_OK); 	} 	if (strcmp(key, "block-dependence") == 0) {-		data->block_independence = value == NULL;+		lz4->block_independence = value == NULL; 		return (ARCHIVE_OK); 	} @@ -225,21 +240,21 @@ static int archive_filter_lz4_open(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct lz4 *lz4 = f->data; 	size_t required_size; 	static const size_t bkmap[] = { 64 * 1024, 256 * 1024, 1 * 1024 * 1024, 			   4 * 1024 * 1024 }; 	size_t pre_block_size; -	if (data->block_maximum_size < 4)-		data->block_size = bkmap[0];+	if (lz4->block_maximum_size < 4)+		lz4->block_size = bkmap[0]; 	else-		data->block_size = bkmap[data->block_maximum_size - 4];+		lz4->block_size = bkmap[lz4->block_maximum_size - 4]; -	required_size = 4 + 15 + 4 + data->block_size + 4 + 4;-	if (data->out_buffer_size < required_size) {+	required_size = 4 + 15 + 4 + lz4->block_size + 4 + 4;+	if (lz4->out_buffer_size < required_size) { 		size_t bs = required_size, bpb;-		free(data->out_buffer);+		free(lz4->out_buffer); 		if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { 			/* Buffer size should be a multiple number of 			 * the bytes per block for performance. */@@ -251,34 +266,32 @@ 				bs -= bs % bpb; 			} 		}-		data->out_block_size = bs;+		lz4->out_block_size = bs; 		bs += required_size;-		data->out_buffer = malloc(bs);-		data->out = data->out_buffer;-		data->out_buffer_size = bs;+		lz4->out_buffer = malloc(bs);+		lz4->out = lz4->out_buffer;+		lz4->out_buffer_size = bs; 	} -	pre_block_size = (data->block_independence)? 0: 64 * 1024;-	if (data->in_buffer_size < data->block_size + pre_block_size) {-		free(data->in_buffer_allocated);-		data->in_buffer_size = data->block_size;-		data->in_buffer_allocated =-		    malloc(data->in_buffer_size + pre_block_size);-		data->in_buffer = data->in_buffer_allocated + pre_block_size;-		if (!data->block_independence && data->compression_level >= 3)-		    data->in_buffer = data->in_buffer_allocated;-		data->in = data->in_buffer;-		data->in_buffer_size = data->block_size;+	pre_block_size = (lz4->block_independence)? 0: 64 * 1024;+	if (lz4->in_buffer_size < lz4->block_size + pre_block_size) {+		free(lz4->in_buffer_allocated);+		lz4->in_buffer_size = lz4->block_size;+		lz4->in_buffer_allocated =+		    malloc(lz4->in_buffer_size + pre_block_size);+		lz4->in_buffer = lz4->in_buffer_allocated + pre_block_size;+		if (!lz4->block_independence && lz4->compression_level >= 3)+		    lz4->in_buffer = lz4->in_buffer_allocated;+		lz4->in = lz4->in_buffer;+		lz4->in_buffer_size = lz4->block_size; 	} -	if (data->out_buffer == NULL || data->in_buffer_allocated == NULL) {+	if (lz4->out_buffer == NULL || lz4->in_buffer_allocated == NULL) { 		archive_set_error(f->archive, ENOMEM, 		    "Can't allocate data for compression buffer"); 		return (ARCHIVE_FATAL); 	} -	f->write = archive_filter_lz4_write;- 	return (ARCHIVE_OK); } @@ -291,18 +304,18 @@ archive_filter_lz4_write(struct archive_write_filter *f,     const void *buff, size_t length) {-	struct private_data *data = (struct private_data *)f->data;+	struct lz4 *lz4 = f->data; 	int ret = ARCHIVE_OK; 	const char *p; 	size_t remaining; 	ssize_t size;  	/* If we haven't written a stream descriptor, we have to do it first. */-	if (!data->header_written) {+	if (!lz4->header_written) { 		ret = lz4_write_stream_descriptor(f); 		if (ret != ARCHIVE_OK) 			return (ret);-		data->header_written = 1;+		lz4->header_written = 1; 	}  	p = (const char *)buff;@@ -313,14 +326,14 @@ 		size = lz4_write_one_block(f, p, remaining); 		if (size < ARCHIVE_OK) 			return (ARCHIVE_FATAL);-		l = data->out - data->out_buffer;-		if (l >= data->out_block_size) {+		l = lz4->out - lz4->out_buffer;+		if (l >= lz4->out_block_size) { 			ret = __archive_write_filter(f->next_filter,-			    data->out_buffer, data->out_block_size);-			l -= data->out_block_size;-			memcpy(data->out_buffer,-			    data->out_buffer + data->out_block_size, l);-			data->out = data->out_buffer + l;+			    lz4->out_buffer, lz4->out_block_size);+			l -= lz4->out_block_size;+			memcpy(lz4->out_buffer,+			    lz4->out_buffer + lz4->out_block_size, l);+			lz4->out = lz4->out_buffer + l; 			if (ret < ARCHIVE_WARN) 				break; 		}@@ -337,7 +350,7 @@ static int archive_filter_lz4_close(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct lz4 *lz4 = f->data; 	int ret;  	/* Finish compression cycle. */@@ -348,77 +361,48 @@ 		 */  		/* Write End Of Stream. */-		memset(data->out, 0, 4); data->out += 4;+		memset(lz4->out, 0, 4); lz4->out += 4; 		/* Write Stream checksum if needed. */-		if (data->stream_checksum) {+		if (lz4->stream_checksum) { 			unsigned int checksum; 			checksum = __archive_xxhash.XXH32_digest(-					data->xxh32_state);-			data->xxh32_state = NULL;-			archive_le32enc(data->out, checksum);-			data->out += 4;+					lz4->xxh32_state);+			lz4->xxh32_state = NULL;+			archive_le32enc(lz4->out, checksum);+			lz4->out += 4; 		} 		ret = __archive_write_filter(f->next_filter,-			    data->out_buffer, data->out - data->out_buffer);+			    lz4->out_buffer, lz4->out - lz4->out_buffer); 	} 	return ret; }  static int-archive_filter_lz4_free(struct archive_write_filter *f)-{-	struct private_data *data = (struct private_data *)f->data;--	if (data->lz4_stream != NULL) {-#ifdef HAVE_LZ4HC_H-		if (data->compression_level >= 3)-#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7-			LZ4_freeStreamHC(data->lz4_stream);-#else-			LZ4_freeHC(data->lz4_stream);-#endif-		else-#endif-#if LZ4_VERSION_MINOR >= 3-			LZ4_freeStream(data->lz4_stream);-#else-			LZ4_free(data->lz4_stream);-#endif-	}-	free(data->out_buffer);-	free(data->in_buffer_allocated);-	free(data->xxh32_state);-	free(data);-	f->data = NULL;-	return (ARCHIVE_OK);-}--static int lz4_write_stream_descriptor(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct lz4 *lz4 = f->data; 	uint8_t *sd; -	sd = (uint8_t *)data->out;+	sd = (uint8_t *)lz4->out; 	/* Write Magic Number. */ 	archive_le32enc(&sd[0], LZ4_MAGICNUMBER); 	/* FLG */-	sd[4] = (data->version_number << 6)-	      | (data->block_independence << 5)-	      | (data->block_checksum << 4)-	      | (data->stream_size << 3)-	      | (data->stream_checksum << 2)-	      | (data->preset_dictionary << 0);+	sd[4] = (lz4->version_number << 6)+	      | (lz4->block_independence << 5)+	      | (lz4->block_checksum << 4)+	      | (lz4->stream_size << 3)+	      | (lz4->stream_checksum << 2)+	      | (lz4->preset_dictionary << 0); 	/* BD */-	sd[5] = (data->block_maximum_size << 4);+	sd[5] = (lz4->block_maximum_size << 4); 	sd[6] = (__archive_xxhash.XXH32(&sd[4], 2, 0) >> 8) & 0xff;-	data->out += 7;-	if (data->stream_checksum) {-		data->xxh32_state = __archive_xxhash.XXH32_init(0);-		if (data->xxh32_state == NULL)+	lz4->out += 7;+	if (lz4->stream_checksum) {+		lz4->xxh32_state = __archive_xxhash.XXH32_init(0);+		if (lz4->xxh32_state == NULL) 			return (ARCHIVE_FATAL); 	} else-		data->xxh32_state = NULL;+		lz4->xxh32_state = NULL; 	return (ARCHIVE_OK); } @@ -426,36 +410,36 @@ lz4_write_one_block(struct archive_write_filter *f, const char *p,     size_t length) {-	struct private_data *data = (struct private_data *)f->data;+	struct lz4 *lz4 = f->data; 	ssize_t r;  	if (p == NULL) { 		/* Compress remaining uncompressed data. */-		if (data->in_buffer == data->in)+		if (lz4->in_buffer == lz4->in) 			return 0; 		else {-			size_t l = data->in - data->in_buffer;-			r = drive_compressor(f, data->in_buffer, l);+			size_t l = lz4->in - lz4->in_buffer;+			r = drive_compressor(f, lz4->in_buffer, l); 			if (r == ARCHIVE_OK) 				r = (ssize_t)l; 		}-	} else if ((data->block_independence || data->compression_level < 3) &&-	    data->in_buffer == data->in && length >= data->block_size) {-		r = drive_compressor(f, p, data->block_size);+	} else if ((lz4->block_independence || lz4->compression_level < 3) &&+	    lz4->in_buffer == lz4->in && length >= lz4->block_size) {+		r = drive_compressor(f, p, lz4->block_size); 		if (r == ARCHIVE_OK)-			r = (ssize_t)data->block_size;+			r = (ssize_t)lz4->block_size; 	} else {-		size_t remaining_size = data->in_buffer_size --			(data->in - data->in_buffer);+		size_t remaining_size = lz4->in_buffer_size -+			(lz4->in - lz4->in_buffer); 		size_t l = (remaining_size > length)? length: remaining_size;-		memcpy(data->in, p, l);-		data->in += l;+		memcpy(lz4->in, p, l);+		lz4->in += l; 		if (l == remaining_size) {-			r = drive_compressor(f, data->in_buffer,-			    data->block_size);+			r = drive_compressor(f, lz4->in_buffer,+			    lz4->block_size); 			if (r == ARCHIVE_OK) 				r = (ssize_t)l;-			data->in = data->in_buffer;+			lz4->in = lz4->in_buffer; 		} else 			r = (ssize_t)l; 	}@@ -474,12 +458,12 @@ static int drive_compressor(struct archive_write_filter *f, const char *p, size_t length) {-	struct private_data *data = (struct private_data *)f->data;+	struct lz4 *lz4 = f->data; -	if (data->stream_checksum)-		__archive_xxhash.XXH32_update(data->xxh32_state,+	if (lz4->stream_checksum)+		__archive_xxhash.XXH32_update(lz4->xxh32_state, 			p, (int)length);-	if (data->block_independence)+	if (lz4->block_independence) 		return drive_compressor_independence(f, p, length); 	else 		return drive_compressor_dependence(f, p, length);@@ -489,48 +473,48 @@ drive_compressor_independence(struct archive_write_filter *f, const char *p,     size_t length) {-	struct private_data *data = (struct private_data *)f->data;+	struct lz4 *lz4 = f->data; 	unsigned int outsize;  #ifdef HAVE_LZ4HC_H-	if (data->compression_level >= 3)+	if (lz4->compression_level >= 3) #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7-		outsize = LZ4_compress_HC(p, data->out + 4,-		     (int)length, (int)data->block_size,-		    data->compression_level);+		outsize = LZ4_compress_HC(p, lz4->out + 4,+		     (int)length, (int)lz4->block_size,+		    lz4->compression_level); #else-		outsize = LZ4_compressHC2_limitedOutput(p, data->out + 4,-		    (int)length, (int)data->block_size,-		    data->compression_level);+		outsize = LZ4_compressHC2_limitedOutput(p, lz4->out + 4,+		    (int)length, (int)lz4->block_size,+		    lz4->compression_level); #endif 	else #endif #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7-		outsize = LZ4_compress_default(p, data->out + 4,-		    (int)length, (int)data->block_size);+		outsize = LZ4_compress_default(p, lz4->out + 4,+		    (int)length, (int)lz4->block_size); #else-		outsize = LZ4_compress_limitedOutput(p, data->out + 4,-		    (int)length, (int)data->block_size);+		outsize = LZ4_compress_limitedOutput(p, lz4->out + 4,+		    (int)length, (int)lz4->block_size); #endif  	if (outsize) { 		/* The buffer is compressed. */-		archive_le32enc(data->out, outsize);-		data->out += 4;+		archive_le32enc(lz4->out, outsize);+		lz4->out += 4; 	} else { 		/* The buffer is not compressed. The compressed size was 		 * bigger than its uncompressed size. */-		archive_le32enc(data->out, (uint32_t)(length | 0x80000000));-		data->out += 4;-		memcpy(data->out, p, length);+		archive_le32enc(lz4->out, (uint32_t)(length | 0x80000000));+		lz4->out += 4;+		memcpy(lz4->out, p, length); 		outsize = (uint32_t)length; 	}-	data->out += outsize;-	if (data->block_checksum) {+	lz4->out += outsize;+	if (lz4->block_checksum) { 		unsigned int checksum =-		    __archive_xxhash.XXH32(data->out - outsize, outsize, 0);-		archive_le32enc(data->out, checksum);-		data->out += 4;+		    __archive_xxhash.XXH32(lz4->out - outsize, outsize, 0);+		archive_le32enc(lz4->out, checksum);+		lz4->out += 4; 	} 	return (ARCHIVE_OK); }@@ -539,21 +523,21 @@ drive_compressor_dependence(struct archive_write_filter *f, const char *p,     size_t length) {-	struct private_data *data = (struct private_data *)f->data;+	struct lz4 *lz4 = f->data; 	int outsize;  #define DICT_SIZE	(64 * 1024) #ifdef HAVE_LZ4HC_H-	if (data->compression_level >= 3) {-		if (data->lz4_stream == NULL) {+	if (lz4->compression_level >= 3) {+		if (lz4->lz4_stream == NULL) { #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7-			data->lz4_stream = LZ4_createStreamHC();-			LZ4_resetStreamHC(data->lz4_stream, data->compression_level);+			lz4->lz4_stream = LZ4_createStreamHC();+			LZ4_resetStreamHC(lz4->lz4_stream, lz4->compression_level); #else-			data->lz4_stream =-			    LZ4_createHC(data->in_buffer_allocated);+			lz4->lz4_stream =+			    LZ4_createHC(lz4->in_buffer_allocated); #endif-			if (data->lz4_stream == NULL) {+			if (lz4->lz4_stream == NULL) { 				archive_set_error(f->archive, ENOMEM, 				    "Can't allocate data for compression" 				    " buffer");@@ -561,23 +545,23 @@ 			} 		} 		else-			LZ4_loadDictHC(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);+			LZ4_loadDictHC(lz4->lz4_stream, lz4->in_buffer_allocated, DICT_SIZE);  #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7 		outsize = LZ4_compress_HC_continue(-		    data->lz4_stream, p, data->out + 4, (int)length,-		    (int)data->block_size);+		    lz4->lz4_stream, p, lz4->out + 4, (int)length,+		    (int)lz4->block_size); #else 		outsize = LZ4_compressHC2_limitedOutput_continue(-		    data->lz4_stream, p, data->out + 4, (int)length,-		    (int)data->block_size, data->compression_level);+		    lz4->lz4_stream, p, lz4->out + 4, (int)length,+		    (int)lz4->block_size, lz4->compression_level); #endif 	} else #endif 	{-		if (data->lz4_stream == NULL) {-			data->lz4_stream = LZ4_createStream();-			if (data->lz4_stream == NULL) {+		if (lz4->lz4_stream == NULL) {+			lz4->lz4_stream = LZ4_createStream();+			if (lz4->lz4_stream == NULL) { 				archive_set_error(f->archive, ENOMEM, 				    "Can't allocate data for compression" 				    " buffer");@@ -585,64 +569,91 @@ 			} 		} 		else-			LZ4_loadDict(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);+			LZ4_loadDict(lz4->lz4_stream, lz4->in_buffer_allocated, DICT_SIZE);  #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7 		outsize = LZ4_compress_fast_continue(-		    data->lz4_stream, p, data->out + 4, (int)length,-		    (int)data->block_size, 1);+		    lz4->lz4_stream, p, lz4->out + 4, (int)length,+		    (int)lz4->block_size, 1); #else 		outsize = LZ4_compress_limitedOutput_continue(-		    data->lz4_stream, p, data->out + 4, (int)length,-		    (int)data->block_size);+		    lz4->lz4_stream, p, lz4->out + 4, (int)length,+		    (int)lz4->block_size); #endif 	}  	if (outsize) { 		/* The buffer is compressed. */-		archive_le32enc(data->out, outsize);-		data->out += 4;+		archive_le32enc(lz4->out, outsize);+		lz4->out += 4; 	} else { 		/* The buffer is not compressed. The compressed size was 		 * bigger than its uncompressed size. */-		archive_le32enc(data->out, (uint32_t)(length | 0x80000000));-		data->out += 4;-		memcpy(data->out, p, length);+		archive_le32enc(lz4->out, (uint32_t)(length | 0x80000000));+		lz4->out += 4;+		memcpy(lz4->out, p, length); 		outsize = (uint32_t)length; 	}-	data->out += outsize;-	if (data->block_checksum) {+	lz4->out += outsize;+	if (lz4->block_checksum) { 		unsigned int checksum =-		    __archive_xxhash.XXH32(data->out - outsize, outsize, 0);-		archive_le32enc(data->out, checksum);-		data->out += 4;+		    __archive_xxhash.XXH32(lz4->out - outsize, outsize, 0);+		archive_le32enc(lz4->out, checksum);+		lz4->out += 4; 	} -	if (length == data->block_size) {+	if (length == lz4->block_size) { #ifdef HAVE_LZ4HC_H-		if (data->compression_level >= 3) {+		if (lz4->compression_level >= 3) { #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7-			LZ4_saveDictHC(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);+			LZ4_saveDictHC(lz4->lz4_stream, lz4->in_buffer_allocated, DICT_SIZE); #else-			LZ4_slideInputBufferHC(data->lz4_stream);+			LZ4_slideInputBufferHC(lz4->lz4_stream); #endif-			data->in_buffer = data->in_buffer_allocated + DICT_SIZE;+			lz4->in_buffer = lz4->in_buffer_allocated + DICT_SIZE; 		} 		else #endif-			LZ4_saveDict(data->lz4_stream,-			    data->in_buffer_allocated, DICT_SIZE);+			LZ4_saveDict(lz4->lz4_stream,+			    lz4->in_buffer_allocated, DICT_SIZE); #undef DICT_SIZE 	} 	return (ARCHIVE_OK); } +static void+free_data(struct lz4 *lz4)+{+	if (lz4 != NULL) {+		if (lz4->lz4_stream != NULL) {+#ifdef HAVE_LZ4HC_H+			if (lz4->compression_level >= 3)+#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7+				LZ4_freeStreamHC(lz4->lz4_stream);+#else+				LZ4_freeHC(lz4->lz4_stream);+#endif+			else+#endif+#if LZ4_VERSION_MINOR >= 3+				LZ4_freeStream(lz4->lz4_stream);+#else+				LZ4_free(lz4->lz4_stream);+#endif+		}+		free(lz4->out_buffer);+		free(lz4->in_buffer_allocated);+		free(lz4->xxh32_state);+		free(lz4);+	}+}+ #else /* HAVE_LIBLZ4 */  static int archive_filter_lz4_open(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct lz4 *lz4 = f->data; 	struct archive_string as; 	int r; @@ -650,24 +661,22 @@ 	archive_strcpy(&as, "lz4 -z -q -q");  	/* Specify a compression level. */-	if (data->compression_level > 0) {+	if (lz4->compression_level > 0) { 		archive_strcat(&as, " -");-		archive_strappend_char(&as, '0' + data->compression_level);+		archive_strappend_char(&as, '0' + lz4->compression_level); 	} 	/* Specify a block size. */ 	archive_strcat(&as, " -B");-	archive_strappend_char(&as, '0' + data->block_maximum_size);+	archive_strappend_char(&as, '0' + lz4->block_maximum_size); -	if (data->block_checksum)+	if (lz4->block_checksum) 		archive_strcat(&as, " -BX");-	if (data->stream_checksum == 0)+	if (lz4->stream_checksum == 0) 		archive_strcat(&as, " --no-frame-crc");-	if (data->block_independence == 0)+	if (lz4->block_independence == 0) 		archive_strcat(&as, " -BD"); -	f->write = archive_filter_lz4_write;--	r = __archive_write_program_open(f, data->pdata, as.s);+	r = __archive_write_program_open(f, lz4->pdata, as.s); 	archive_string_free(&as); 	return (r); }@@ -676,27 +685,26 @@ archive_filter_lz4_write(struct archive_write_filter *f, const void *buff,     size_t length) {-	struct private_data *data = (struct private_data *)f->data;+	struct lz4 *lz4 = f->data; -	return __archive_write_program_write(f, data->pdata, buff, length);+	return __archive_write_program_write(f, lz4->pdata, buff, length); }  static int archive_filter_lz4_close(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct lz4 *lz4 = f->data; -	return __archive_write_program_close(f, data->pdata);+	return __archive_write_program_close(f, lz4->pdata); } -static int-archive_filter_lz4_free(struct archive_write_filter *f)+static void+free_data(struct lz4 *lz4) {-	struct private_data *data = (struct private_data *)f->data;--	__archive_write_program_free(data->pdata);-	free(data);-	return (ARCHIVE_OK);+	if (lz4 != NULL) {+		__archive_write_program_free(lz4->pdata);+		free(lz4);+	} }  #endif /* HAVE_LIBLZ4 */
c/archive_write_add_filter_lzop.c view
@@ -55,7 +55,7 @@ 	METHOD_LZO1X_1_15 = 2, 	METHOD_LZO1X_999 = 3 };-struct write_lzop {+struct lzop { 	int compression_level; #if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H) 	unsigned char	*uncompressed;@@ -80,6 +80,7 @@ 		    const void *, size_t); static int archive_write_lzop_close(struct archive_write_filter *); static int archive_write_lzop_free(struct archive_write_filter *);+static void free_data(struct lzop *);  #if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H) /* Maximum block size. */@@ -133,73 +134,72 @@ #endif  int-archive_write_add_filter_lzop(struct archive *_a)+archive_write_add_filter_lzop(struct archive *a) {-	struct archive_write_filter *f = __archive_write_allocate_filter(_a);-	struct write_lzop *data;+	struct archive_write_filter *f;+	struct lzop *lzop;+	int r; -	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,+	archive_check_magic(a, ARCHIVE_WRITE_MAGIC, 	    ARCHIVE_STATE_NEW, "archive_write_add_filter_lzop"); -	data = calloc(1, sizeof(*data));-	if (data == NULL) {-		archive_set_error(_a, ENOMEM, "Can't allocate memory");-		return (ARCHIVE_FATAL);-	}--	f->name = "lzop";-	f->code = ARCHIVE_FILTER_LZOP;-	f->data = data;-	f->open = archive_write_lzop_open;-	f->options = archive_write_lzop_options;-	f->write = archive_write_lzop_write;-	f->close = archive_write_lzop_close;-	f->free = archive_write_lzop_free;+	lzop = calloc(1, sizeof(*lzop));+	if (lzop == NULL)+		goto memerr; #if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H) 	if (lzo_init() != LZO_E_OK) {-		free(data);-		archive_set_error(_a, ARCHIVE_ERRNO_MISC,+		free_data(lzop);+		archive_set_error(a, ARCHIVE_ERRNO_MISC, 		    "lzo_init(type check) failed"); 		return (ARCHIVE_FATAL); 	} 	if (lzo_version() < 0x940) {-		free(data);-		archive_set_error(_a, ARCHIVE_ERRNO_MISC,+		free_data(lzop);+		archive_set_error(a, ARCHIVE_ERRNO_MISC, 		    "liblzo library is too old(%s < 0.940)", 		    lzo_version_string()); 		return (ARCHIVE_FATAL); 	}-	data->compression_level = 5;-	return (ARCHIVE_OK);+	lzop->compression_level = 5;++	r = ARCHIVE_OK; #else-	data->pdata = __archive_write_program_allocate("lzop");-	if (data->pdata == NULL) {-		free(data);-		archive_set_error(_a, ENOMEM, "Can't allocate memory");-		return (ARCHIVE_FATAL);-	}-	data->compression_level = 0;+	lzop->pdata = __archive_write_program_allocate("lzop");+	if (lzop->pdata == NULL)+		goto memerr;+	lzop->compression_level = 0;+ 	/* Note: We return "warn" to inform of using an external lzop 	 * program. */-	archive_set_error(_a, ARCHIVE_ERRNO_MISC,+	archive_set_error(a, ARCHIVE_ERRNO_MISC, 	    "Using external lzop program for lzop compression");-	return (ARCHIVE_WARN);+	r = ARCHIVE_WARN; #endif++	f = __archive_write_allocate_filter(a);+	if (f == NULL)+		goto memerr;+	f->name = "lzop";+	f->code = ARCHIVE_FILTER_LZOP;+	f->data = lzop;+	f->options = archive_write_lzop_options;+	f->open = archive_write_lzop_open;+	f->write = archive_write_lzop_write;+	f->close = archive_write_lzop_close;+	f->free = archive_write_lzop_free;++	return (r);+memerr:+	free_data(lzop);+	archive_set_error(a, ENOMEM, "Can't allocate memory");+	return (ARCHIVE_FATAL); }  static int archive_write_lzop_free(struct archive_write_filter *f) {-	struct write_lzop *data = (struct write_lzop *)f->data;--#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)-	free(data->uncompressed);-	free(data->compressed);-	free(data->work_buffer);-#else-	__archive_write_program_free(data->pdata);-#endif-	free(data);+	free_data(f->data);+	f->data = NULL; 	return (ARCHIVE_OK); } @@ -207,7 +207,7 @@ archive_write_lzop_options(struct archive_write_filter *f, const char *key,     const char *value) {-	struct write_lzop *data = (struct write_lzop *)f->data;+	struct lzop *lzop = f->data;  	if (strcmp(key, "compression-level") == 0) { 		if (value == NULL || !(value[0] >= '1' && value[0] <= '9') ||@@ -216,7 +216,7 @@ 			    "compression-level invalid"); 			return (ARCHIVE_FAILED); 		}-		data->compression_level = value[0] - '0';+		lzop->compression_level = value[0] - '0'; 		return (ARCHIVE_OK); 	} 	/* Note: The "warn" return is just to inform the options@@ -229,58 +229,58 @@ static int archive_write_lzop_open(struct archive_write_filter *f) {-	struct write_lzop *data = (struct write_lzop *)f->data;+	struct lzop *lzop = f->data; -	switch (data->compression_level) {+	switch (lzop->compression_level) { 	case 1:-		data->method = METHOD_LZO1X_1_15; data->level = 1; break;+		lzop->method = METHOD_LZO1X_1_15; lzop->level = 1; break; 	default: 	case 2: case 3: case 4: case 5: case 6:-		data->method = METHOD_LZO1X_1; data->level = 5; break;+		lzop->method = METHOD_LZO1X_1; lzop->level = 5; break; 	case 7:-		data->method = METHOD_LZO1X_999; data->level = 7; break;+		lzop->method = METHOD_LZO1X_999; lzop->level = 7; break; 	case 8:-		data->method = METHOD_LZO1X_999; data->level = 8; break;+		lzop->method = METHOD_LZO1X_999; lzop->level = 8; break; 	case 9:-		data->method = METHOD_LZO1X_999; data->level = 9; break;+		lzop->method = METHOD_LZO1X_999; lzop->level = 9; break; 	}-	switch (data->method) {+	switch (lzop->method) { 	case METHOD_LZO1X_1:-		data->work_buffer_size = LZO1X_1_MEM_COMPRESS; break;+		lzop->work_buffer_size = LZO1X_1_MEM_COMPRESS; break; 	case METHOD_LZO1X_1_15:-		data->work_buffer_size = LZO1X_1_15_MEM_COMPRESS; break;+		lzop->work_buffer_size = LZO1X_1_15_MEM_COMPRESS; break; 	case METHOD_LZO1X_999:-		data->work_buffer_size = LZO1X_999_MEM_COMPRESS; break;+		lzop->work_buffer_size = LZO1X_999_MEM_COMPRESS; break; 	}-	if (data->work_buffer == NULL) {-		data->work_buffer = (lzo_voidp)malloc(data->work_buffer_size);-		if (data->work_buffer == NULL) {+	if (lzop->work_buffer == NULL) {+		lzop->work_buffer = (lzo_voidp)malloc(lzop->work_buffer_size);+		if (lzop->work_buffer == NULL) { 			archive_set_error(f->archive, ENOMEM, 			    "Can't allocate data for compression buffer"); 			return (ARCHIVE_FATAL); 		} 	}-	if (data->compressed == NULL) {-		data->compressed_buffer_size = sizeof(header) ++	if (lzop->compressed == NULL) {+		lzop->compressed_buffer_size = sizeof(header) + 		    BLOCK_SIZE + (BLOCK_SIZE >> 4) + 64 + 3;-		data->compressed = (unsigned char *)-		    malloc(data->compressed_buffer_size);-		if (data->compressed == NULL) {+		lzop->compressed = (unsigned char *)+		    malloc(lzop->compressed_buffer_size);+		if (lzop->compressed == NULL) { 			archive_set_error(f->archive, ENOMEM, 			    "Can't allocate data for compression buffer"); 			return (ARCHIVE_FATAL); 		} 	}-	if (data->uncompressed == NULL) {-		data->uncompressed_buffer_size = BLOCK_SIZE;-		data->uncompressed = (unsigned char *)-		    malloc(data->uncompressed_buffer_size);-		if (data->uncompressed == NULL) {+	if (lzop->uncompressed == NULL) {+		lzop->uncompressed_buffer_size = BLOCK_SIZE;+		lzop->uncompressed = (unsigned char *)+		    malloc(lzop->uncompressed_buffer_size);+		if (lzop->uncompressed == NULL) { 			archive_set_error(f->archive, ENOMEM, 			    "Can't allocate data for compression buffer"); 			return (ARCHIVE_FATAL); 		}-		data->uncompressed_avail_bytes = BLOCK_SIZE;+		lzop->uncompressed_avail_bytes = BLOCK_SIZE; 	} 	return (ARCHIVE_OK); }@@ -288,68 +288,68 @@ static int make_header(struct archive_write_filter *f) {-	struct write_lzop *data = (struct write_lzop *)f->data;+	struct lzop *lzop = f->data; 	int64_t t; 	uint32_t checksum; -	memcpy(data->compressed, header, sizeof(header));+	memcpy(lzop->compressed, header, sizeof(header)); 	/* Overwrite library version. */-	data->compressed[HEADER_LIBVERSION] = (unsigned char )+	lzop->compressed[HEADER_LIBVERSION] = (unsigned char ) 	    (lzo_version() >> 8) & 0xff;-	data->compressed[HEADER_LIBVERSION + 1] = (unsigned char )+	lzop->compressed[HEADER_LIBVERSION + 1] = (unsigned char ) 	    lzo_version() & 0xff; 	/* Overwrite method and level. */-	data->compressed[HEADER_METHOD] = (unsigned char)data->method;-	data->compressed[HEADER_LEVEL] = data->level;+	lzop->compressed[HEADER_METHOD] = (unsigned char)lzop->method;+	lzop->compressed[HEADER_LEVEL] = lzop->level; 	/* Overwrite mtime with current time. */ 	t = (int64_t)time(NULL);-	archive_be32enc(&data->compressed[HEADER_MTIME_LOW],+	archive_be32enc(&lzop->compressed[HEADER_MTIME_LOW], 	    (uint32_t)(t & 0xffffffff));-	archive_be32enc(&data->compressed[HEADER_MTIME_HIGH],+	archive_be32enc(&lzop->compressed[HEADER_MTIME_HIGH], 	    (uint32_t)((t >> 32) & 0xffffffff)); 	/* Overwrite header checksum with calculated value. */-	checksum = lzo_adler32(1, data->compressed + HEADER_VERSION,+	checksum = lzo_adler32(1, lzop->compressed + HEADER_VERSION, 			(lzo_uint)(HEADER_H_CHECKSUM - HEADER_VERSION));-	archive_be32enc(&data->compressed[HEADER_H_CHECKSUM], checksum);+	archive_be32enc(&lzop->compressed[HEADER_H_CHECKSUM], checksum); 	return (sizeof(header)); }  static int drive_compressor(struct archive_write_filter *f) {-	struct write_lzop *data = (struct write_lzop *)f->data;+	struct lzop *lzop = f->data; 	unsigned char *p; 	const int block_info_bytes = 12; 	int header_bytes, r; 	lzo_uint usize, csize; 	uint32_t checksum; -	if (!data->header_written) {+	if (!lzop->header_written) { 		header_bytes = make_header(f);-		data->header_written = 1;+		lzop->header_written = 1; 	} else 		header_bytes = 0;-	p = data->compressed;+	p = lzop->compressed;  	usize = (lzo_uint)-	    (data->uncompressed_buffer_size - data->uncompressed_avail_bytes);+	    (lzop->uncompressed_buffer_size - lzop->uncompressed_avail_bytes); 	csize = 0;-	switch (data->method) {+	switch (lzop->method) { 	default: 	case METHOD_LZO1X_1:-		r = lzo1x_1_compress(data->uncompressed, usize,+		r = lzo1x_1_compress(lzop->uncompressed, usize, 			p + header_bytes + block_info_bytes, &csize,-			data->work_buffer);+			lzop->work_buffer); 		break; 	case METHOD_LZO1X_1_15:-		r = lzo1x_1_15_compress(data->uncompressed, usize,+		r = lzo1x_1_15_compress(lzop->uncompressed, usize, 			p + header_bytes + block_info_bytes, &csize,-			data->work_buffer);+			lzop->work_buffer); 		break; 	case METHOD_LZO1X_999:-		r = lzo1x_999_compress_level(data->uncompressed, usize,+		r = lzo1x_999_compress_level(lzop->uncompressed, usize, 			p + header_bytes + block_info_bytes, &csize,-			data->work_buffer, NULL, 0, 0, data->level);+			lzop->work_buffer, NULL, 0, 0, lzop->level); 		break; 	} 	if (r != LZO_E_OK) {@@ -361,13 +361,13 @@ 	/* Store uncompressed size. */ 	archive_be32enc(p + header_bytes, (uint32_t)usize); 	/* Store the checksum of the uncompressed data. */-	checksum = lzo_adler32(1, data->uncompressed, usize);+	checksum = lzo_adler32(1, lzop->uncompressed, usize); 	archive_be32enc(p + header_bytes + 8, checksum);  	if (csize < usize) { 		/* Store compressed size. */ 		archive_be32enc(p + header_bytes + 4, (uint32_t)csize);-		r = __archive_write_filter(f->next_filter, data->compressed,+		r = __archive_write_filter(f->next_filter, lzop->compressed, 			header_bytes + block_info_bytes + csize); 	} else { 		/*@@ -375,11 +375,11 @@ 		 */ 		/* Store uncompressed size as compressed size. */ 		archive_be32enc(p + header_bytes + 4, (uint32_t)usize);-		r = __archive_write_filter(f->next_filter, data->compressed,+		r = __archive_write_filter(f->next_filter, lzop->compressed, 			header_bytes + block_info_bytes); 		if (r != ARCHIVE_OK) 			return (ARCHIVE_FATAL);-		r = __archive_write_filter(f->next_filter, data->uncompressed,+		r = __archive_write_filter(f->next_filter, lzop->uncompressed, 			usize); 	} @@ -392,30 +392,30 @@ archive_write_lzop_write(struct archive_write_filter *f,     const void *buff, size_t length) {-	struct write_lzop *data = (struct write_lzop *)f->data;+	struct lzop *lzop = f->data; 	const char *p = buff; 	int r;  	do {-		if (data->uncompressed_avail_bytes > length) {-			memcpy(data->uncompressed-				+ data->uncompressed_buffer_size-				- data->uncompressed_avail_bytes,+		if (lzop->uncompressed_avail_bytes > length) {+			memcpy(lzop->uncompressed+				+ lzop->uncompressed_buffer_size+				- lzop->uncompressed_avail_bytes, 			    p, length);-			data->uncompressed_avail_bytes -= length;+			lzop->uncompressed_avail_bytes -= length; 			return (ARCHIVE_OK); 		} -		memcpy(data->uncompressed + data->uncompressed_buffer_size-			- data->uncompressed_avail_bytes,-		    p, data->uncompressed_avail_bytes);-		length -= data->uncompressed_avail_bytes;-		p += data->uncompressed_avail_bytes;-		data->uncompressed_avail_bytes = 0;+		memcpy(lzop->uncompressed + lzop->uncompressed_buffer_size+			- lzop->uncompressed_avail_bytes,+		    p, lzop->uncompressed_avail_bytes);+		length -= lzop->uncompressed_avail_bytes;+		p += lzop->uncompressed_avail_bytes;+		lzop->uncompressed_avail_bytes = 0;  		r = drive_compressor(f); 		if (r != ARCHIVE_OK) return (r);-		data->uncompressed_avail_bytes = BLOCK_SIZE;+		lzop->uncompressed_avail_bytes = BLOCK_SIZE; 	} while (length);  	return (ARCHIVE_OK);@@ -424,11 +424,11 @@ static int archive_write_lzop_close(struct archive_write_filter *f) {-	struct write_lzop *data = (struct write_lzop *)f->data;+	struct lzop *lzop = f->data; 	const uint32_t endmark = 0; 	int r; -	if (data->uncompressed_avail_bytes < BLOCK_SIZE) {+	if (lzop->uncompressed_avail_bytes < BLOCK_SIZE) { 		/* Compress and output remaining data. */ 		r = drive_compressor(f); 		if (r != ARCHIVE_OK)@@ -439,24 +439,35 @@ 	return __archive_write_filter(f->next_filter, &endmark, sizeof(endmark)); } +static void+free_data(struct lzop *lzop)+{+	if (lzop != NULL) {+		free(lzop->uncompressed);+		free(lzop->compressed);+		free(lzop->work_buffer);+		free(lzop);+	}+}+ #else static int archive_write_lzop_open(struct archive_write_filter *f) {-	struct write_lzop *data = (struct write_lzop *)f->data;+	struct lzop *lzop = f->data; 	struct archive_string as; 	int r;  	archive_string_init(&as); 	archive_strcpy(&as, "lzop"); 	/* Specify compression level. */-	if (data->compression_level > 0) {+	if (lzop->compression_level > 0) { 		archive_strappend_char(&as, ' '); 		archive_strappend_char(&as, '-');-		archive_strappend_char(&as, '0' + data->compression_level);+		archive_strappend_char(&as, '0' + lzop->compression_level); 	} -	r = __archive_write_program_open(f, data->pdata, as.s);+	r = __archive_write_program_open(f, lzop->pdata, as.s); 	archive_string_free(&as); 	return (r); }@@ -465,16 +476,25 @@ archive_write_lzop_write(struct archive_write_filter *f,     const void *buff, size_t length) {-	struct write_lzop *data = (struct write_lzop *)f->data;+	struct lzop *lzop = f->data; -	return __archive_write_program_write(f, data->pdata, buff, length);+	return __archive_write_program_write(f, lzop->pdata, buff, length); }  static int archive_write_lzop_close(struct archive_write_filter *f) {-	struct write_lzop *data = (struct write_lzop *)f->data;+	struct lzop *lzop = f->data; -	return __archive_write_program_close(f, data->pdata);+	return __archive_write_program_close(f, lzop->pdata);+}++static void+free_data(struct lzop *lzop)+{+	if (lzop != NULL) {+		__archive_write_program_free(lzop->pdata);+		free(lzop);+	} } #endif
c/archive_write_add_filter_program.c view
@@ -70,7 +70,7 @@ 	char		*program_name; }; -struct private_data {+struct program { 	struct archive_write_program_data *pdata; 	struct archive_string description; 	char		*cmd;@@ -81,51 +81,53 @@ 		    const void *, size_t); static int archive_compressor_program_close(struct archive_write_filter *); static int archive_compressor_program_free(struct archive_write_filter *);+static void free_data(struct program *);  /*  * Add a filter to this write handle that passes all data through an  * external program.  */ int-archive_write_add_filter_program(struct archive *_a, const char *cmd)+archive_write_add_filter_program(struct archive *a, const char *cmd) {-	struct archive_write_filter *f = __archive_write_allocate_filter(_a);-	struct private_data *data;+	struct archive_write_filter *f;+	struct program *program; 	static const char prefix[] = "Program: "; -	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,+	archive_check_magic(a, ARCHIVE_WRITE_MAGIC, 	    ARCHIVE_STATE_NEW, "archive_write_add_filter_program"); -	f->data = calloc(1, sizeof(*data));-	if (f->data == NULL)+	program = calloc(1, sizeof(*program));+	if (program == NULL) 		goto memerr;-	data = (struct private_data *)f->data;--	data->cmd = strdup(cmd);-	if (data->cmd == NULL)+	program->cmd = strdup(cmd);+	if (program->cmd == NULL) 		goto memerr;--	data->pdata = __archive_write_program_allocate(cmd);-	if (data->pdata == NULL)+	program->pdata = __archive_write_program_allocate(cmd);+	if (program->pdata == NULL) 		goto memerr;- 	/* Make up a description string. */-	if (archive_string_ensure(&data->description,+	if (archive_string_ensure(&program->description, 	    strlen(prefix) + strlen(cmd) + 1) == NULL) 		goto memerr;-	archive_strcpy(&data->description, prefix);-	archive_strcat(&data->description, cmd);+	archive_strcpy(&program->description, prefix);+	archive_strcat(&program->description, cmd); -	f->name = data->description.s;+	f = __archive_write_allocate_filter(a);+	if (f == NULL)+		goto memerr;+	f->name = program->description.s; 	f->code = ARCHIVE_FILTER_PROGRAM;+	f->data = program; 	f->open = archive_compressor_program_open; 	f->write = archive_compressor_program_write; 	f->close = archive_compressor_program_close; 	f->free = archive_compressor_program_free;+ 	return (ARCHIVE_OK); memerr:-	archive_compressor_program_free(f);-	archive_set_error(_a, ENOMEM,+	free_data(program);+	archive_set_error(a, ENOMEM, 	    "Can't allocate memory for filter program"); 	return (ARCHIVE_FATAL); }@@ -133,40 +135,33 @@ static int archive_compressor_program_open(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct program *program = f->data; -	return __archive_write_program_open(f, data->pdata, data->cmd);+	return __archive_write_program_open(f, program->pdata, program->cmd); }  static int archive_compressor_program_write(struct archive_write_filter *f,     const void *buff, size_t length) {-	struct private_data *data = (struct private_data *)f->data;+	struct program *program = f->data; -	return __archive_write_program_write(f, data->pdata, buff, length);+	return __archive_write_program_write(f, program->pdata, buff, length); }  static int archive_compressor_program_close(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct program *program = f->data; -	return __archive_write_program_close(f, data->pdata);+	return __archive_write_program_close(f, program->pdata); }  static int archive_compressor_program_free(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;--	if (data) {-		free(data->cmd);-		archive_string_free(&data->description);-		__archive_write_program_free(data->pdata);-		free(data);-		f->data = NULL;-	}+	free_data(f->data);+	f->data = NULL; 	return (ARCHIVE_OK); } @@ -391,3 +386,13 @@ 	return ret; } +static void+free_data(struct program *program)+{+	if (program) {+		free(program->cmd);+		archive_string_free(&program->description);+		__archive_write_program_free(program->pdata);+		free(program);+	}+}
c/archive_write_add_filter_uuencode.c view
@@ -46,7 +46,7 @@  #define LBYTES 45 -struct private_uuencode {+struct uuencode { 	int			mode; 	struct archive_string	name; 	struct archive_string	encoded_buff;@@ -64,39 +64,44 @@ static int archive_filter_uuencode_free(struct archive_write_filter *); static void uu_encode(struct archive_string *, const unsigned char *, size_t); static int64_t atol8(const char *, size_t);+static void free_data(struct uuencode *);  /*  * Add a compress filter to this write handle.  */ int-archive_write_add_filter_uuencode(struct archive *_a)+archive_write_add_filter_uuencode(struct archive *a) {-	struct archive_write *a = (struct archive_write *)_a;-	struct archive_write_filter *f = __archive_write_allocate_filter(_a);-	struct private_uuencode *state;+	struct archive_write_filter *f;+	struct uuencode *uuencode; -	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,-	    ARCHIVE_STATE_NEW, "archive_write_add_filter_uu");+	archive_check_magic(a, ARCHIVE_WRITE_MAGIC,+	    ARCHIVE_STATE_NEW, "archive_write_add_filter_uuencode"); -	state = calloc(1, sizeof(*state));-	if (state == NULL) {-		archive_set_error(f->archive, ENOMEM,-		    "Can't allocate data for uuencode filter");-		return (ARCHIVE_FATAL);-	}-	archive_strcpy(&state->name, "-");-	state->mode = 0644;+	uuencode = calloc(1, sizeof(*uuencode));+	if (uuencode == NULL)+		goto memerr;+	archive_strcpy(&uuencode->name, "-");+	uuencode->mode = 0644; -	f->data = state;+	f = __archive_write_allocate_filter(a);+	if (f == NULL)+		goto memerr; 	f->name = "uuencode"; 	f->code = ARCHIVE_FILTER_UU;-	f->open = archive_filter_uuencode_open;+	f->data = uuencode; 	f->options = archive_filter_uuencode_options;+	f->open = archive_filter_uuencode_open; 	f->write = archive_filter_uuencode_write; 	f->close = archive_filter_uuencode_close; 	f->free = archive_filter_uuencode_free;  	return (ARCHIVE_OK);+memerr:+	free_data(uuencode);+	archive_set_error(a, ENOMEM,+	    "Can't allocate data for uuencode filter");+	return (ARCHIVE_FATAL); }  /*@@ -106,7 +111,7 @@ archive_filter_uuencode_options(struct archive_write_filter *f, const char *key,     const char *value) {-	struct private_uuencode *state = (struct private_uuencode *)f->data;+	struct uuencode *uuencode = f->data;  	if (strcmp(key, "mode") == 0) { 		int64_t val;@@ -122,7 +127,7 @@ 			    "invalid mode option"); 			return (ARCHIVE_FAILED); 		}-		state->mode = (int)val & 0777;+		uuencode->mode = (int)val & 0777; 		return (ARCHIVE_OK); 	} else if (strcmp(key, "name") == 0) { 		if (value == NULL) {@@ -130,7 +135,7 @@ 			    "name option requires a string"); 			return (ARCHIVE_FAILED); 		}-		archive_strcpy(&state->name, value);+		archive_strcpy(&uuencode->name, value); 		return (ARCHIVE_OK); 	} @@ -146,7 +151,7 @@ static int archive_filter_uuencode_open(struct archive_write_filter *f) {-	struct private_uuencode *state = (struct private_uuencode *)f->data;+	struct uuencode *uuencode = f->data; 	size_t bs = 65536, bpb;  	if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {@@ -159,18 +164,17 @@ 			bs -= bs % bpb; 	} -	state->bs = bs;-	if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) {+	uuencode->bs = bs;+	if (archive_string_ensure(&uuencode->encoded_buff, bs + 512) == NULL) { 		archive_set_error(f->archive, ENOMEM, 		    "Can't allocate data for uuencode buffer"); 		return (ARCHIVE_FATAL); 	} -	archive_string_sprintf(&state->encoded_buff, "begin %o %s\n",-	    (unsigned int)state->mode, state->name.s);+	archive_string_sprintf(&uuencode->encoded_buff, "begin %o %s\n",+	    (unsigned int)uuencode->mode, uuencode->name.s); -	f->data = state;-	return (0);+	return (ARCHIVE_OK); }  static void@@ -216,39 +220,39 @@ archive_filter_uuencode_write(struct archive_write_filter *f, const void *buff,     size_t length) {-	struct private_uuencode *state = (struct private_uuencode *)f->data;+	struct uuencode *uuencode = f->data; 	const unsigned char *p = buff; 	int ret = ARCHIVE_OK;  	if (length == 0) 		return (ret); -	if (state->hold_len) {-		while (state->hold_len < LBYTES && length > 0) {-			state->hold[state->hold_len++] = *p++;+	if (uuencode->hold_len) {+		while (uuencode->hold_len < LBYTES && length > 0) {+			uuencode->hold[uuencode->hold_len++] = *p++; 			length--; 		}-		if (state->hold_len < LBYTES)+		if (uuencode->hold_len < LBYTES) 			return (ret);-		uu_encode(&state->encoded_buff, state->hold, LBYTES);-		state->hold_len = 0;+		uu_encode(&uuencode->encoded_buff, uuencode->hold, LBYTES);+		uuencode->hold_len = 0; 	}  	for (; length >= LBYTES; length -= LBYTES, p += LBYTES)-		uu_encode(&state->encoded_buff, p, LBYTES);+		uu_encode(&uuencode->encoded_buff, p, LBYTES);  	/* Save remaining bytes. */ 	if (length > 0) {-		memcpy(state->hold, p, length);-		state->hold_len = length;+		memcpy(uuencode->hold, p, length);+		uuencode->hold_len = length; 	}-	while (archive_strlen(&state->encoded_buff) >= state->bs) {+	while (archive_strlen(&uuencode->encoded_buff) >= uuencode->bs) { 		ret = __archive_write_filter(f->next_filter,-		    state->encoded_buff.s, state->bs);-		memmove(state->encoded_buff.s,-		    state->encoded_buff.s + state->bs,-		    state->encoded_buff.length - state->bs);-		state->encoded_buff.length -= state->bs;+		    uuencode->encoded_buff.s, uuencode->bs);+		memmove(uuencode->encoded_buff.s,+		    uuencode->encoded_buff.s + uuencode->bs,+		    uuencode->encoded_buff.length - uuencode->bs);+		uuencode->encoded_buff.length -= uuencode->bs; 	}  	return (ret);@@ -261,26 +265,24 @@ static int archive_filter_uuencode_close(struct archive_write_filter *f) {-	struct private_uuencode *state = (struct private_uuencode *)f->data;+	struct uuencode *uuencode = f->data;  	/* Flush remaining bytes. */-	if (state->hold_len != 0)-		uu_encode(&state->encoded_buff, state->hold, state->hold_len);-	archive_string_sprintf(&state->encoded_buff, "`\nend\n");+	if (uuencode->hold_len != 0)+		uu_encode(&uuencode->encoded_buff, uuencode->hold,+		    uuencode->hold_len);+	archive_string_sprintf(&uuencode->encoded_buff, "`\nend\n"); 	/* Write the last block */ 	archive_write_set_bytes_in_last_block(f->archive, 1); 	return __archive_write_filter(f->next_filter,-	    state->encoded_buff.s, archive_strlen(&state->encoded_buff));+	    uuencode->encoded_buff.s, archive_strlen(&uuencode->encoded_buff)); }  static int archive_filter_uuencode_free(struct archive_write_filter *f) {-	struct private_uuencode *state = (struct private_uuencode *)f->data;--	archive_string_free(&state->name);-	archive_string_free(&state->encoded_buff);-	free(state);+	free_data(f->data);+	f->data = NULL; 	return (ARCHIVE_OK); } @@ -307,3 +309,12 @@ 	return (l); } +static void+free_data(struct uuencode *uuencode)+{+	if (uuencode != NULL) {+		archive_string_free(&uuencode->name);+		archive_string_free(&uuencode->encoded_buff);+		free(uuencode);+	}+}
c/archive_write_add_filter_xz.c view
@@ -99,7 +99,7 @@ #else /* Don't compile this if we don't have liblzma. */ -struct private_data {+struct xz { 	int		 compression_level; 	uint32_t	 threads; 	lzma_stream	 stream;@@ -121,7 +121,8 @@ static int	archive_compressor_xz_close(struct archive_write_filter *); static int	archive_compressor_xz_free(struct archive_write_filter *); static int	drive_compressor(struct archive_write_filter *,-		    struct private_data *, int finishing);+		    struct xz *, int finishing);+static void	free_data(struct xz *);  struct option_value { 	uint32_t dict_size;@@ -142,85 +143,72 @@ };  static int-common_setup(struct archive_write_filter *f)+common_setup(struct archive *a, const char *name, int code) {-	struct private_data *data;-	struct archive_write *a = (struct archive_write *)f->archive;-	data = calloc(1, sizeof(*data));-	if (data == NULL) {-		archive_set_error(&a->archive, ENOMEM, "Out of memory");-		return (ARCHIVE_FATAL);-	}-	f->data = data;-	data->compression_level = LZMA_PRESET_DEFAULT;-	data->threads = 1;-	f->open = &archive_compressor_xz_open;+	struct xz *xz;+	struct archive_write_filter *f;++	xz = calloc(1, sizeof(*xz));+	if (xz == NULL)+		goto memerr;+	xz->compression_level = LZMA_PRESET_DEFAULT;+	xz->threads = 1;++	f = __archive_write_allocate_filter(a);+	if (f == NULL)+		goto memerr;+	f->name = name;+	f->code = code;+	f->data = xz;+	f->options = archive_compressor_xz_options;+	f->open = archive_compressor_xz_open;+	f->write = archive_compressor_xz_write; 	f->close = archive_compressor_xz_close; 	f->free = archive_compressor_xz_free;-	f->options = &archive_compressor_xz_options;+ 	return (ARCHIVE_OK);+memerr:+	free_data(xz);+	archive_set_error(a, ENOMEM, "Out of memory");+	return (ARCHIVE_FATAL); }  /*  * Add an xz compression filter to this write handle.  */ int-archive_write_add_filter_xz(struct archive *_a)+archive_write_add_filter_xz(struct archive *a) {-	struct archive_write_filter *f;-	int r;--	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,+	archive_check_magic(a, ARCHIVE_WRITE_MAGIC, 	    ARCHIVE_STATE_NEW, "archive_write_add_filter_xz");-	f = __archive_write_allocate_filter(_a);-	r = common_setup(f);-	if (r == ARCHIVE_OK) {-		f->code = ARCHIVE_FILTER_XZ;-		f->name = "xz";-	}-	return (r);++	return common_setup(a, "xz", ARCHIVE_FILTER_XZ); }  /* LZMA is handled identically, we just need a different compression  * code set.  (The liblzma setup looks at the code to determine  * the one place that XZ and LZMA require different handling.) */ int-archive_write_add_filter_lzma(struct archive *_a)+archive_write_add_filter_lzma(struct archive *a) {-	struct archive_write_filter *f;-	int r;--	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,+	archive_check_magic(a, ARCHIVE_WRITE_MAGIC, 	    ARCHIVE_STATE_NEW, "archive_write_add_filter_lzma");-	f = __archive_write_allocate_filter(_a);-	r = common_setup(f);-	if (r == ARCHIVE_OK) {-		f->code = ARCHIVE_FILTER_LZMA;-		f->name = "lzma";-	}-	return (r);++	return common_setup(a, "lzma", ARCHIVE_FILTER_LZMA); }  int-archive_write_add_filter_lzip(struct archive *_a)+archive_write_add_filter_lzip(struct archive *a) {-	struct archive_write_filter *f;-	int r;--	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,+	archive_check_magic(a, ARCHIVE_WRITE_MAGIC, 	    ARCHIVE_STATE_NEW, "archive_write_add_filter_lzip");-	f = __archive_write_allocate_filter(_a);-	r = common_setup(f);-	if (r == ARCHIVE_OK) {-		f->code = ARCHIVE_FILTER_LZIP;-		f->name = "lzip";-	}-	return (r);++	return common_setup(a, "lzip", ARCHIVE_FILTER_LZIP); }  static int archive_compressor_xz_init_stream(struct archive_write_filter *f,-    struct private_data *data)+    struct xz *xz) { 	static const lzma_stream lzma_stream_init_data = LZMA_STREAM_INIT; 	int ret;@@ -228,27 +216,27 @@ 	lzma_mt mt_options; #endif -	data->stream = lzma_stream_init_data;-	data->stream.next_out = data->compressed;-	data->stream.avail_out = data->compressed_buffer_size;+	xz->stream = lzma_stream_init_data;+	xz->stream.next_out = xz->compressed;+	xz->stream.avail_out = xz->compressed_buffer_size; 	if (f->code == ARCHIVE_FILTER_XZ) { #ifdef HAVE_LZMA_STREAM_ENCODER_MT-		if (data->threads != 1) {+		if (xz->threads != 1) { 			memset(&mt_options, 0, sizeof(mt_options));-			mt_options.threads = data->threads;+			mt_options.threads = xz->threads; 			mt_options.timeout = 300;-			mt_options.filters = data->lzmafilters;+			mt_options.filters = xz->lzmafilters; 			mt_options.check = LZMA_CHECK_CRC64;-			ret = lzma_stream_encoder_mt(&(data->stream),+			ret = lzma_stream_encoder_mt(&(xz->stream), 			    &mt_options); 		} else #endif-			ret = lzma_stream_encoder(&(data->stream),-			    data->lzmafilters, LZMA_CHECK_CRC64);+			ret = lzma_stream_encoder(&(xz->stream),+			    xz->lzmafilters, LZMA_CHECK_CRC64); 	} else if (f->code == ARCHIVE_FILTER_LZMA) {-		ret = lzma_alone_encoder(&(data->stream), &data->lzma_opt);+		ret = lzma_alone_encoder(&(xz->stream), &xz->lzma_opt); 	} else {	/* ARCHIVE_FILTER_LZIP */-		int dict_size = data->lzma_opt.dict_size;+		int dict_size = xz->lzma_opt.dict_size; 		int ds, log2dic, wedges;  		/* Calculate a coded dictionary size */@@ -270,18 +258,18 @@ 			wedges = 0; 		ds = ((wedges << 5) & 0xe0) | (log2dic & 0x1f); -		data->crc32 = 0;+		xz->crc32 = 0; 		/* Make a header */-		data->compressed[0] = 0x4C;-		data->compressed[1] = 0x5A;-		data->compressed[2] = 0x49;-		data->compressed[3] = 0x50;-		data->compressed[4] = 1;/* Version */-		data->compressed[5] = (unsigned char)ds;-		data->stream.next_out += 6;-		data->stream.avail_out -= 6;+		xz->compressed[0] = 0x4C;+		xz->compressed[1] = 0x5A;+		xz->compressed[2] = 0x49;+		xz->compressed[3] = 0x50;+		xz->compressed[4] = 1;/* Version */+		xz->compressed[5] = (unsigned char)ds;+		xz->stream.next_out += 6;+		xz->stream.avail_out -= 6; -		ret = lzma_raw_encoder(&(data->stream), data->lzmafilters);+		ret = lzma_raw_encoder(&(xz->stream), xz->lzmafilters); 	} 	if (ret == LZMA_OK) 		return (ARCHIVE_OK);@@ -307,10 +295,10 @@ static int archive_compressor_xz_open(struct archive_write_filter *f) {-	struct private_data *data = f->data;+	struct xz *xz = f->data; 	int ret; -	if (data->compressed == NULL) {+	if (xz->compressed == NULL) { 		size_t bs = 65536, bpb; 		if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { 			/* Buffer size should be a multiple number of the bytes@@ -321,49 +309,46 @@ 			else if (bpb != 0) 				bs -= bs % bpb; 		}-		data->compressed_buffer_size = bs;-		data->compressed = malloc(data->compressed_buffer_size);-		if (data->compressed == NULL) {+		xz->compressed_buffer_size = bs;+		xz->compressed = malloc(xz->compressed_buffer_size);+		if (xz->compressed == NULL) { 			archive_set_error(f->archive, ENOMEM, 			    "Can't allocate data for compression buffer"); 			return (ARCHIVE_FATAL); 		} 	} -	f->write = archive_compressor_xz_write;- 	/* Initialize compression library. */ 	if (f->code == ARCHIVE_FILTER_LZIP) { 		const struct option_value *val =-		    &option_values[data->compression_level];+		    &option_values[xz->compression_level]; -		data->lzma_opt.dict_size = val->dict_size;-		data->lzma_opt.preset_dict = NULL;-		data->lzma_opt.preset_dict_size = 0;-		data->lzma_opt.lc = LZMA_LC_DEFAULT;-		data->lzma_opt.lp = LZMA_LP_DEFAULT;-		data->lzma_opt.pb = LZMA_PB_DEFAULT;-		data->lzma_opt.mode =-		    data->compression_level<= 2? LZMA_MODE_FAST:LZMA_MODE_NORMAL;-		data->lzma_opt.nice_len = val->nice_len;-		data->lzma_opt.mf = val->mf;-		data->lzma_opt.depth = 0;-		data->lzmafilters[0].id = LZMA_FILTER_LZMA1;-		data->lzmafilters[0].options = &data->lzma_opt;-		data->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */+		xz->lzma_opt.dict_size = val->dict_size;+		xz->lzma_opt.preset_dict = NULL;+		xz->lzma_opt.preset_dict_size = 0;+		xz->lzma_opt.lc = LZMA_LC_DEFAULT;+		xz->lzma_opt.lp = LZMA_LP_DEFAULT;+		xz->lzma_opt.pb = LZMA_PB_DEFAULT;+		xz->lzma_opt.mode =+		    xz->compression_level<= 2? LZMA_MODE_FAST:LZMA_MODE_NORMAL;+		xz->lzma_opt.nice_len = val->nice_len;+		xz->lzma_opt.mf = val->mf;+		xz->lzma_opt.depth = 0;+		xz->lzmafilters[0].id = LZMA_FILTER_LZMA1;+		xz->lzmafilters[0].options = &xz->lzma_opt;+		xz->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */ 	} else {-		if (lzma_lzma_preset(&data->lzma_opt, data->compression_level)) {+		if (lzma_lzma_preset(&xz->lzma_opt, xz->compression_level)) { 			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 			    "Internal error initializing compression library"); 		}-		data->lzmafilters[0].id = LZMA_FILTER_LZMA2;-		data->lzmafilters[0].options = &data->lzma_opt;-		data->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */+		xz->lzmafilters[0].id = LZMA_FILTER_LZMA2;+		xz->lzmafilters[0].options = &xz->lzma_opt;+		xz->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */ 	}-	ret = archive_compressor_xz_init_stream(f, data);+	ret = archive_compressor_xz_init_stream(f, xz); 	if (ret == LZMA_OK) {-		f->data = data;-		return (0);+		return (ARCHIVE_OK); 	} 	return (ARCHIVE_FATAL); }@@ -375,7 +360,7 @@ archive_compressor_xz_options(struct archive_write_filter *f,     const char *key, const char *value) {-	struct private_data *data = (struct private_data *)f->data;+	struct xz *xz = f->data;  	if (strcmp(key, "compression-level") == 0) { 		if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||@@ -384,9 +369,9 @@ 			    "compression-level invalid"); 			return (ARCHIVE_FAILED); 		}-		data->compression_level = value[0] - '0';-		if (data->compression_level > 9)-			data->compression_level = 9;+		xz->compression_level = value[0] - '0';+		if (xz->compression_level > 9)+			xz->compression_level = 9; 		return (ARCHIVE_OK); 	} else if (strcmp(key, "threads") == 0) { 		char *endptr;@@ -400,17 +385,17 @@ 		errno = 0; 		val = strtoul(value, &endptr, 10); 		if (errno != 0 || *endptr != '\0' || val > (unsigned)INT_MAX) {-			data->threads = 1;+			xz->threads = 1; 			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 			    "threads invalid"); 			return (ARCHIVE_FAILED); 		}-		data->threads = (int)val;-		if (data->threads == 0) {+		xz->threads = (int)val;+		if (xz->threads == 0) { #ifdef HAVE_LZMA_STREAM_ENCODER_MT-			data->threads = lzma_cputhreads();+			xz->threads = lzma_cputhreads(); #else-			data->threads = 1;+			xz->threads = 1; #endif 		} 		return (ARCHIVE_OK);@@ -429,18 +414,18 @@ archive_compressor_xz_write(struct archive_write_filter *f,     const void *buff, size_t length) {-	struct private_data *data = (struct private_data *)f->data;+	struct xz *xz = f->data; 	int ret;  	/* Update statistics */-	data->total_in += length;+	xz->total_in += length; 	if (f->code == ARCHIVE_FILTER_LZIP)-		data->crc32 = lzma_crc32(buff, length, data->crc32);+		xz->crc32 = lzma_crc32(buff, length, xz->crc32);  	/* Compress input data to output buffer */-	data->stream.next_in = buff;-	data->stream.avail_in = length;-	if ((ret = drive_compressor(f, data, 0)) != ARCHIVE_OK)+	xz->stream.next_in = buff;+	xz->stream.avail_in = length;+	if ((ret = drive_compressor(f, xz, 0)) != ARCHIVE_OK) 		return (ret);  	return (ARCHIVE_OK);@@ -453,34 +438,32 @@ static int archive_compressor_xz_close(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct xz *xz = f->data; 	int ret; -	ret = drive_compressor(f, data, 1);+	ret = drive_compressor(f, xz, 1); 	if (ret == ARCHIVE_OK) {-		data->total_out +=-		    data->compressed_buffer_size - data->stream.avail_out;+		xz->total_out +=+		    xz->compressed_buffer_size - xz->stream.avail_out; 		ret = __archive_write_filter(f->next_filter,-		    data->compressed,-		    data->compressed_buffer_size - data->stream.avail_out);+		    xz->compressed,+		    xz->compressed_buffer_size - xz->stream.avail_out); 		if (f->code == ARCHIVE_FILTER_LZIP && ret == ARCHIVE_OK) {-			archive_le32enc(data->compressed, data->crc32);-			archive_le64enc(data->compressed+4, data->total_in);-			archive_le64enc(data->compressed+12, data->total_out + 20);+			archive_le32enc(xz->compressed, xz->crc32);+			archive_le64enc(xz->compressed+4, xz->total_in);+			archive_le64enc(xz->compressed+12, xz->total_out + 20); 			ret = __archive_write_filter(f->next_filter,-			    data->compressed, 20);+			    xz->compressed, 20); 		} 	}-	lzma_end(&(data->stream));+	lzma_end(&(xz->stream)); 	return ret; }  static int archive_compressor_xz_free(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;-	free(data->compressed);-	free(data);+	free_data(f->data); 	f->data = NULL; 	return (ARCHIVE_OK); }@@ -494,34 +477,34 @@  */ static int drive_compressor(struct archive_write_filter *f,-    struct private_data *data, int finishing)+    struct xz *xz, int finishing) { 	int ret;  	for (;;) {-		if (data->stream.avail_out == 0) {-			data->total_out += data->compressed_buffer_size;+		if (xz->stream.avail_out == 0) {+			xz->total_out += xz->compressed_buffer_size; 			ret = __archive_write_filter(f->next_filter,-			    data->compressed,-			    data->compressed_buffer_size);+			    xz->compressed,+			    xz->compressed_buffer_size); 			if (ret != ARCHIVE_OK) 				return (ARCHIVE_FATAL);-			data->stream.next_out = data->compressed;-			data->stream.avail_out = data->compressed_buffer_size;+			xz->stream.next_out = xz->compressed;+			xz->stream.avail_out = xz->compressed_buffer_size; 		}  		/* If there's nothing to do, we're done. */-		if (!finishing && data->stream.avail_in == 0)+		if (!finishing && xz->stream.avail_in == 0) 			return (ARCHIVE_OK); -		ret = lzma_code(&(data->stream),+		ret = lzma_code(&(xz->stream), 		    finishing ? LZMA_FINISH : LZMA_RUN );  		switch (ret) { 		case LZMA_OK: 			/* In non-finishing case, check if compressor 			 * consumed everything */-			if (!finishing && data->stream.avail_in == 0)+			if (!finishing && xz->stream.avail_in == 0) 				return (ARCHIVE_OK); 			/* In finishing case, this return always means 			 * there's more work */@@ -537,7 +520,7 @@ 			archive_set_error(f->archive, ENOMEM, 			    "lzma compression error: " 			    "%ju MiB would have been needed",-			    (uintmax_t)((lzma_memusage(&(data->stream))+			    (uintmax_t)((lzma_memusage(&(xz->stream)) 				    + 1024 * 1024 -1) 				/ (1024 * 1024))); 			return (ARCHIVE_FATAL);@@ -549,6 +532,15 @@ 			    ret); 			return (ARCHIVE_FATAL); 		}+	}+}++static void+free_data(struct xz *xz)+{+	if (xz != NULL) {+		free(xz->compressed);+		free(xz); 	} } 
c/archive_write_add_filter_zstd.c view
@@ -55,7 +55,7 @@  /* Don't compile this if we don't have zstd.h */ -struct private_data {+struct zstd { 	int		 compression_level; 	int		 threads; 	int		 long_distance;@@ -103,79 +103,77 @@ static int archive_compressor_zstd_free(struct archive_write_filter *); #if HAVE_ZSTD_H && HAVE_ZSTD_compressStream static int drive_compressor(struct archive_write_filter *,-		    struct private_data *, int, const void *, size_t);+		    struct zstd *, int, const void *, size_t); #endif+static void free_data(struct zstd *);   /*  * Add a zstd compression filter to this write handle.  */ int-archive_write_add_filter_zstd(struct archive *_a)+archive_write_add_filter_zstd(struct archive *a) {-	struct archive_write *a = (struct archive_write *)_a;-	struct archive_write_filter *f = __archive_write_allocate_filter(_a);-	struct private_data *data;-	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,+	struct archive_write_filter *f;+	struct zstd *zstd;+	int r;++	archive_check_magic(a, ARCHIVE_WRITE_MAGIC, 	    ARCHIVE_STATE_NEW, "archive_write_add_filter_zstd"); -	data = calloc(1, sizeof(*data));-	if (data == NULL) {-		archive_set_error(&a->archive, ENOMEM, "Out of memory");-		return (ARCHIVE_FATAL);-	}-	f->data = data;-	f->open = &archive_compressor_zstd_open;-	f->options = &archive_compressor_zstd_options;-	f->flush = &archive_compressor_zstd_flush;-	f->close = &archive_compressor_zstd_close;-	f->free = &archive_compressor_zstd_free;-	f->code = ARCHIVE_FILTER_ZSTD;-	f->name = "zstd";-	data->compression_level = CLEVEL_DEFAULT;-	data->threads = 0;-	data->long_distance = 0;+	zstd = calloc(1, sizeof(*zstd));+	if (zstd == NULL)+		goto memerr;+	zstd->compression_level = CLEVEL_DEFAULT;+	zstd->threads = 0;+	zstd->long_distance = 0; #if HAVE_ZSTD_H && HAVE_ZSTD_compressStream-	data->frame_per_file = 0;-	data->min_frame_in = 0;-	data->max_frame_in = SIZE_MAX;-	data->min_frame_out = 0;-	data->max_frame_out = SIZE_MAX;-	data->cur_frame_in = 0;-	data->cur_frame_out = 0;-	data->cstream = ZSTD_createCStream();-	if (data->cstream == NULL) {-		free(data);-		archive_set_error(&a->archive, ENOMEM,-		    "Failed to allocate zstd compressor object");-		return (ARCHIVE_FATAL);-	}+	zstd->frame_per_file = 0;+	zstd->min_frame_in = 0;+	zstd->max_frame_in = SIZE_MAX;+	zstd->min_frame_out = 0;+	zstd->max_frame_out = SIZE_MAX;+	zstd->cur_frame_in = 0;+	zstd->cur_frame_out = 0;+	zstd->cstream = ZSTD_createCStream();+	if (zstd->cstream == NULL)+		goto memerr; -	return (ARCHIVE_OK);+	r = ARCHIVE_OK; #else-	data->pdata = __archive_write_program_allocate("zstd");-	if (data->pdata == NULL) {-		free(data);-		archive_set_error(&a->archive, ENOMEM, "Out of memory");-		return (ARCHIVE_FATAL);-	}-	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+	zstd->pdata = __archive_write_program_allocate("zstd");+	if (zstd->pdata == NULL)+		goto memerr;++	archive_set_error(a, ARCHIVE_ERRNO_MISC, 	    "Using external zstd program");-	return (ARCHIVE_WARN);+	r = ARCHIVE_WARN; #endif++	f = __archive_write_allocate_filter(a);+	if (f == NULL)+		goto memerr;+	f->name = "zstd";+	f->code = ARCHIVE_FILTER_ZSTD;+	f->data = zstd;+	f->options = archive_compressor_zstd_options;+	f->open = archive_compressor_zstd_open;+	f->write = archive_compressor_zstd_write;+	f->flush = archive_compressor_zstd_flush;+	f->close = archive_compressor_zstd_close;+	f->free = archive_compressor_zstd_free;++	return (r);+memerr:+	free_data(zstd);+	archive_set_error(a, ENOMEM, "Out of memory");+	return (ARCHIVE_FATAL); }  static int archive_compressor_zstd_free(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;-#if HAVE_ZSTD_H && HAVE_ZSTD_compressStream-	ZSTD_freeCStream(data->cstream);-	free(data->out.dst);-#else-	__archive_write_program_free(data->pdata);-#endif-	free(data);+	free_data(f->data); 	f->data = NULL; 	return (ARCHIVE_OK); }@@ -239,7 +237,7 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,     const char *value) {-	struct private_data *data = (struct private_data *)f->data;+	struct zstd *zstd = f->data;  	if (strcmp(key, "compression-level") == 0) { 		intmax_t level;@@ -268,7 +266,7 @@ 			    "compression-level out of range"); 			return (ARCHIVE_FAILED); 		}-		data->compression_level = (int)level;+		zstd->compression_level = (int)level; 		return (ARCHIVE_OK); 	} else if (strcmp(key, "threads") == 0) { 		intmax_t threads;@@ -295,14 +293,14 @@ 			    "threads out of rnage"); 			return (ARCHIVE_FAILED); 		}-		data->threads = (int)threads;+		zstd->threads = (int)threads; 		return (ARCHIVE_OK); #if HAVE_ZSTD_H && HAVE_ZSTD_compressStream 	} else if (strcmp(key, "frame-per-file") == 0) {-		data->frame_per_file = 1;+		zstd->frame_per_file = 1; 		return (ARCHIVE_OK); 	} else if (strcmp(key, "min-frame-in") == 0) {-		if (string_to_size(value, &data->min_frame_in) != ARCHIVE_OK) {+		if (string_to_size(value, &zstd->min_frame_in) != ARCHIVE_OK) { 			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 			    "min-frame-in invalid"); 			return (ARCHIVE_FAILED);@@ -310,7 +308,7 @@ 		return (ARCHIVE_OK); 	} else if (strcmp(key, "min-frame-out") == 0 || 	    strcmp(key, "min-frame-size") == 0) {-		if (string_to_size(value, &data->min_frame_out) != ARCHIVE_OK) {+		if (string_to_size(value, &zstd->min_frame_out) != ARCHIVE_OK) { 			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 			    "min-frame-out invalid"); 			return (ARCHIVE_FAILED);@@ -318,16 +316,16 @@ 		return (ARCHIVE_OK); 	} else if (strcmp(key, "max-frame-in") == 0 || 	    strcmp(key, "max-frame-size") == 0) {-		if (string_to_size(value, &data->max_frame_in) != ARCHIVE_OK ||-		    data->max_frame_in < 1024) {+		if (string_to_size(value, &zstd->max_frame_in) != ARCHIVE_OK ||+		    zstd->max_frame_in < 1024) { 			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 			    "max-frame-size invalid"); 			return (ARCHIVE_FAILED); 		} 		return (ARCHIVE_OK); 	} else if (strcmp(key, "max-frame-out") == 0) {-		if (string_to_size(value, &data->max_frame_out) != ARCHIVE_OK ||-		    data->max_frame_out < 1024) {+		if (string_to_size(value, &zstd->max_frame_out) != ARCHIVE_OK ||+		    zstd->max_frame_out < 1024) { 			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 			    "max-frame-out invalid"); 			return (ARCHIVE_FAILED);@@ -363,7 +361,7 @@ 		if (((int)long_distance) < 10 || (int)long_distance > max_distance) 		    return (ARCHIVE_FAILED); #endif-		data->long_distance = (int)long_distance;+		zstd->long_distance = (int)long_distance; 		return (ARCHIVE_OK); 	} @@ -380,9 +378,9 @@ static int archive_compressor_zstd_open(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct zstd *zstd = f->data; -	if (data->out.dst == NULL) {+	if (zstd->out.dst == NULL) { 		size_t bs = ZSTD_CStreamOutSize(), bpb; 		if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { 			/* Buffer size should be a multiple number of@@ -393,31 +391,29 @@ 			else if (bpb != 0) 				bs -= bs % bpb; 		}-		data->out.size = bs;-		data->out.pos = 0;-		data->out.dst = malloc(data->out.size);-		if (data->out.dst == NULL) {+		zstd->out.size = bs;+		zstd->out.pos = 0;+		zstd->out.dst = malloc(zstd->out.size);+		if (zstd->out.dst == NULL) { 			archive_set_error(f->archive, ENOMEM, 			    "Can't allocate data for compression buffer"); 			return (ARCHIVE_FATAL); 		} 	} -	f->write = archive_compressor_zstd_write;--	if (ZSTD_isError(ZSTD_initCStream(data->cstream,-	    data->compression_level))) {+	if (ZSTD_isError(ZSTD_initCStream(zstd->cstream,+	    zstd->compression_level))) { 		archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 		    "Internal error initializing zstd compressor object"); 		return (ARCHIVE_FATAL); 	} -	ZSTD_CCtx_setParameter(data->cstream, ZSTD_c_nbWorkers, data->threads);+	ZSTD_CCtx_setParameter(zstd->cstream, ZSTD_c_nbWorkers, zstd->threads); -	ZSTD_CCtx_setParameter(data->cstream, ZSTD_c_checksumFlag, 1);+	ZSTD_CCtx_setParameter(zstd->cstream, ZSTD_c_checksumFlag, 1);  #if ZSTD_VERSION_NUMBER >= MINVER_LONG-	ZSTD_CCtx_setParameter(data->cstream, ZSTD_c_windowLog, data->long_distance);+	ZSTD_CCtx_setParameter(zstd->cstream, ZSTD_c_windowLog, zstd->long_distance); #endif  	return (ARCHIVE_OK);@@ -430,9 +426,9 @@ archive_compressor_zstd_write(struct archive_write_filter *f, const void *buff,     size_t length) {-	struct private_data *data = (struct private_data *)f->data;+	struct zstd *zstd = f->data; -	return (drive_compressor(f, data, 0, buff, length));+	return (drive_compressor(f, zstd, 0, buff, length)); }  /*@@ -441,15 +437,15 @@ static int archive_compressor_zstd_flush(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct zstd *zstd = f->data; -	if (data->frame_per_file && data->state == running) {-		if (data->cur_frame_in > data->min_frame_in &&-		    data->cur_frame_out > data->min_frame_out) {-			data->state = finishing;+	if (zstd->frame_per_file && zstd->state == running) {+		if (zstd->cur_frame_in > zstd->min_frame_in &&+		    zstd->cur_frame_out > zstd->min_frame_out) {+			zstd->state = finishing; 		} 	}-	return (drive_compressor(f, data, 1, NULL, 0));+	return (drive_compressor(f, zstd, 1, NULL, 0)); }  /*@@ -458,11 +454,11 @@ static int archive_compressor_zstd_close(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct zstd *zstd = f->data; -	if (data->state == running)-		data->state = finishing;-	return (drive_compressor(f, data, 1, NULL, 0));+	if (zstd->state == running)+		zstd->state = finishing;+	return (drive_compressor(f, zstd, 1, NULL, 0)); }  /*@@ -471,7 +467,7 @@  */ static int drive_compressor(struct archive_write_filter *f,-    struct private_data *data, int flush, const void *src, size_t length)+    struct zstd *zstd, int flush, const void *src, size_t length) { 	ZSTD_inBuffer in = { .src = src, .size = length, .pos = 0 }; 	size_t ipos, opos, zstdret = 0;@@ -479,46 +475,46 @@  	for (;;) { 		ipos = in.pos;-		opos = data->out.pos;-		switch (data->state) {+		opos = zstd->out.pos;+		switch (zstd->state) { 		case running: 			if (in.pos == in.size) 				return (ARCHIVE_OK);-			zstdret = ZSTD_compressStream(data->cstream,-			    &data->out, &in);+			zstdret = ZSTD_compressStream(zstd->cstream,+			    &zstd->out, &in); 			if (ZSTD_isError(zstdret)) 				goto zstd_fatal; 			break; 		case finishing:-			zstdret = ZSTD_endStream(data->cstream, &data->out);+			zstdret = ZSTD_endStream(zstd->cstream, &zstd->out); 			if (ZSTD_isError(zstdret)) 				goto zstd_fatal; 			if (zstdret == 0)-				data->state = resetting;+				zstd->state = resetting; 			break; 		case resetting:-			ZSTD_CCtx_reset(data->cstream, ZSTD_reset_session_only);-			data->cur_frame++;-			data->cur_frame_in = 0;-			data->cur_frame_out = 0;-			data->state = running;+			ZSTD_CCtx_reset(zstd->cstream, ZSTD_reset_session_only);+			zstd->cur_frame++;+			zstd->cur_frame_in = 0;+			zstd->cur_frame_out = 0;+			zstd->state = running; 			break; 		}-		data->cur_frame_in += in.pos - ipos;-		data->cur_frame_out += data->out.pos - opos;-		if (data->state == running) {-			if (data->cur_frame_in >= data->max_frame_in ||-			    data->cur_frame_out >= data->max_frame_out) {-				data->state = finishing;+		zstd->cur_frame_in += in.pos - ipos;+		zstd->cur_frame_out += zstd->out.pos - opos;+		if (zstd->state == running) {+			if (zstd->cur_frame_in >= zstd->max_frame_in ||+			    zstd->cur_frame_out >= zstd->max_frame_out) {+				zstd->state = finishing; 			} 		}-		if (data->out.pos == data->out.size ||-		    (flush && data->out.pos > 0)) {+		if (zstd->out.pos == zstd->out.size ||+		    (flush && zstd->out.pos > 0)) { 			ret = __archive_write_filter(f->next_filter,-			    data->out.dst, data->out.pos);+			    zstd->out.dst, zstd->out.pos); 			if (ret != ARCHIVE_OK) 				goto fatal;-			data->out.pos = 0;+			zstd->out.pos = 0; 		} 	} zstd_fatal:@@ -529,12 +525,22 @@ 	return (ARCHIVE_FATAL); } +static void+free_data(struct zstd *zstd)+{+	if (zstd != NULL) {+		ZSTD_freeCStream(zstd->cstream);+		free(zstd->out.dst);+		free(zstd);+	}+}+ #else /* HAVE_ZSTD_H && HAVE_ZSTD_compressStream */  static int archive_compressor_zstd_open(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct zstd *zstd = f->data; 	struct archive_string as; 	int r; @@ -542,26 +548,25 @@ 	/* --no-check matches library default */ 	archive_strcpy(&as, "zstd --no-check"); -	if (data->compression_level < CLEVEL_STD_MIN) {-		archive_string_sprintf(&as, " --fast=%d", -data->compression_level);+	if (zstd->compression_level < CLEVEL_STD_MIN) {+		archive_string_sprintf(&as, " --fast=%d", -zstd->compression_level); 	} else {-		archive_string_sprintf(&as, " -%d", data->compression_level);+		archive_string_sprintf(&as, " -%d", zstd->compression_level); 	} -	if (data->compression_level > CLEVEL_STD_MAX) {+	if (zstd->compression_level > CLEVEL_STD_MAX) { 		archive_strcat(&as, " --ultra"); 	} -	if (data->threads != 0) {-		archive_string_sprintf(&as, " --threads=%d", data->threads);+	if (zstd->threads != 0) {+		archive_string_sprintf(&as, " --threads=%d", zstd->threads); 	} -	if (data->long_distance != 0) {-		archive_string_sprintf(&as, " --long=%d", data->long_distance);+	if (zstd->long_distance != 0) {+		archive_string_sprintf(&as, " --long=%d", zstd->long_distance); 	} -	f->write = archive_compressor_zstd_write;-	r = __archive_write_program_open(f, data->pdata, as.s);+	r = __archive_write_program_open(f, zstd->pdata, as.s); 	archive_string_free(&as); 	return (r); }@@ -570,9 +575,9 @@ archive_compressor_zstd_write(struct archive_write_filter *f, const void *buff,     size_t length) {-	struct private_data *data = (struct private_data *)f->data;+	struct zstd *zstd = f->data; -	return __archive_write_program_write(f, data->pdata, buff, length);+	return __archive_write_program_write(f, zstd->pdata, buff, length); }  static int@@ -586,9 +591,18 @@ static int archive_compressor_zstd_close(struct archive_write_filter *f) {-	struct private_data *data = (struct private_data *)f->data;+	struct zstd *zstd = f->data; -	return __archive_write_program_close(f, data->pdata);+	return __archive_write_program_close(f, zstd->pdata);+}++static void+free_data(struct zstd *zstd)+{+	if (zstd != NULL) {+		__archive_write_program_free(zstd->pdata);+		free(zstd);+	} }  #endif /* HAVE_ZSTD_H && HAVE_ZSTD_compressStream */
c/archive_write_disk_posix.c view
@@ -300,7 +300,7 @@ 	uint32_t		 compressed_rsrc_position; 	uint32_t		 compressed_rsrc_position_v; 	/* Buffer for uncompressed data. */-	char			*uncompressed_buffer;+	unsigned char		*uncompressed_buffer; 	size_t			 block_remaining_bytes; 	size_t			 file_remaining_bytes; #ifdef HAVE_ZLIB_H@@ -1254,7 +1254,7 @@ hfs_decompress(struct archive_write_disk *a) { 	uint32_t *block_info;-	unsigned int block_count;+	uint32_t block_count; 	uint32_t data_pos, data_size; 	ssize_t r; 	ssize_t bytes_written, bytes_to_write;@@ -1277,10 +1277,10 @@ 			bytes_to_write = data_size -1; 			b = a->compressed_buffer + 1; 		} else {-			uLong dest_len = MAX_DECMPFS_BLOCK_SIZE;+			size_t dest_len = MAX_DECMPFS_BLOCK_SIZE; 			int zr; -			zr = uncompress((Bytef *)a->uncompressed_buffer,+			zr = uncompress(a->uncompressed_buffer, 			    &dest_len, a->compressed_buffer, data_size); 			if (zr != Z_OK) { 				archive_set_error(&a->archive,@@ -1289,7 +1289,7 @@ 				return (ARCHIVE_WARN); 			} 			bytes_to_write = dest_len;-			b = (unsigned char *)a->uncompressed_buffer;+			b = a->uncompressed_buffer; 		} 		do { 			bytes_written = write(a->fd, b, bytes_to_write);@@ -1472,8 +1472,7 @@  	if (a->decmpfs_block_count == (unsigned)-1) { 		void *new_block;-		size_t new_size;-		unsigned int block_count;+		size_t block_count, new_size;  		if (a->decmpfs_header_p == NULL) { 			new_block = malloc(MAX_DECMPFS_XATTR_SIZE@@ -1493,13 +1492,20 @@ 		archive_le64enc(&a->decmpfs_header_p[DECMPFS_UNCOMPRESSED_SIZE], 		    a->filesize); -		/* Calculate a block count of the file. */-		block_count =-		    (a->filesize + MAX_DECMPFS_BLOCK_SIZE -1) /-			MAX_DECMPFS_BLOCK_SIZE; 		/*+		 * Calculate block count for the file.+		 */+		block_count = (a->filesize + MAX_DECMPFS_BLOCK_SIZE - 1) /+		    MAX_DECMPFS_BLOCK_SIZE;+		if (block_count > (SIZE_MAX - RSRC_H_SIZE - 4 - RSRC_F_SIZE) /+		    (sizeof(uint32_t) * 2) || block_count > UINT32_MAX) {+			archive_set_error(&a->archive, EFBIG, "File too big");+			return (ARCHIVE_FATAL);+		}++		/* 		 * Allocate buffer for resource fork.-		 * Set up related pointers;+		 * Set up related pointers. 		 */ 		new_size = 		    RSRC_H_SIZE + /* header */@@ -1540,7 +1546,7 @@ 		a->decmpfs_block_info = 		    (uint32_t *)(a->resource_fork + RSRC_H_SIZE); 		/* Set the block count to the resource fork. */-		archive_le32enc(a->decmpfs_block_info++, block_count);+		archive_le32enc(a->decmpfs_block_info++, (uint32_t)block_count); 		/* Get the position where we are going to set compressed 		 * data. */ 		a->compressed_rsrc_position =@@ -2369,7 +2375,7 @@ #endif 			if (r != 0) 				r = errno;-			else if ((st.st_mode & AE_IFMT) == AE_IFREG) {+			else if (S_ISREG(st.st_mode)) { 				a->fd = open(a->name, O_WRONLY | O_TRUNC | 				    O_BINARY | O_CLOEXEC | O_NOFOLLOW); 				__archive_ensure_cloexec_flag(a->fd);@@ -4344,7 +4350,7 @@ 		 * with at least a writing mode(O_RDWR or O_WRONLY). it 		 * makes the data fork uncompressed. 		 */-		dffd = open(datafork, 0);+		dffd = open(datafork, O_SYMLINK); 		if (dffd == -1) { 			archive_set_error(&a->archive, errno, 			    "Failed to open the data fork for metadata");@@ -4446,14 +4452,16 @@ 	 */ 	archive_strncpy(&datafork, pathname, p - pathname); 	archive_strcat(&datafork, p + 2);-	if ( #ifdef HAVE_LSTAT-		lstat(datafork.s, &st) == -1 ||+	if (lstat(datafork.s, &st) == -1)+		goto skip_appledouble; #else-		la_stat(datafork.s, &st) == -1 ||+	if (la_stat(datafork.s, &st) == -1)+		goto skip_appledouble; #endif-	    (((st.st_mode & AE_IFMT) != AE_IFREG) &&-		((st.st_mode & AE_IFMT) != AE_IFDIR)))+	if (!S_ISREG(st.st_mode) &&+	    !S_ISDIR(st.st_mode) &&+	    !S_ISLNK(st.st_mode)) 		goto skip_appledouble;  	/*
c/archive_write_disk_set_standard_lookup.c view
@@ -45,6 +45,7 @@ #endif  #include "archive.h"+#include "archive_integer.h" #include "archive_private.h" #include "archive_read_private.h" #include "archive_write_disk_private.h"@@ -134,7 +135,8 @@ 				break; 			if (r != ERANGE) 				break;-			bufsize *= 2;+			if (archive_ckd_mul_size(&bufsize, bufsize, 2))+				break; 			free(allocated); 			allocated = malloc(bufsize); 			if (allocated == NULL)@@ -203,7 +205,8 @@ 				break; 			if (r != ERANGE) 				break;-			bufsize *= 2;+			if (archive_ckd_mul_size(&bufsize, bufsize, 2))+				break; 			free(allocated); 			allocated = malloc(bufsize); 			if (allocated == NULL)
c/archive_write_disk_windows.c view
@@ -194,6 +194,8 @@  static int	disk_unlink(const wchar_t *); static int	disk_rmdir(const wchar_t *);+static int	check_symlinks_by_path(struct archive_write_disk *,+		    wchar_t *, size_t *, int); static int	check_symlinks(struct archive_write_disk *); static int	create_filesystem_object(struct archive_write_disk *); static struct fixup_entry *current_fixup(struct archive_write_disk *,@@ -244,8 +246,8 @@     ((((int64_t)(bhfi)->nFileSizeHigh) << 32) | (bhfi)->nFileSizeLow)  static int-file_information(struct archive_write_disk *a, wchar_t *path,-    BY_HANDLE_FILE_INFORMATION *st, mode_t *mode, int sim_lstat)+file_information(wchar_t *path, BY_HANDLE_FILE_INFORMATION *st,+    mode_t *mode, int sim_lstat) { 	HANDLE h; 	int r;@@ -282,10 +284,10 @@ 	ZeroMemory(&createExParams, sizeof(createExParams)); 	createExParams.dwSize = sizeof(createExParams); 	createExParams.dwFileFlags = flag;-	h = CreateFile2(a->name, 0, 0,+	h = CreateFile2(path, 0, 0, 		OPEN_EXISTING, &createExParams); #else-	h = CreateFileW(a->name, 0, 0, NULL,+	h = CreateFileW(path, 0, 0, NULL, 	    OPEN_EXISTING, flag, NULL); #endif 	if (h == INVALID_HANDLE_VALUE &&@@ -629,6 +631,7 @@ 	DWORD attrs = 0; 	DWORD flags = 0; 	DWORD newflags = 0;+	DWORD lasterr = 0;  	len = wcslen(target); 	if (len == 0) {@@ -693,10 +696,14 @@ 	ret = CreateSymbolicLinkW(linkname, ttarget, newflags); 	/* 	 * Prior to Windows 10 calling CreateSymbolicLinkW() will fail-	 * if SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE is set+	 * if SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE is set; however,+	 * trying this fallback if we fail due to a bad path will replace+	 * ENOENT with EPERM and confuse later error recovery efforts. 	 */ 	if (!ret) {-		ret = CreateSymbolicLinkW(linkname, ttarget, flags);+		lasterr = GetLastError();+		if (lasterr != ERROR_PATH_NOT_FOUND)+			ret = CreateSymbolicLinkW(linkname, ttarget, flags); 	} 	free(ttarget); #endif@@ -741,7 +748,7 @@ 	 * XXX At this point, symlinks should not be hit, otherwise 	 * XXX a race occurred.  Do we want to check explicitly for that? 	 */-	if (file_information(a, a->name, &a->st, NULL, 1) == 0) {+	if (file_information(a->name, &a->st, NULL, 1) == 0) { 		a->pst = &a->st; 		return (ARCHIVE_OK); 	}@@ -1516,7 +1523,7 @@ 		 * such symlinks. We always need both source and target 		 * information. 		 */-		r = file_information(a, a->name, &lst, &lst_mode, 1);+		r = file_information(a->name, &lst, &lst_mode, 1); 		if (r != 0) { 			archive_set_error(&a->archive, errno, 			    "Can't stat existing object");@@ -1525,7 +1532,7 @@ 			if (lst.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 				dirlnk = 1; 			/* In case of a symlink we need target information */-			r = file_information(a, a->name, &a->st, &st_mode, 0);+			r = file_information(a->name, &a->st, &st_mode, 0); 			if (r != 0) { 				a->st = lst; 				st_mode = lst_mode;@@ -1653,6 +1660,7 @@ 	mode_t final_mode, mode; 	int r; 	DWORD attrs = 0;+	DWORD file_flags = 0; # if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ 		CREATEFILE2_EXTENDED_PARAMETERS createExParams; #endif@@ -1675,6 +1683,22 @@ 			free(linksanitized); 			return (r); 		}++		if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) {+			r = check_symlinks_by_path(a, linksanitized, NULL, 1);+			if (r != ARCHIVE_OK) {+				/*+				 * Prevent extracting a hardlink to a symlink.+				 * libarchive supports the POSIX feature of+				 * hardlinks with data payloads, which would+				 * provide a way to write through an otherwise+				 * disallowed symlink.+				 */+				free(linksanitized);+				return (r);+			}+		}+ 		linkfull = __la_win_permissive_name_w(linksanitized); 		free(linksanitized); 		namefull = __la_win_permissive_name_w(a->name);@@ -1752,6 +1776,13 @@ 			else 				disk_unlink(a->name); 		}++		/*+		 * Since the symlink-safe path cache is just an optimization, and we+		 * are about to create a new symlink, invalidating the cache prevents+		 * incidentally writing through the entry we are about to create.+		 */+		a->path_safe.s[0] = 0; #if HAVE_SYMLINK 		return symlink(linkname, a->name) ? errno : 0; #else@@ -1790,16 +1821,31 @@ 	case AE_IFREG: 		a->tmpname = NULL; 		fullname = a->name;+		if ((a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) == 0) {+			/*+			 * Creating a regular file is expected to fail with EEXIST if *any+			 * object* exists at the target location.+			 * SECURE_SYMLINKS deletes any symbolic link that would have been+			 * written through. When it's off, though, we risk writing through+			 * extant but broken symlinks unless we allow CreateFile to fail+			 * on the link rather than creating its target.+			 *+			 * This is effectively O_EXCL.+			 */+			file_flags |= FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS;+		}+ 		/* O_WRONLY | O_CREAT | O_EXCL */ # if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ 		ZeroMemory(&createExParams, sizeof(createExParams)); 		createExParams.dwSize = sizeof(createExParams); 		createExParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;+		createExParams.dwFileFlags = file_flags; 		a->fh = CreateFile2(fullname, GENERIC_WRITE, 0, 		    CREATE_NEW, &createExParams); #else 		a->fh = CreateFileW(fullname, GENERIC_WRITE, 0, NULL,-		    CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);+		    CREATE_NEW, FILE_ATTRIBUTE_NORMAL | file_flags, NULL); #endif 		if (a->fh == INVALID_HANDLE_VALUE && 		    GetLastError() == ERROR_INVALID_NAME &&@@ -1810,7 +1856,7 @@ 			    CREATE_NEW, &createExParams); #else 			a->fh = CreateFileW(fullname, GENERIC_WRITE, 0, NULL,-			    CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);+			    CREATE_NEW, FILE_ATTRIBUTE_NORMAL | file_flags, NULL); #endif 		} 		if (a->fh == INVALID_HANDLE_VALUE) {@@ -2075,9 +2121,10 @@  * recent paths.  */ static int-check_symlinks(struct archive_write_disk *a)+check_symlinks_by_path(struct archive_write_disk *a,+    wchar_t *path, size_t *safe_len, int checking_linkname) {-	wchar_t *pn, *p;+	wchar_t *pn, *p, *su; 	wchar_t c; 	int r; 	BY_HANDLE_FILE_INFORMATION st;@@ -2088,13 +2135,17 @@ 	 * destination would be altered by a symlink. 	 */ 	/* Whatever we checked last time doesn't need to be re-checked. */-	pn = a->name;+	pn = path; 	p = a->path_safe.s; 	while ((*pn != '\0') && (*p == *pn)) 		++p, ++pn; 	/* Skip leading backslashes */ 	while (*pn == '\\') 		++pn;+	su = pn;+	/* The end-of-safe region, however, should not cover a partial leaf name */+	while (su > path && *su != '\\')+		--su; 	c = pn[0]; 	/* Keep going until we've checked the entire name. */ 	while (pn[0] != '\0' && (pn[0] != '\\' || pn[1] != '\0')) {@@ -2104,13 +2155,20 @@ 		c = pn[0]; 		pn[0] = '\0'; 		/* Check that we haven't hit a symlink. */-		r = file_information(a, a->name, &st, &st_mode, 1);+		r = file_information(path, &st, &st_mode, 1); 		if (r != 0) { 			/* We've hit a dir that doesn't exist; stop now. */ 			if (errno == ENOENT) 				break; 		} else if (S_ISLNK(st_mode)) { 			if (c == '\0') {+				if (checking_linkname) {+					archive_set_error(&a->archive, ELOOP,+					    "Cannot write hardlink to symlink %ls",+					    path);+					pn[0] = c;+					return (ARCHIVE_FAILED);+				} 				/* 				 * Last element is a file or directory symlink. 				 * Remove it so we can overwrite it with the@@ -2122,14 +2180,14 @@ 				} 				if (st.dwFileAttributes & 				    FILE_ATTRIBUTE_DIRECTORY) {-					r = disk_rmdir(a->name);+					r = disk_rmdir(path); 				} else {-					r = disk_unlink(a->name);+					r = disk_unlink(path); 				} 				if (r) { 					archive_set_error(&a->archive, errno, 					    "Could not remove symlink %ls",-					    a->name);+					    path); 					pn[0] = c; 					return (ARCHIVE_FAILED); 				}@@ -2143,11 +2201,16 @@ 				if (!S_ISLNK(a->mode)) { 					archive_set_error(&a->archive, -1, 					    "Removing symlink %ls",-					    a->name);+					    path);+					/*+					 * We can safely return the entire path as a safe range,+					 * having deleted the symlink at the leaf with no intent+					 * to create another symlink.+					 */+					su = pn; 				} 				/* Symlink gone.  No more problem! */-				pn[0] = c;-				return (0);+				break; 			} else if (a->flags & ARCHIVE_EXTRACT_UNLINK) { 				/* User asked us to remove problems. */ 				if (a->flags &@@ -2156,14 +2219,14 @@ 				} 				if (st.dwFileAttributes & 				    FILE_ATTRIBUTE_DIRECTORY) {-					r = disk_rmdir(a->name);+					r = disk_rmdir(path); 				} else {-					r = disk_unlink(a->name);+					r = disk_unlink(path); 				} 				if (r != 0) { 					archive_set_error(&a->archive, EIO, 					    "Cannot remove intervening "-					    "symlink %ls", a->name);+					    "symlink %ls", path); 					pn[0] = c; 					return (ARCHIVE_FAILED); 				}@@ -2171,23 +2234,48 @@ 			} else { 				archive_set_error(&a->archive, ELOOP, 				    "Cannot extract through symlink %ls",-				    a->name);+				    path); 				pn[0] = c; 				return (ARCHIVE_FAILED); 			} 		}+		su = pn; 		if (!c) 			break; 		pn[0] = c; 		pn++; 	} 	pn[0] = c;-	/* We've checked and/or cleaned the whole path, so remember it. */-	archive_wstrcpy(&a->path_safe, a->name);+	if (safe_len)+		*safe_len = su - path; 	return (ARCHIVE_OK); }  static int+check_symlinks(struct archive_write_disk *a)+{+	int r;+	size_t safe_len;+	r = check_symlinks_by_path(a, a->name, &safe_len, 0);++	if (r == ARCHIVE_OK) {+		/*+		 * We've checked and/or cleaned the whole path, so remember the+		 * portion check_symlinks_by_path returned as "safe" (typically+		 * the parent of the entry we are about to create, unless that+		 * entry was just unlinked.)+		 *+		 * We only cache path safety info for entry paths (which we+		 * operate on in a->name). We do not cache safety info for+		 * any other paths.+		 */+		archive_wstrncpy(&a->path_safe, a->name, safe_len);+	}++	return (r);+}++static int guidword(wchar_t *p, int n) { 	int i;@@ -2456,7 +2544,7 @@ 	 * here loses the ability to extract through symlinks.  Also note 	 * that this should not use the a->st cache. 	 */-	if (file_information(a, path, &st, &st_mode, 0) == 0) {+	if (file_information(path, &st, &st_mode, 0) == 0) { 		if (S_ISDIR(st_mode)) 			return (ARCHIVE_OK); 		if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {@@ -2523,7 +2611,7 @@ 	 * don't add it to the fixup list here, as it's already been 	 * added. 	 */-	if (file_information(a, path, &st, &st_mode, 0) == 0 &&+	if (file_information(path, &st, &st_mode, 0) == 0 && 	    S_ISDIR(st_mode)) 		return (ARCHIVE_OK); 
c/archive_write_private.h view
@@ -69,7 +69,7 @@ struct archive_write_filter *__archive_write_allocate_filter(struct archive *);  int __archive_write_output(struct archive_write *, const void *, size_t);-int __archive_write_nulls(struct archive_write *, size_t);+int __archive_write_nulls(struct archive_write *, uint64_t); int __archive_write_filter(struct archive_write_filter *, const void *, size_t);  struct archive_write {@@ -131,6 +131,8 @@ 	archive_passphrase_callback *passphrase_callback; 	void		*passphrase_client_data; };++int	__archive_write_unregister_format(struct archive_write *);  /*  * Utility function to format a USTAR header into a buffer.  If
c/archive_write_set_format_7zip.c view
@@ -215,8 +215,6 @@ 	size_t			 total_number_dir_entry; 	size_t			 total_bytes_entry_name; 	size_t			 total_number_time_defined[3];-	uint64_t		 total_bytes_compressed;-	uint64_t		 total_bytes_uncompressed; 	uint64_t		 entry_bytes_remaining; 	uint32_t		 entry_crc32; 	uint32_t		 precode_crc32;@@ -358,8 +356,7 @@ 	    ARCHIVE_STATE_NEW, "archive_write_set_format_7zip");  	/* If another format was already registered, unregister it. */-	if (a->format_free != NULL)-		(a->format_free)(a);+	(void)__archive_write_unregister_format(a);  	zip = calloc(1, sizeof(*zip)); 	if (zip == NULL) {@@ -415,9 +412,7 @@ static int _7z_options(struct archive_write *a, const char *key, const char *value) {-	struct _7zip *zip;--	zip = (struct _7zip *)a->format_data;+	struct _7zip *zip = a->format_data;  	if (strcmp(key, "compression") == 0) { 		const char *name = NULL;@@ -559,11 +554,10 @@ static int _7z_write_header(struct archive_write *a, struct archive_entry *entry) {-	struct _7zip *zip;+	struct _7zip *zip = a->format_data; 	struct file *file; 	int r; -	zip = (struct _7zip *)a->format_data; 	zip->cur_file = NULL; 	zip->entry_bytes_remaining = 0; @@ -667,12 +661,10 @@ static int write_to_temp(struct archive_write *a, const void *buff, size_t s) {-	struct _7zip *zip;+	struct _7zip *zip = a->format_data; 	const unsigned char *p; 	ssize_t ws; -	zip = (struct _7zip *)a->format_data;- 	/* 	 * Open a temporary file. 	 */@@ -705,7 +697,7 @@ compress_out(struct archive_write *a, const void *buff, size_t s,     enum la_zaction run) {-	struct _7zip *zip = (struct _7zip *)a->format_data;+	struct _7zip *zip = a->format_data; 	int r;  	if (run == ARCHIVE_Z_FINISH && zip->stream.total_in == 0 && s == 0)@@ -751,11 +743,9 @@ static ssize_t _7z_write_data(struct archive_write *a, const void *buff, size_t s) {-	struct _7zip *zip;+	struct _7zip *zip = a->format_data; 	ssize_t bytes; -	zip = (struct _7zip *)a->format_data;- 	if (s > zip->entry_bytes_remaining) 		s = (size_t)zip->entry_bytes_remaining; 	if (s == 0 || zip->cur_file == NULL)@@ -771,11 +761,10 @@ static int _7z_finish_entry(struct archive_write *a) {-	struct _7zip *zip;+	struct _7zip *zip = a->format_data; 	size_t s; 	ssize_t r; -	zip = (struct _7zip *)a->format_data; 	if (zip->cur_file == NULL) 		return (ARCHIVE_OK); @@ -787,8 +776,6 @@ 		if (r < 0) 			return ((int)r); 	}-	zip->total_bytes_compressed += zip->stream.total_in;-	zip->total_bytes_uncompressed += zip->stream.total_out; 	zip->cur_file->crc32 = zip->entry_crc32; 	zip->cur_file = NULL; @@ -798,11 +785,10 @@ static int flush_wbuff(struct archive_write *a) {-	struct _7zip *zip;+	struct _7zip *zip = a->format_data; 	int r; 	size_t s; -	zip = (struct _7zip *)a->format_data; 	s = sizeof(zip->wbuff) - zip->wbuff_remaining; 	r = __archive_write_output(a, zip->wbuff, s); 	if (r != ARCHIVE_OK)@@ -814,10 +800,9 @@ static int copy_out(struct archive_write *a, uint64_t offset, uint64_t length) {-	struct _7zip *zip;+	struct _7zip *zip = a->format_data; 	int r; -	zip = (struct _7zip *)a->format_data; 	if (zip->temp_offset > 0 && 	    lseek(zip->temp_fd, offset, SEEK_SET) < 0) { 		archive_set_error(&(a->archive), errno, "lseek failed");@@ -860,15 +845,13 @@ static int _7z_close(struct archive_write *a) {-	struct _7zip *zip;+	struct _7zip *zip = a->format_data; 	unsigned char *wb; 	uint64_t header_offset, header_size, header_unpacksize; 	uint64_t length; 	uint32_t header_crc32; 	int r; -	zip = (struct _7zip *)a->format_data;- 	if (zip->total_number_entry > 0) { 		struct archive_rb_node *n; 		uint64_t data_offset, data_size, data_unpacksize;@@ -1033,7 +1016,7 @@ static int make_substreamsInfo(struct archive_write *a, struct coder *coders) {-	struct _7zip *zip = (struct _7zip *)a->format_data;+	struct _7zip *zip = a->format_data; 	struct file *file; 	int r; @@ -1109,7 +1092,7 @@     uint64_t unpack_size, int num_coder, struct coder *coders, int substrm,     uint32_t header_crc) {-	struct _7zip *zip = (struct _7zip *)a->format_data;+	struct _7zip *zip = a->format_data; 	uint8_t codec_buff[8]; 	int numFolders, fi; 	int codec_size;@@ -1301,8 +1284,8 @@ static int make_time(struct archive_write *a, uint8_t type, unsigned flg, int ti) {+	struct _7zip *zip = a->format_data; 	uint8_t filetime[8];-	struct _7zip *zip = (struct _7zip *)a->format_data; 	struct file *file; 	int r; 	uint8_t b, mask;@@ -1390,7 +1373,7 @@ make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size,     uint64_t unpack_size, int codernum, struct coder *coders) {-	struct _7zip *zip = (struct _7zip *)a->format_data;+	struct _7zip *zip = a->format_data; 	struct file *file; 	int r; 	uint8_t b, mask;@@ -1598,7 +1581,7 @@ static int _7z_free(struct archive_write *a) {-	struct _7zip *zip = (struct _7zip *)a->format_data;+	struct _7zip *zip = a->format_data;  	/* Close the temporary file. */ 	if (zip->temp_fd >= 0)@@ -1636,13 +1619,12 @@ file_new(struct archive_write *a, struct archive_entry *entry,     struct file **newfile) {-	struct _7zip *zip;+	struct _7zip *zip = a->format_data; 	struct file *file; 	const char *u16; 	size_t u16len; 	int ret = ARCHIVE_OK; -	zip = (struct _7zip *)a->format_data; 	*newfile = NULL;  	file = calloc(1, sizeof(*file));@@ -2260,7 +2242,7 @@ ppmd_write(void *p, Byte b) { 	struct archive_write *a = ((IByteOut *)p)->a;-	struct _7zip *zip = (struct _7zip *)(a->format_data);+	struct _7zip *zip = a->format_data; 	struct la_zstream *lastrm = &(zip->stream); 	struct ppmd_stream *strm; @@ -2517,10 +2499,9 @@ _7z_compression_init_encoder(struct archive_write *a, unsigned compression,     int compression_level) {-	struct _7zip *zip;+	struct _7zip *zip = a->format_data; 	int r; -	zip = (struct _7zip *)a->format_data; 	switch (compression) { 	case _7Z_DEFLATE: 		r = compression_init_encoder_deflate(
c/archive_write_set_format_ar.c view
@@ -40,10 +40,11 @@ #include "archive.h" #include "archive_entry.h" #include "archive_private.h"+#include "archive_string.h" #include "archive_write_private.h" #include "archive_write_set_format_private.h" -struct ar_w {+struct ar { 	uint64_t	 entry_bytes_remaining; 	uint64_t	 entry_padding; 	int		 is_strtab;@@ -78,7 +79,6 @@ static int		 archive_write_ar_free(struct archive_write *); static int		 archive_write_ar_close(struct archive_write *); static int		 archive_write_ar_finish_entry(struct archive_write *);-static const char	*ar_basename(const char *path); static int		 format_octal(int64_t v, char *p, int s); static int		 format_decimal(int64_t v, char *p, int s); @@ -120,11 +120,10 @@ static int archive_write_set_format_ar(struct archive_write *a) {-	struct ar_w *ar;+	struct ar *ar;  	/* If someone else was already registered, unregister them. */-	if (a->format_free != NULL)-		(a->format_free)(a);+	(void)__archive_write_unregister_format(a);  	ar = calloc(1, sizeof(*ar)); 	if (ar == NULL) {@@ -147,16 +146,18 @@ { 	int ret, append_fn; 	char buff[60];-	char *ss, *se;-	struct ar_w *ar;+	char *ss;+	struct ar *ar = a->format_data;+	struct archive_string se; 	const char *pathname; 	const char *filename;+	size_t filename_length; 	int64_t size;  	append_fn = 0;-	ar = (struct ar_w *)a->format_data; 	ar->is_strtab = 0; 	filename = NULL;+	filename_length = 0; 	size = archive_entry_size(entry);  @@ -215,12 +216,17 @@ 	 * Otherwise, entry is a normal archive member. 	 * Strip leading paths from filenames, if any. 	 */-	if ((filename = ar_basename(pathname)) == NULL) {+	filename = strrchr(pathname, '/');+	if (filename == NULL)+		filename = pathname;+	else if (filename[1] == '\0') { 		/* Reject filenames with trailing "/" */ 		archive_set_error(&a->archive, EINVAL, 		    "Invalid filename"); 		return (ARCHIVE_WARN);-	}+	} else+		filename++;+	filename_length = strlen(filename);  	if (a->archive.archive_format == ARCHIVE_FORMAT_AR_GNU) { 		/*@@ -229,10 +235,10 @@ 		 * So, the longest filename here (without extension) is 		 * actually 15 bytes. 		 */-		if (strlen(filename) <= 15) {+		if (filename_length <= 15) { 			memcpy(&buff[AR_name_offset],-			    filename, strlen(filename));-			buff[AR_name_offset + strlen(filename)] = '/';+			    filename, filename_length);+			buff[AR_name_offset + filename_length] = '/'; 		} else { 			/* 			 * For filename longer than 15 bytes, GNU variant@@ -246,18 +252,10 @@ 				return (ARCHIVE_WARN); 			} -			se = malloc(strlen(filename) + 3);-			if (se == NULL) {-				archive_set_error(&a->archive, ENOMEM,-				    "Can't allocate filename buffer");-				return (ARCHIVE_FATAL);-			}--			memcpy(se, filename, strlen(filename));-			strcpy(se + strlen(filename), "/\n");--			ss = strstr(ar->strtab, se);-			free(se);+			archive_string_init(&se);+			archive_string_sprintf(&se, "%s/\n", filename);+			ss = strstr(ar->strtab, se.s);+			archive_string_free(&se);  			if (ss == NULL) { 				archive_set_error(&a->archive, EINVAL,@@ -289,13 +287,13 @@ 		 * The name is then written immediately following the 		 * archive header. 		 */-		if (strlen(filename) <= 16 && strchr(filename, ' ') == NULL) {-			memcpy(&buff[AR_name_offset], filename, strlen(filename));-			buff[AR_name_offset + strlen(filename)] = ' ';+		if (filename_length <= 16 && strchr(filename, ' ') == NULL) {+			memcpy(&buff[AR_name_offset], filename, filename_length);+			buff[AR_name_offset + filename_length] = ' '; 		} 		else { 			memcpy(buff + AR_name_offset, "#1/", 3);-			if (format_decimal(strlen(filename),+			if (format_decimal(filename_length, 			    buff + AR_name_offset + 3, 			    AR_name_size - 3)) { 				archive_set_error(&a->archive, ERANGE,@@ -303,7 +301,7 @@ 				return (ARCHIVE_WARN); 			} 			append_fn = 1;-			size += strlen(filename);+			size += filename_length; 		} 	} @@ -353,10 +351,10 @@ 	ar->entry_padding = ar->entry_bytes_remaining % 2;  	if (append_fn > 0) {-		ret = __archive_write_output(a, filename, strlen(filename));+		ret = __archive_write_output(a, filename, filename_length); 		if (ret != ARCHIVE_OK) 			return (ret);-		ar->entry_bytes_remaining -= strlen(filename);+		ar->entry_bytes_remaining -= filename_length; 	}  	return (ARCHIVE_OK);@@ -365,10 +363,9 @@ static ssize_t archive_write_ar_data(struct archive_write *a, const void *buff, size_t s) {-	struct ar_w *ar;+	struct ar *ar = a->format_data; 	int ret; -	ar = (struct ar_w *)a->format_data; 	if (s > ar->entry_bytes_remaining) 		s = (size_t)ar->entry_bytes_remaining; @@ -401,9 +398,7 @@ static int archive_write_ar_free(struct archive_write *a) {-	struct ar_w *ar;--	ar = (struct ar_w *)a->format_data;+	struct ar *ar = a->format_data;  	if (ar == NULL) 		return (ARCHIVE_OK);@@ -421,14 +416,13 @@ static int archive_write_ar_close(struct archive_write *a) {-	struct ar_w *ar;+	struct ar *ar = a->format_data; 	int ret;  	/* 	 * If we haven't written anything yet, we need to write 	 * the ar global header now to make it a valid ar archive. 	 */-	ar = (struct ar_w *)a->format_data; 	if (!ar->wrote_global_header) { 		ar->wrote_global_header = 1; 		ret = __archive_write_output(a, "!<arch>\n", 8);@@ -441,11 +435,9 @@ static int archive_write_ar_finish_entry(struct archive_write *a) {-	struct ar_w *ar;+	struct ar *ar = a->format_data; 	int ret; -	ar = (struct ar_w *)a->format_data;- 	if (ar->entry_bytes_remaining != 0) { 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 		    "Entry remaining bytes larger than 0");@@ -545,25 +537,4 @@ 		*p++ = '9';  	return (-1);-}--static const char *-ar_basename(const char *path)-{-	const char *endp, *startp;--	endp = path + strlen(path) - 1;-	/*-	 * For filename with trailing slash(es), we return-	 * NULL indicating an error.-	 */-	if (*endp == '/')-		return (NULL);--	/* Find the start of the base */-	startp = endp;-	while (startp > path && *(startp - 1) != '/')-		startp--;-	-	return (startp); }
c/archive_write_set_format_cpio_binary.c view
@@ -40,6 +40,7 @@ #include "archive.h" #include "archive_entry.h" #include "archive_entry_locale.h"+#include "archive_integer.h" #include "archive_private.h" #include "archive_write_private.h" #include "archive_write_set_format_private.h"@@ -182,8 +183,7 @@ 	    ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_binary");  	/* If someone else was already registered, unregister them. */-	if (a->format_free != NULL)-		(a->format_free)(a);+	(void)__archive_write_unregister_format(a);  	cpio = calloc(1, sizeof(*cpio)); 	if (cpio == NULL) {@@ -235,7 +235,7 @@ archive_write_binary_options(struct archive_write *a, const char *key,     const char *val) {-	struct cpio *cpio = (struct cpio *)a->format_data;+	struct cpio *cpio = a->format_data; 	int ret = ARCHIVE_FAILED;  	if (strcmp(key, "hdrcharset")  == 0) {@@ -307,10 +307,16 @@  	/* Ensure space for the new mapping. */ 	if (cpio->ino_list_size <= cpio->ino_list_next) {-		size_t newsize = cpio->ino_list_size < 512-		    ? 512 : cpio->ino_list_size * 2;-		void *newlist = realloc(cpio->ino_list,-		    sizeof(cpio->ino_list[0]) * newsize);+		size_t newsize, size;+		if (cpio->ino_list_size < 512)+			newsize = 512;+		else if (archive_ckd_mul_size(&newsize,+		    cpio->ino_list_size, 2))+			return (-1);+		if (archive_ckd_mul_size(&size,+		    newsize, sizeof(cpio->ino_list[0])))+			return (-1);+		void *newlist = realloc(cpio->ino_list, size); 		if (newlist == NULL) 			return (-1); @@ -329,10 +335,9 @@ static struct archive_string_conv * get_sconv(struct archive_write *a) {-	struct cpio *cpio;+	struct cpio *cpio = a->format_data; 	struct archive_string_conv *sconv; -	cpio = (struct cpio *)a->format_data; 	sconv = cpio->opt_sconv; 	if (sconv == NULL) { 		if (!cpio->init_default_conversion) {@@ -378,7 +383,7 @@ static int write_header(struct archive_write *a, struct archive_entry *entry) {-	struct cpio *cpio;+	struct cpio *cpio = a->format_data; 	const char *p, *path; 	int ret, ret_final; 	int64_t	ino;@@ -387,7 +392,6 @@ 	struct archive_entry *entry_main; 	size_t len, pathlength; -	cpio = (struct cpio *)a->format_data; 	ret_final = ARCHIVE_OK; 	sconv = get_sconv(a); @@ -561,10 +565,9 @@ static ssize_t archive_write_binary_data(struct archive_write *a, const void *buff, size_t s) {-	struct cpio *cpio;+	struct cpio *cpio = a->format_data; 	int ret; -	cpio = (struct cpio *)a->format_data; 	if (s > cpio->entry_bytes_remaining) 		s = (size_t)cpio->entry_bytes_remaining; @@ -598,9 +601,8 @@ static int archive_write_binary_free(struct archive_write *a) {-	struct cpio *cpio;+	struct cpio *cpio = a->format_data; -	cpio = (struct cpio *)a->format_data; 	free(cpio->ino_list); 	free(cpio); 	a->format_data = NULL;@@ -610,9 +612,7 @@ static int archive_write_binary_finish_entry(struct archive_write *a) {-	struct cpio *cpio;+	struct cpio *cpio = a->format_data; -	cpio = (struct cpio *)a->format_data;-	return (__archive_write_nulls(a,-		(size_t)cpio->entry_bytes_remaining));+	return (__archive_write_nulls(a, cpio->entry_bytes_remaining)); }
c/archive_write_set_format_cpio_newc.c view
@@ -113,8 +113,7 @@ 	    ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_newc");  	/* If someone else was already registered, unregister them. */-	if (a->format_free != NULL)-		(a->format_free)(a);+	(void)__archive_write_unregister_format(a);  	cpio = calloc(1, sizeof(*cpio)); 	if (cpio == NULL) {@@ -138,7 +137,7 @@ archive_write_newc_options(struct archive_write *a, const char *key,     const char *val) {-	struct cpio *cpio = (struct cpio *)a->format_data;+	struct cpio *cpio = a->format_data; 	int ret = ARCHIVE_FAILED;  	if (strcmp(key, "hdrcharset")  == 0) {@@ -166,10 +165,9 @@ static struct archive_string_conv * get_sconv(struct archive_write *a) {-	struct cpio *cpio;+	struct cpio *cpio = a->format_data; 	struct archive_string_conv *sconv; -	cpio = (struct cpio *)a->format_data; 	sconv = cpio->opt_sconv; 	if (sconv == NULL) { 		if (!cpio->init_default_conversion) {@@ -216,8 +214,8 @@ static int write_header(struct archive_write *a, struct archive_entry *entry) {+	struct cpio *cpio = a->format_data; 	int64_t ino;-	struct cpio *cpio; 	const char *p, *path; 	int ret, ret_final; 	char h[c_header_size];@@ -226,7 +224,6 @@ 	size_t len, pathlength; 	int pad; -	cpio = (struct cpio *)a->format_data; 	ret_final = ARCHIVE_OK; 	sconv = get_sconv(a); @@ -378,10 +375,9 @@ static ssize_t archive_write_newc_data(struct archive_write *a, const void *buff, size_t s) {-	struct cpio *cpio;+	struct cpio *cpio = a->format_data; 	int ret; -	cpio = (struct cpio *)a->format_data; 	if (s > cpio->entry_bytes_remaining) 		s = (size_t)cpio->entry_bytes_remaining; @@ -430,6 +426,8 @@ 	struct archive_entry *trailer;  	trailer = archive_entry_new();+	if (trailer == NULL)+		return ARCHIVE_FATAL; 	archive_entry_set_nlink(trailer, 1); 	archive_entry_set_size(trailer, 0); 	archive_entry_set_pathname(trailer, "TRAILER!!!");@@ -442,9 +440,8 @@ static int archive_write_newc_free(struct archive_write *a) {-	struct cpio *cpio;+	struct cpio *cpio = a->format_data; -	cpio = (struct cpio *)a->format_data; 	free(cpio); 	a->format_data = NULL; 	return (ARCHIVE_OK);@@ -453,9 +450,8 @@ static int archive_write_newc_finish_entry(struct archive_write *a) {-	struct cpio *cpio;+	struct cpio *cpio = a->format_data; -	cpio = (struct cpio *)a->format_data; 	return (__archive_write_nulls(a,-		(size_t)cpio->entry_bytes_remaining + cpio->padding));+	    cpio->entry_bytes_remaining + cpio->padding)); }
c/archive_write_set_format_cpio_odc.c view
@@ -40,6 +40,7 @@ #include "archive.h" #include "archive_entry.h" #include "archive_entry_locale.h"+#include "archive_integer.h" #include "archive_private.h" #include "archive_write_private.h" #include "archive_write_set_format_private.h"@@ -107,8 +108,7 @@ 	    ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_odc");  	/* If someone else was already registered, unregister them. */-	if (a->format_free != NULL)-		(a->format_free)(a);+	(void)__archive_write_unregister_format(a);  	cpio = calloc(1, sizeof(*cpio)); 	if (cpio == NULL) {@@ -132,7 +132,7 @@ archive_write_odc_options(struct archive_write *a, const char *key,     const char *val) {-	struct cpio *cpio = (struct cpio *)a->format_data;+	struct cpio *cpio = a->format_data; 	int ret = ARCHIVE_FAILED;  	if (strcmp(key, "hdrcharset")  == 0) {@@ -204,10 +204,16 @@  	/* Ensure space for the new mapping. */ 	if (cpio->ino_list_size <= cpio->ino_list_next) {-		size_t newsize = cpio->ino_list_size < 512-		    ? 512 : cpio->ino_list_size * 2;-		void *newlist = realloc(cpio->ino_list,-		    sizeof(cpio->ino_list[0]) * newsize);+		size_t newsize, size;+		if (cpio->ino_list_size < 512)+			newsize = 512;+		else if (archive_ckd_mul_size(&newsize,+		    cpio->ino_list_size, 2))+			return (-1);+		if (archive_ckd_mul_size(&size,+		    newsize, sizeof(cpio->ino_list[0])))+			return (-1);+		void *newlist = realloc(cpio->ino_list, size); 		if (newlist == NULL) 			return (-1); @@ -226,10 +232,9 @@ static struct archive_string_conv * get_sconv(struct archive_write *a) {-	struct cpio *cpio;+	struct cpio *cpio = a->format_data; 	struct archive_string_conv *sconv; -	cpio = (struct cpio *)a->format_data; 	sconv = cpio->opt_sconv; 	if (sconv == NULL) { 		if (!cpio->init_default_conversion) {@@ -275,7 +280,7 @@ static int write_header(struct archive_write *a, struct archive_entry *entry) {-	struct cpio *cpio;+	struct cpio *cpio = a->format_data; 	const char *p, *path; 	int ret, ret_final; 	int64_t	ino;@@ -284,7 +289,6 @@ 	struct archive_entry *entry_main; 	size_t len, pathlength; -	cpio = (struct cpio *)a->format_data; 	ret_final = ARCHIVE_OK; 	sconv = get_sconv(a); @@ -420,10 +424,9 @@ static ssize_t archive_write_odc_data(struct archive_write *a, const void *buff, size_t s) {-	struct cpio *cpio;+	struct cpio *cpio = a->format_data; 	int ret; -	cpio = (struct cpio *)a->format_data; 	if (s > cpio->entry_bytes_remaining) 		s = (size_t)cpio->entry_bytes_remaining; @@ -487,9 +490,8 @@ static int archive_write_odc_free(struct archive_write *a) {-	struct cpio *cpio;+	struct cpio *cpio = a->format_data; -	cpio = (struct cpio *)a->format_data; 	free(cpio->ino_list); 	free(cpio); 	a->format_data = NULL;@@ -499,9 +501,8 @@ static int archive_write_odc_finish_entry(struct archive_write *a) {-	struct cpio *cpio;+	struct cpio *cpio = a->format_data; -	cpio = (struct cpio *)a->format_data;-	return (__archive_write_nulls(a,-		(size_t)cpio->entry_bytes_remaining));+	return (__archive_write_nulls(a, +	    cpio->entry_bytes_remaining)); }
c/archive_write_set_format_gnutar.c view
@@ -174,6 +174,11 @@ 	struct archive_write *a = (struct archive_write *)_a; 	struct gnutar *gnutar; +	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,+	    ARCHIVE_STATE_NEW, "archive_write_set_format_gnutar");++	(void)__archive_write_unregister_format(a);+ 	gnutar = calloc(1, sizeof(*gnutar)); 	if (gnutar == NULL) { 		archive_set_error(&a->archive, ENOMEM,@@ -197,7 +202,7 @@ archive_write_gnutar_options(struct archive_write *a, const char *key,     const char *val) {-	struct gnutar *gnutar = (struct gnutar *)a->format_data;+	struct gnutar *gnutar = a->format_data; 	int ret = ARCHIVE_FAILED;  	if (strcmp(key, "hdrcharset")  == 0) {@@ -231,9 +236,8 @@ static int archive_write_gnutar_free(struct archive_write *a) {-	struct gnutar *gnutar;+	struct gnutar *gnutar = a->format_data; -	gnutar = (struct gnutar *)a->format_data; 	free(gnutar); 	a->format_data = NULL; 	return (ARCHIVE_OK);@@ -242,12 +246,11 @@ static int archive_write_gnutar_finish_entry(struct archive_write *a) {-	struct gnutar *gnutar;+	struct gnutar *gnutar = a->format_data; 	int ret; -	gnutar = (struct gnutar *)a->format_data;-	ret = __archive_write_nulls(a, (size_t)-	    (gnutar->entry_bytes_remaining + gnutar->entry_padding));+	ret = __archive_write_nulls(a,+	    gnutar->entry_bytes_remaining + gnutar->entry_padding); 	gnutar->entry_bytes_remaining = gnutar->entry_padding = 0; 	return (ret); }@@ -255,10 +258,9 @@ static ssize_t archive_write_gnutar_data(struct archive_write *a, const void *buff, size_t s) {-	struct gnutar *gnutar;+	struct gnutar *gnutar = a->format_data; 	int ret; -	gnutar = (struct gnutar *)a->format_data; 	if (s > gnutar->entry_bytes_remaining) 		s = (size_t)gnutar->entry_bytes_remaining; 	ret = __archive_write_output(a, buff, s);@@ -272,15 +274,13 @@ archive_write_gnutar_header(struct archive_write *a,      struct archive_entry *entry) {+	struct gnutar *gnutar = a->format_data; 	char buff[512]; 	int r, ret, ret2 = ARCHIVE_OK; 	char tartype;-	struct gnutar *gnutar; 	struct archive_string_conv *sconv; 	struct archive_entry *entry_main; -	gnutar = (struct gnutar *)a->format_data;- 	/* Setup default string conversion. */ 	if (gnutar->opt_sconv == NULL) { 		if (!gnutar->init_default_conversion) {@@ -494,6 +494,13 @@ 		size_t length = gnutar->linkname_length + 1; 		struct archive_entry *temp = archive_entry_new2(&a->archive); +		if (temp == NULL) {+			archive_set_error(&a->archive, ENOMEM,+			    "Can't allocate memory for Linkname");+			ret = ARCHIVE_FATAL;+			goto exit_write_header;+		}+ 		/* Uname/gname here don't really matter since no one reads them; 		 * these are the values that GNU tar happens to use on FreeBSD. */ 		archive_entry_set_uname(temp, "root");@@ -524,6 +531,13 @@ 		size_t length = gnutar->pathname_length + 1; 		struct archive_entry *temp = archive_entry_new2(&a->archive); +		if (temp == NULL) {+			archive_set_error(&a->archive, ENOMEM,+			    "Can't allocate memory for Linkname");+			ret = ARCHIVE_FATAL;+			goto exit_write_header;+		}+ 		/* Uname/gname here don't really matter since no one reads them; 		 * these are the values that GNU tar happens to use on FreeBSD. */ 		archive_entry_set_uname(temp, "root");@@ -589,14 +603,12 @@ archive_format_gnutar_header(struct archive_write *a, char h[512],     struct archive_entry *entry, char tartype) {+	struct gnutar *gnutar = a->format_data; 	unsigned int checksum; 	int i, ret; 	size_t copy_length; 	const char *p;-	struct gnutar *gnutar; -	gnutar = (struct gnutar *)a->format_data;- 	ret = 0;  	/*@@ -652,7 +664,7 @@ 		copy_length = gnutar->gname_length; 	} 	if (copy_length > 0) {-		if (strlen(p) > GNUTAR_gname_size)+		if (copy_length > GNUTAR_gname_size) 			copy_length = GNUTAR_gname_size; 		memcpy(h + GNUTAR_gname_offset, p, copy_length); 	}
c/archive_write_set_format_iso9660.c view
@@ -1059,8 +1059,7 @@ 	    ARCHIVE_STATE_NEW, "archive_write_set_format_iso9660");  	/* If another format was already registered, unregister it. */-	if (a->format_free != NULL)-		(a->format_free)(a);+	(void)__archive_write_unregister_format(a);  	iso9660 = calloc(1, sizeof(*iso9660)); 	if (iso9660 == NULL) {@@ -1427,8 +1426,8 @@ 		break; 	case 'i': 		if (strcmp(key, "iso-level") == 0) {-			if (value != NULL && value[1] == '\0' &&-			    (value[0] >= '1' && value[0] <= '4')) {+			if (value != NULL && value[0] >= '1' &&+			    value[0] <= '4' && value[1] == '\0') { 				iso9660->opt.iso_level = value[0]-'0'; 				return (ARCHIVE_OK); 			}@@ -1529,13 +1528,11 @@ static int iso9660_write_header(struct archive_write *a, struct archive_entry *entry) {-	struct iso9660 *iso9660;+	struct iso9660 *iso9660 = a->format_data; 	struct isofile *file; 	struct isoent *isoent; 	int r, ret = ARCHIVE_OK; -	iso9660 = a->format_data;- 	iso9660->cur_file = NULL; 	iso9660->bytes_remaining = 0; 	iso9660->need_multi_extent = 0;@@ -1677,7 +1674,7 @@ 	 * order to reduce a extra memory copy. 	 */ 	if (wb_remaining(a) == wb_buffmax() && s > (1024 * 16)) {-		struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;+		struct iso9660 *iso9660 = a->format_data; 		xs = s % LOGICAL_BLOCK_SIZE; 		iso9660->wbuff_offset += s - xs; 		if (write_to_temp(a, buff, s - xs) != ARCHIVE_OK)@@ -1859,11 +1856,9 @@ static int iso9660_close(struct archive_write *a) {-	struct iso9660 *iso9660;+	struct iso9660 *iso9660 = a->format_data; 	int ret, blocks; -	iso9660 = a->format_data;- 	/* 	 * Write remaining data out to the temporary file. 	 */@@ -2121,11 +2116,9 @@ static int iso9660_free(struct archive_write *a) {-	struct iso9660 *iso9660;+	struct iso9660 *iso9660 = a->format_data; 	int i, ret; -	iso9660 = a->format_data;- 	/* Close the temporary file. */ 	if (iso9660->temp_fd >= 0) 		close(iso9660->temp_fd);@@ -2921,10 +2914,10 @@ 			extra_tell_used_size(&ctl, length); 			if (extra_space(&ctl) < 6) { 				bp = extra_next_record(&ctl, 6);-				nmmax = extra_space(&ctl);-				if (nmmax > 0xff)-					nmmax = 0xff; 			}+			nmmax = extra_space(&ctl);+			if (nmmax > 0xff)+				nmmax = 0xff; 			if (bp != NULL) { 				bp[1] = 'N'; 				bp[2] = 'M';@@ -3619,7 +3612,7 @@ static inline unsigned char * wb_buffptr(struct archive_write *a) {-	struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;+	struct iso9660 *iso9660 = a->format_data;  	return (&(iso9660->wbuff[sizeof(iso9660->wbuff) 		- iso9660->wbuff_remaining]));@@ -3628,7 +3621,7 @@ static int wb_write_out(struct archive_write *a) {-	struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;+	struct iso9660 *iso9660 = a->format_data; 	size_t wsize, nw; 	int r; @@ -3653,7 +3646,7 @@ static int wb_consume(struct archive_write *a, size_t size) {-	struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;+	struct iso9660 *iso9660 = a->format_data;  	if (size > iso9660->wbuff_remaining || 	    iso9660->wbuff_remaining == 0) {@@ -3674,7 +3667,7 @@ static int wb_set_offset(struct archive_write *a, int64_t off) {-	struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;+	struct iso9660 *iso9660 = a->format_data; 	int64_t used, ext_bytes;  	if (iso9660->wbuff_type != WB_TO_TEMP) {@@ -3841,7 +3834,7 @@ static int write_VD(struct archive_write *a, struct vdd *vdd) {-	struct iso9660 *iso9660;+	struct iso9660 *iso9660 = a->format_data; 	unsigned char *bp; 	uint16_t volume_set_size = 1; 	char identifier[256];@@ -3850,7 +3843,6 @@ 	unsigned char vd_ver, fst_ver; 	int r; -	iso9660 = a->format_data; 	switch (vdd->vdd_type) { 	case VDD_JOLIET: 		vdt = VDT_SUPPLEMENTARY;@@ -3988,10 +3980,9 @@ static int write_VD_boot_record(struct archive_write *a) {-	struct iso9660 *iso9660;+	struct iso9660 *iso9660 = a->format_data; 	unsigned char *bp; -	iso9660 = a->format_data; 	bp = wb_buffptr(a) -1; 	/* Volume Descriptor Type */ 	set_VD_bp(bp, VDT_BOOT_RECORD, 1);@@ -4059,7 +4050,7 @@ static int write_information_block(struct archive_write *a) {-	struct iso9660 *iso9660;+	struct iso9660 *iso9660 = a->format_data; 	char buf[128]; 	const char *v; 	int opt, r;@@ -4067,7 +4058,6 @@ 	size_t info_size = LOGICAL_BLOCK_SIZE * 			       NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK; -	iso9660 = (struct iso9660 *)a->format_data; 	if (info_size > wb_remaining(a)) { 		r = wb_write_out(a); 		if (r != ARCHIVE_OK)@@ -4717,14 +4707,12 @@ static int isofile_gen_utility_names(struct archive_write *a, struct isofile *file) {-	struct iso9660 *iso9660;+	struct iso9660 *iso9660 = a->format_data; 	const char *pathname; 	char *p, *dirname, *slash; 	size_t len; 	int ret = ARCHIVE_OK; -	iso9660 = a->format_data;- 	archive_string_empty(&(file->parentdir)); 	archive_string_empty(&(file->basename)); 	archive_string_empty(&(file->basename_utf16));@@ -5563,6 +5551,7 @@ static int isoent_tree(struct archive_write *a, struct isoent **isoentpp) {+	struct iso9660 *iso9660 = a->format_data; #if defined(_WIN32) && !defined(__CYGWIN__) 	char name[_MAX_FNAME];/* Included null terminator size. */ #elif defined(NAME_MAX) && NAME_MAX >= 255@@ -5570,7 +5559,6 @@ #else 	char name[256]; #endif-	struct iso9660 *iso9660 = a->format_data; 	struct isoent *dent, *isoent, *np; 	struct isofile *f1, *f2; 	const char *fn, *p;@@ -5998,7 +5986,7 @@ isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,     struct idr *idr) {-	struct iso9660 *iso9660;+	struct iso9660 *iso9660 = a->format_data; 	struct isoent *np; 	char *p; 	int l, r;@@ -6014,9 +6002,8 @@ 	const int null_size = 1;  	if (isoent->children.cnt == 0)-		return (0);+		return (ARCHIVE_OK); -	iso9660 = a->format_data; 	char_map = idr->char_map; 	if (iso9660->opt.iso_level <= 3) { 		allow_ldots = 0;@@ -6258,7 +6245,7 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,     struct idr *idr) {-	struct iso9660 *iso9660;+	struct iso9660 *iso9660 = a->format_data; 	struct isoent *np; 	unsigned char *p; 	size_t l;@@ -6271,9 +6258,8 @@ 	const int null_size = 2;  	if (isoent->children.cnt == 0)-		return (0);+		return (ARCHIVE_OK); -	iso9660 = a->format_data; 	if (iso9660->opt.joliet == OPT_JOLIET_LONGNAME) 		ffmax = 206; 	else@@ -7522,8 +7508,9 @@ 		(uint32_t)archive_entry_size(file->entry);  	/* Calculate a size of Block Pointers of zisofs. */-	_ceil = (file->zisofs.uncompressed_size + ZF_BLOCK_SIZE -1)-		>> file->zisofs.log2_bs;+	_ceil = (size_t)(((uint64_t)file->zisofs.uncompressed_size ++		    (ZF_BLOCK_SIZE - 1))+		>> file->zisofs.log2_bs); 	iso9660->zisofs.block_pointers_cnt = (int)_ceil + 1; 	iso9660->zisofs.block_pointers_idx = 0; 
c/archive_write_set_format_mtree.c view
@@ -117,7 +117,7 @@ 	int64_t ino; }; -struct mtree_writer {+struct mtree { 	struct mtree_entry *mtree_entry; 	struct mtree_entry *root; 	struct mtree_entry *cur_dirent;@@ -220,10 +220,10 @@ 	struct attr_counter *, struct mtree_entry *); static struct attr_counter * attr_counter_new(struct mtree_entry *, 	struct attr_counter *);-static int attr_counter_set_collect(struct mtree_writer *,+static int attr_counter_set_collect(struct mtree *, 	struct mtree_entry *);-static void attr_counter_set_free(struct mtree_writer *);-static int get_global_set_keys(struct mtree_writer *, struct mtree_entry *);+static void attr_counter_set_free(struct mtree *);+static int get_global_set_keys(struct mtree *, struct mtree_entry *); static int mtree_entry_add_child_tail(struct mtree_entry *, 	struct mtree_entry *); static int mtree_entry_create_virtual_dir(struct archive_write *, const char *,@@ -236,14 +236,14 @@ static void mtree_entry_free(struct mtree_entry *); static int mtree_entry_new(struct archive_write *, struct archive_entry *, 	struct mtree_entry **);-static void mtree_entry_register_free(struct mtree_writer *);-static void mtree_entry_register_init(struct mtree_writer *);+static void mtree_entry_register_free(struct mtree *);+static void mtree_entry_register_init(struct mtree *); static int mtree_entry_setup_filenames(struct archive_write *, 	struct mtree_entry *, struct archive_entry *); static int mtree_entry_tree_add(struct archive_write *, struct mtree_entry **);-static void sum_init(struct mtree_writer *);-static void sum_update(struct mtree_writer *, const void *, size_t);-static void sum_final(struct mtree_writer *, struct reg_info *);+static void sum_init(struct mtree *);+static void sum_update(struct mtree *, const void *, size_t);+static void sum_final(struct mtree *, struct reg_info *); static void sum_write(struct archive_string *, struct reg_info *); static int write_mtree_entry(struct archive_write *, struct mtree_entry *); static int write_dot_dot_entry(struct archive_write *, struct mtree_entry *);@@ -358,7 +358,7 @@  * Indent a line as the mtree utility does so it is readable for people.  */ static void-mtree_indent(struct mtree_writer *mtree)+mtree_indent(struct mtree *mtree) { 	int i, fn, nd, pd; 	const char *r, *s, *x;@@ -434,7 +434,7 @@  * collected by the attr_counter_set_collect() function.  */ static void-write_global(struct mtree_writer *mtree)+write_global(struct mtree *mtree) { 	struct archive_string setstr; 	struct archive_string unsetstr;@@ -636,7 +636,7 @@  * Tabulate uid, gid, mode and fflags of a entry in order to be used for /set.  */ static int-attr_counter_set_collect(struct mtree_writer *mtree, struct mtree_entry *me)+attr_counter_set_collect(struct mtree *mtree, struct mtree_entry *me) { 	struct attr_counter *ac, *last; 	struct attr_counter_set *acs = &mtree->acs;@@ -713,7 +713,7 @@ }  static void-attr_counter_set_free(struct mtree_writer *mtree)+attr_counter_set_free(struct mtree *mtree) { 	struct attr_counter_set *acs = &mtree->acs; @@ -724,7 +724,7 @@ }  static int-get_global_set_keys(struct mtree_writer *mtree, struct mtree_entry *me)+get_global_set_keys(struct mtree *mtree, struct mtree_entry *me) { 	int keys; @@ -913,7 +913,7 @@ archive_write_mtree_header(struct archive_write *a,     struct archive_entry *entry) {-	struct mtree_writer *mtree= a->format_data;+	struct mtree *mtree = a->format_data; 	struct mtree_entry *mtree_entry; 	int r, r2; @@ -956,7 +956,7 @@ static int write_mtree_entry(struct archive_write *a, struct mtree_entry *me) {-	struct mtree_writer *mtree = a->format_data;+	struct mtree *mtree = a->format_data; 	struct archive_string *str; 	int keys, ret; @@ -1107,7 +1107,7 @@ static int write_dot_dot_entry(struct archive_write *a, struct mtree_entry *n) {-	struct mtree_writer *mtree = a->format_data;+	struct mtree *mtree = a->format_data; 	int ret;  	if (n->parentdir.s) {@@ -1142,7 +1142,7 @@ static int write_mtree_entry_tree(struct archive_write *a) {-	struct mtree_writer *mtree = a->format_data;+	struct mtree *mtree = a->format_data; 	struct mtree_entry *np = mtree->root; 	struct archive_rb_node *n; 	int ret;@@ -1245,7 +1245,7 @@ static int archive_write_mtree_finish_entry(struct archive_write *a) {-	struct mtree_writer *mtree = a->format_data;+	struct mtree *mtree = a->format_data; 	struct mtree_entry *me;  	if ((me = mtree->mtree_entry) == NULL)@@ -1261,7 +1261,7 @@ static int archive_write_mtree_close(struct archive_write *a) {-	struct mtree_writer *mtree= a->format_data;+	struct mtree *mtree = a->format_data; 	int ret;  	if (mtree->root != NULL) {@@ -1278,7 +1278,7 @@ static ssize_t archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n) {-	struct mtree_writer *mtree= a->format_data;+	struct mtree *mtree = a->format_data;  	if (n > mtree->entry_bytes_remaining) 		n = (size_t)mtree->entry_bytes_remaining;@@ -1297,7 +1297,7 @@ static int archive_write_mtree_free(struct archive_write *a) {-	struct mtree_writer *mtree= a->format_data;+	struct mtree *mtree = a->format_data;  	if (mtree == NULL) 		return (ARCHIVE_OK);@@ -1317,7 +1317,7 @@ archive_write_mtree_options(struct archive_write *a, const char *key,     const char *value) {-	struct mtree_writer *mtree= a->format_data;+	struct mtree *mtree = a->format_data; 	int keybit = 0;  	switch (key[0]) {@@ -1429,12 +1429,11 @@ archive_write_set_format_mtree_default(struct archive *_a, const char *fn) { 	struct archive_write *a = (struct archive_write *)_a;-	struct mtree_writer *mtree;+	struct mtree *mtree;  	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, fn); -	if (a->format_free != NULL)-		(a->format_free)(a);+	(void)__archive_write_unregister_format(a);  	if ((mtree = calloc(1, sizeof(*mtree))) == NULL) { 		archive_set_error(&a->archive, ENOMEM,@@ -1481,9 +1480,7 @@ 		"archive_write_set_format_mtree_classic"); 	if (r == ARCHIVE_OK) { 		struct archive_write *a = (struct archive_write *)_a;-		struct mtree_writer *mtree;--		mtree = (struct mtree_writer *)a->format_data;+		struct mtree *mtree = a->format_data;  		/* Set to output a mtree archive in classic format. */ 		mtree->classic = 1;@@ -1495,7 +1492,7 @@ }  static void-sum_init(struct mtree_writer *mtree)+sum_init(struct mtree *mtree) {  	mtree->compute_sum = 0;@@ -1556,7 +1553,7 @@ }  static void-sum_update(struct mtree_writer *mtree, const void *buff, size_t n)+sum_update(struct mtree *mtree, const void *buff, size_t n) { 	if (mtree->compute_sum & F_CKSUM) { 		/*@@ -1614,7 +1611,7 @@ }  static void-sum_final(struct mtree_writer *mtree, struct reg_info *reg)+sum_final(struct mtree *mtree, struct reg_info *reg) { 	struct ae_digest digest; @@ -1995,7 +1992,7 @@ }  static void-mtree_entry_register_add(struct mtree_writer *mtree, struct mtree_entry *file)+mtree_entry_register_add(struct mtree *mtree, struct mtree_entry *file) {         file->next = NULL;         *mtree->file_list.last = file;@@ -2003,14 +2000,14 @@ }  static void-mtree_entry_register_init(struct mtree_writer *mtree)+mtree_entry_register_init(struct mtree *mtree) { 	mtree->file_list.first = NULL; 	mtree->file_list.last = &(mtree->file_list.first); }  static void-mtree_entry_register_free(struct mtree_writer *mtree)+mtree_entry_register_free(struct mtree *mtree) { 	struct mtree_entry *file, *file_next; @@ -2073,6 +2070,7 @@ static int mtree_entry_tree_add(struct archive_write *a, struct mtree_entry **filep) {+	struct mtree *mtree = a->format_data; #if defined(_WIN32) && !defined(__CYGWIN__) 	char name[_MAX_FNAME];/* Included null terminator size. */ #elif defined(NAME_MAX) && NAME_MAX >= 255@@ -2080,7 +2078,6 @@ #else 	char name[256]; #endif-	struct mtree_writer *mtree = (struct mtree_writer *)a->format_data; 	struct mtree_entry *dent, *file, *np; 	const char *fn, *p; 	int l, r;
c/archive_write_set_format_pax.c view
@@ -45,6 +45,8 @@ #include "archive_write_private.h" #include "archive_write_set_format_private.h" +#define PAX_MAX_ALIGN (1U << 20)+ struct sparse_block { 	struct sparse_block	*next; 	int		is_hole;@@ -64,6 +66,10 @@ 	struct archive_string_conv *sconv_utf8; 	int			 opt_binary; +	/* If non-zero, align regular file data to this many bytes in the+	 * uncompressed stream (power of two, multiple of 512). */+	size_t			 align;+ 	unsigned flags; #define WRITE_SCHILY_XATTR       (1 << 0) #define WRITE_LIBARCHIVE_XATTR   (1 << 1)@@ -79,6 +85,8 @@ static void		 add_pax_attr_time(struct archive_string *, 			     const char *key, int64_t sec, 			     unsigned long nanos);+static size_t		 add_pax_padding_prefix(struct archive_string *,+			     size_t cur_len, size_t target_len); static int		 add_pax_acl(struct archive_write *, 			    struct archive_entry *, struct pax *, int); static ssize_t		 archive_write_pax_data(struct archive_write *,@@ -90,6 +98,7 @@ 			     struct archive_entry *); static int		 archive_write_pax_options(struct archive_write *, 			     const char *, const char *);+static int		 write_pax_padding(struct archive_write *, size_t); static char		*base64_encode(const char *src, size_t len); static char		*build_gnu_sparse_name(char *dest, const char *src); static char		*build_pax_attribute_name(char *dest, const char *src);@@ -136,8 +145,7 @@ 	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, 	    ARCHIVE_STATE_NEW, "archive_write_set_format_pax"); -	if (a->format_free != NULL)-		(a->format_free)(a);+	(void)__archive_write_unregister_format(a);  	pax = calloc(1, sizeof(*pax)); 	if (pax == NULL) {@@ -164,7 +172,7 @@ archive_write_pax_options(struct archive_write *a, const char *key,     const char *val) {-	struct pax *pax = (struct pax *)a->format_data;+	struct pax *pax = a->format_data; 	int ret = ARCHIVE_FAILED;  	if (strcmp(key, "hdrcharset")  == 0) {@@ -223,6 +231,25 @@ 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 			    "pax: invalid xattr header name"); 		return (ret);+	} else if (strcmp(key, "align") == 0) {+		unsigned long v;+		char *end;++		if (val == NULL || val[0] == 0) {+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+			    "pax: align option needs a value");+			return (ARCHIVE_FAILED);+		}+		v = strtoul(val, &end, 10);+		if (*end != '\0' || v == 0 || (v % 512) != 0 ||+		    (v & (v - 1)) != 0 || v > PAX_MAX_ALIGN) {+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+			    "pax: align must be a power of two, a multiple "+			    "of 512, and no larger than 1 MiB");+			return (ARCHIVE_FAILED);+		}+		pax->align = (size_t)v;+		return (ARCHIVE_OK); 	}  	/* Note: The "warn" return is just to inform the options@@ -361,6 +388,81 @@ 	archive_strappend_char(as, '\n'); } +/*+ * Append the length/key prefix of an ignorable "LIBARCHIVE.pad" record whose+ * full length rounds the pax body up to 'target_len'.  Return the number of+ * value/newline bytes that must be emitted after the in-memory header.+ */+static size_t+add_pax_padding_prefix(struct archive_string *as, size_t cur_len,+    size_t target_len)+{+	static const char key[] = "LIBARCHIVE.pad";+	char tmp[1 + 3 * sizeof(int64_t)];+	char *length;+	size_t prefix_len, record_len;++	if (target_len <= cur_len)+		return (0);+	record_len = target_len - cur_len;+	tmp[sizeof(tmp) - 1] = 0;+	length = format_int(tmp + sizeof(tmp) - 1, (int64_t)record_len);+	prefix_len = strlen(length) + 1 + sizeof(key) - 1 + 1;+	if (record_len <= prefix_len)+		return (0); /* not enough room; leave unaligned */++	archive_strcat(as, length);+	archive_strappend_char(as, ' ');+	archive_strcat(as, key);+	archive_strappend_char(as, '=');+	return (record_len - prefix_len);+}++/* Emit a deferred pax padding value followed by its record newline. */+static int+write_pax_padding(struct archive_write *a, size_t length)+{+	char padding[1024];++	if (length == 0)+		return (ARCHIVE_OK);+	memset(padding, 'X', sizeof(padding));+	while (length > 1) {+		size_t to_write = length - 1;+		int r;++		if (to_write > sizeof(padding))+			to_write = sizeof(padding);+		r = __archive_write_output(a, padding, to_write);+		if (r != ARCHIVE_OK)+			return (r);+		length -= to_write;+	}+	return (__archive_write_output(a, "\n", 1));+}++/*+ * For the pax "align" option: given entry offset 'off' (a multiple of 512) and+ * current extended-header body length 'l0', return the body length needed so+ * the file data (after the x header) lands on 'align', or 'l0' if already+ * aligned.+ */+static size_t+pax_align_body_len(uint64_t off, size_t l0, size_t align)+{+	uint64_t amask = (uint64_t)align - 1;+	/* Data offset with no extra padding (no x header when l0 == 0). */+	uint64_t natural_off = (l0 == 0) ? off + 512+	    : off + 1024 + (((uint64_t)l0 + 511) & ~(uint64_t)511);++	if ((natural_off & amask) == 0)+		return (l0);++	/* Grow the body (past l0 plus pad-record room) to land data on align. */+	uint64_t base = off + 1024;+	return ((size_t)(((base + l0 + 64 + amask) & ~amask) - base));+}+ static void archive_write_pax_header_xattr(struct pax *pax, const char *encoded_name,     const void *value, size_t value_len)@@ -578,6 +680,7 @@ archive_write_pax_header(struct archive_write *a,     struct archive_entry *entry_original) {+	struct pax *pax = a->format_data; 	struct archive_entry *entry_main; 	const char *p; 	const char *suffix;@@ -585,7 +688,6 @@ 	int acl_types; 	int sparse_count; 	uint64_t sparse_total, real_size;-	struct pax *pax; 	const char *hardlink; 	const char *path = NULL, *linkpath = NULL; 	const char *uname = NULL, *gname = NULL;@@ -593,6 +695,7 @@ 	size_t mac_metadata_size; 	struct archive_string_conv *sconv; 	size_t hardlink_length, path_length, linkpath_length;+	size_t pax_header_padding = 0; 	size_t uname_length, gname_length;  	char paxbuff[512];@@ -604,7 +707,6 @@  	ret = ARCHIVE_OK; 	need_extension = 0;-	pax = (struct pax *)a->format_data;  	const time_t ustar_max_mtime = get_ustar_max_mtime(); @@ -1338,14 +1440,6 @@ 		archive_entry_set_size(entry_main, 0);  	/*-	 * Pax-restricted does not store data for hardlinks, in order-	 * to improve compatibility with ustar.-	 */-	if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE &&-	    hardlink != NULL)-		archive_entry_set_size(entry_main, 0);--	/* 	 * XXX Full pax interchange format does permit a hardlink 	 * entry to have data associated with it.  I'm not supporting 	 * that here because the client expects me to tell them whether@@ -1411,6 +1505,21 @@ 		return (ARCHIVE_FATAL); 	} +	/* Pad the extended header so contiguous file data starts on a pax->align+	 * boundary (for reflinking); short and sparse files are left alone. */+	if (pax->align > 0+	    && archive_entry_filetype(entry_main) == AE_IFREG+	    && hardlink == NULL+	    && sparse_count == 0+	    && real_size >= (uint64_t)pax->align) {+		size_t l0 = archive_strlen(&(pax->pax_header));+		size_t needed = pax_align_body_len(+		    (uint64_t)a->filter_first->bytes_written, l0, pax->align);+		if (needed != l0)+			pax_header_padding = add_pax_padding_prefix(+			    &(pax->pax_header), l0, needed);+	}+ 	/* If we built any extended attributes, write that entry first. */ 	if (archive_strlen(&(pax->pax_header)) > 0) { 		struct archive_entry *pax_attr_entry;@@ -1419,11 +1528,20 @@ 		__LA_MODE_T mode;  		pax_attr_entry = archive_entry_new2(&a->archive);+		if (pax_attr_entry == NULL) {+			archive_set_error(&a->archive, ENOMEM,+			    "Out of memory");+			archive_entry_free(entry_main);+			archive_string_free(&entry_name);+			return (ARCHIVE_FATAL);+		}+ 		p = entry_name.s; 		archive_entry_set_pathname(pax_attr_entry, 		    build_pax_attribute_name(pax_entry_name, p)); 		archive_entry_set_size(pax_attr_entry,-		    archive_strlen(&(pax->pax_header)));+		    archive_strlen(&(pax->pax_header)) ++		    pax_header_padding); 		/* Copy uid/gid (but clip to ustar limits). */ 		uid = archive_entry_uid(entry_main); 		if (uid >= 1 << 18)@@ -1489,7 +1607,8 @@ 			return (ARCHIVE_FATAL); 		} -		pax->entry_bytes_remaining = archive_strlen(&(pax->pax_header));+		pax->entry_bytes_remaining = archive_strlen(&(pax->pax_header)) ++		    pax_header_padding; 		pax->entry_padding = 		    0x1ff & (-(int64_t)pax->entry_bytes_remaining); @@ -1501,8 +1620,14 @@ 			archive_string_free(&entry_name); 			return (ARCHIVE_FATAL); 		}+		r = write_pax_padding(a, pax_header_padding);+		if (r != ARCHIVE_OK) {+			archive_entry_free(entry_main);+			archive_string_free(&entry_name);+			return (ARCHIVE_FATAL);+		} 		/* Pad out the end of the entry. */-		r = __archive_write_nulls(a, (size_t)pax->entry_padding);+		r = __archive_write_nulls(a, pax->entry_padding); 		if (r != ARCHIVE_OK) { 			/* If a write fails, we're pretty much toast. */ 			archive_entry_free(entry_main);@@ -1574,18 +1699,21 @@ 	char *p; 	int need_slash = 0; /* Was there a trailing slash? */ 	size_t suffix_length = 98; /* 99 - 1 for trailing slash */-	size_t insert_length;+	size_t insert_length, insert_name_length;  	/* Length of additional dir element to be added. */-	if (insert == NULL)+	if (insert == NULL) {+		insert_name_length = 0; 		insert_length = 0;-	else+	} else {+		insert_name_length = strlen(insert); 		/* +2 here allows for '/' before and after the insert. */-		insert_length = strlen(insert) + 2;+		insert_length = insert_name_length + 2;+	}  	/* Step 0: Quick bailout in a common case. */ 	if (src_length < 100 && insert == NULL) {-		strncpy(dest, src, src_length);+		memcpy(dest, src, src_length); 		dest[src_length] = '\0'; 		return (dest); 	}@@ -1607,6 +1735,26 @@ 		} 		break; 	}++	/*+	 * Pathological case: after trimming trailing '/' characters and+	 * '/.' path elements, there is no filename component left.  This+	 * happens for pathnames made entirely of '/' characters.  Do not+	 * attempt to compute filename_end - 1 in that case, which would+	 * move the filename pointer in front of the input buffer and read+	 * one byte out of bounds.  Emit a root-like ustar name instead.+	 */+	if (filename_end == src) {+		p = dest;+		if (insert != NULL) {+			strcpy(p, insert);+			p += strlen(insert);+		}+		*p++ = '/';+		*p = '\0';+		return (dest);+	}+ 	if (need_slash) 		suffix_length--; 	/* Find start of filename. */@@ -1647,24 +1795,22 @@ 		suffix_end++;  	/* Step 4: Build the new name. */-	/* The OpenBSD strlcpy function is safer, but less portable. */-	/* Rather than maintain two versions, just use the strncpy version. */ 	p = dest; 	if (prefix_end > prefix) {-		strncpy(p, prefix, prefix_end - prefix);+		memcpy(p, prefix, (size_t)(prefix_end - prefix)); 		p += prefix_end - prefix; 	} 	if (suffix_end > suffix) {-		strncpy(p, suffix, suffix_end - suffix);+		memcpy(p, suffix, (size_t)(suffix_end - suffix)); 		p += suffix_end - suffix; 	} 	if (insert != NULL) { 		/* Note: assume insert does not have leading or trailing '/' */-		strcpy(p, insert);-		p += strlen(insert);+		memcpy(p, insert, insert_name_length);+		p += insert_name_length; 		*p++ = '/'; 	}-	strncpy(p, filename, filename_end - filename);+	memcpy(p, filename, (size_t)(filename_end - filename)); 	p += filename_end - filename; 	if (need_slash) 		*p++ = '/';@@ -1794,7 +1940,12 @@ 	}  	/* General case: build a ustar-compatible name adding-	 * "/GNUSparseFile/". */+	 * "/GNUSparseFile.0/". */++	if (p == src) {+		strcpy(dest, "/GNUSparseFile.0/rootdir");+		return (dest);+	} 	build_ustar_entry_name(dest, src, p - src, "GNUSparseFile.0");  	return (dest);@@ -1810,9 +1961,8 @@ static int archive_write_pax_free(struct archive_write *a) {-	struct pax *pax;+	struct pax *pax = a->format_data; -	pax = (struct pax *)a->format_data; 	if (pax == NULL) 		return (ARCHIVE_OK); @@ -1828,11 +1978,10 @@ static int archive_write_pax_finish_entry(struct archive_write *a) {-	struct pax *pax;+	struct pax *pax = a->format_data; 	uint64_t remaining; 	int ret; -	pax = (struct pax *)a->format_data; 	remaining = pax->entry_bytes_remaining; 	if (remaining == 0) { 		while (pax->sparse_list) {@@ -1844,7 +1993,7 @@ 			pax->sparse_list = sb; 		} 	}-	ret = __archive_write_nulls(a, (size_t)(remaining + pax->entry_padding));+	ret = __archive_write_nulls(a, remaining + pax->entry_padding); 	pax->entry_bytes_remaining = pax->entry_padding = 0; 	return (ret); }@@ -1852,13 +2001,11 @@ static ssize_t archive_write_pax_data(struct archive_write *a, const void *buff, size_t s) {-	struct pax *pax;+	struct pax *pax = a->format_data; 	size_t ws; 	size_t total; 	int ret; -	pax = (struct pax *)a->format_data;- 	/* 	 * According to GNU PAX format 1.0, write a sparse map 	 * before the body.@@ -1980,20 +2127,27 @@ 	      'e','f','g','h','i','j','k','l','m','n','o','p','q','r','s', 	      't','u','v','w','x','y','z','0','1','2','3','4','5','6','7', 	      '8','9','+','/' };-	int v;+	uint32_t v; 	char *d, *out;+	size_t out_len;  	/* 3 bytes becomes 4 chars, but round up and allow for trailing NUL */-	out = malloc((len * 4 + 2) / 3 + 1);+	if (archive_ckd_mul_size(&out_len, len, 4) ||+	    archive_ckd_add_size(&out_len, out_len, 2))+		return (NULL);+	out_len = out_len / 3;+	if (archive_ckd_add_size(&out_len, out_len, 1))+		return (NULL);+	out = malloc(out_len); 	if (out == NULL) 		return (NULL); 	d = out;  	/* Convert each group of 3 bytes into 4 characters. */ 	while (len >= 3) {-		v = (((int)s[0] << 16) & 0xff0000)-		    | (((int)s[1] << 8) & 0xff00)-		    | (((int)s[2]) & 0x00ff);+		v = ((uint32_t)(unsigned char)s[0] << 16)+		    | ((uint32_t)(unsigned char)s[1] << 8)+		    | (uint32_t)(unsigned char)s[2]; 		s += 3; 		len -= 3; 		*d++ = digits[(v >> 18) & 0x3f];@@ -2005,13 +2159,13 @@ 	switch (len) { 	case 0: break; 	case 1:-		v = (((int)s[0] << 16) & 0xff0000);+		v = ((uint32_t)(unsigned char)s[0] << 16); 		*d++ = digits[(v >> 18) & 0x3f]; 		*d++ = digits[(v >> 12) & 0x3f]; 		break; 	case 2:-		v = (((int)s[0] << 16) & 0xff0000)-		    | (((int)s[1] << 8) & 0xff00);+		v = ((uint32_t)(unsigned char)s[0] << 16)+		    | ((uint32_t)(unsigned char)s[1] << 8); 		*d++ = digits[(v >> 18) & 0x3f]; 		*d++ = digits[(v >> 12) & 0x3f]; 		*d++ = digits[(v >> 6) & 0x3f];
c/archive_write_set_format_raw.c view
@@ -55,8 +55,7 @@ 	    ARCHIVE_STATE_NEW, "archive_write_set_format_raw");  	/* If someone else was already registered, unregister them. */-	if (a->format_free != NULL)-		(a->format_free)(a);+	(void)__archive_write_unregister_format(a);  	raw = calloc(1, sizeof(*raw)); 	if (raw == NULL) {@@ -82,7 +81,7 @@ static int archive_write_raw_header(struct archive_write *a, struct archive_entry *entry) {-	struct raw *raw = (struct raw *)a->format_data;+	struct raw *raw = a->format_data;  	if (archive_entry_filetype(entry) != AE_IFREG) { 		archive_set_error(&a->archive, ERANGE,@@ -116,9 +115,8 @@ static int archive_write_raw_free(struct archive_write *a) {-	struct raw *raw;+	struct raw *raw = a->format_data; -	raw = (struct raw *)a->format_data; 	free(raw); 	a->format_data = NULL; 	return (ARCHIVE_OK);
c/archive_write_set_format_shar.c view
@@ -98,11 +98,8 @@ 	} } -/*- * Set output format to 'shar' format.- */-int-archive_write_set_format_shar(struct archive *_a)+static int+shar_set_format(struct archive *_a, int dump) { 	struct archive_write *a = (struct archive_write *)_a; 	struct shar *shar;@@ -111,8 +108,7 @@ 	    ARCHIVE_STATE_NEW, "archive_write_set_format_shar");  	/* If someone else was already registered, unregister them. */-	if (a->format_free != NULL)-		(a->format_free)(a);+	(void)__archive_write_unregister_format(a);  	shar = calloc(1, sizeof(*shar)); 	if (shar == NULL) {@@ -121,50 +117,54 @@ 	} 	archive_string_init(&shar->work); 	archive_string_init(&shar->quoted_name);+	if (dump) {+		shar->dump = 1;+		a->format_write_data = archive_write_shar_data_uuencode;+		a->archive.archive_format = ARCHIVE_FORMAT_SHAR_DUMP;+		a->archive.archive_format_name = "shar dump";+	} else {+		a->format_write_data = archive_write_shar_data_sed;+		a->archive.archive_format = ARCHIVE_FORMAT_SHAR_BASE;+		a->archive.archive_format_name = "shar";+	} 	a->format_data = shar; 	a->format_name = "shar"; 	a->format_write_header = archive_write_shar_header; 	a->format_close = archive_write_shar_close; 	a->format_free = archive_write_shar_free;-	a->format_write_data = archive_write_shar_data_sed; 	a->format_finish_entry = archive_write_shar_finish_entry;-	a->archive.archive_format = ARCHIVE_FORMAT_SHAR_BASE;-	a->archive.archive_format_name = "shar"; 	return (ARCHIVE_OK); }  /*+ * Set output format to 'shar' format.+ */+int+archive_write_set_format_shar(struct archive *a)+{+	return shar_set_format(a, 0);+}++/*  * An alternate 'shar' that uses uudecode instead of 'sed' to encode  * file contents and can therefore be used to archive binary files.  * In addition, this variant also attempts to restore ownership, file modes,  * and other extended file information.  */ int-archive_write_set_format_shar_dump(struct archive *_a)+archive_write_set_format_shar_dump(struct archive *a) {-	struct archive_write *a = (struct archive_write *)_a;-	struct shar *shar;--	int ret = archive_write_set_format_shar(&a->archive);-	if (ret != ARCHIVE_OK)-		return ret;-	shar = (struct shar *)a->format_data;-	shar->dump = 1;-	a->format_write_data = archive_write_shar_data_uuencode;-	a->archive.archive_format = ARCHIVE_FORMAT_SHAR_DUMP;-	a->archive.archive_format_name = "shar dump";-	return (ARCHIVE_OK);+	return shar_set_format(a, 1); }  static int archive_write_shar_header(struct archive_write *a, struct archive_entry *entry) {+	struct shar *shar = a->format_data; 	const char *linkname; 	const char *name; 	char *p, *pp;-	struct shar *shar; -	shar = (struct shar *)a->format_data; 	if (!shar->wrote_header) { 		archive_strcat(&shar->work, "#!/bin/sh\n"); 		archive_strcat(&shar->work, "# This is a shell archive\n");@@ -343,14 +343,13 @@ static ssize_t archive_write_shar_data_sed(struct archive_write *a, const void *buff, size_t n) {+	struct shar *shar = a->format_data; 	static const size_t ensured = 65533;-	struct shar *shar; 	const char *src; 	char *buf, *buf_end; 	int ret; 	size_t written = n; -	shar = (struct shar *)a->format_data; 	if (!shar->has_data || n == 0) 		return (0); @@ -475,12 +474,11 @@ archive_write_shar_data_uuencode(struct archive_write *a, const void *buff,     size_t length) {-	struct shar *shar;+	struct shar *shar = a->format_data; 	const char *src; 	size_t n; 	int ret; -	shar = (struct shar *)a->format_data; 	if (!shar->has_data) 		return (ARCHIVE_OK); 	src = (const char *)buff;@@ -524,13 +522,12 @@ static int archive_write_shar_finish_entry(struct archive_write *a) {+	struct shar *shar = a->format_data; 	const char *g, *p, *u;-	struct shar *shar; 	int ret; -	shar = (struct shar *)a->format_data; 	if (shar->entry == NULL)-		return (0);+		return (ARCHIVE_OK);  	if (shar->dump) { 		/* Finish uuencoded data. */@@ -602,7 +599,7 @@ static int archive_write_shar_close(struct archive_write *a) {-	struct shar *shar;+	struct shar *shar = a->format_data; 	int ret;  	/*@@ -610,8 +607,6 @@ 	 * fix them all up at end-of-archive. 	 */ -	shar = (struct shar *)a->format_data;- 	/* 	 * Only write the end-of-archive markers if the archive was 	 * actually started.  This avoids problems if someone sets@@ -640,9 +635,8 @@ static int archive_write_shar_free(struct archive_write *a) {-	struct shar *shar;+	struct shar *shar = a->format_data; -	shar = (struct shar *)a->format_data; 	if (shar == NULL) 		return (ARCHIVE_OK); 
c/archive_write_set_format_ustar.c view
@@ -172,8 +172,7 @@ 	    ARCHIVE_STATE_NEW, "archive_write_set_format_ustar");  	/* If someone else was already registered, unregister them. */-	if (a->format_free != NULL)-		(a->format_free)(a);+	(void)__archive_write_unregister_format(a);  	/* Basic internal sanity test. */ 	if (sizeof(template_header) != 512) {@@ -206,7 +205,7 @@ archive_write_ustar_options(struct archive_write *a, const char *key,     const char *val) {-	struct ustar *ustar = (struct ustar *)a->format_data;+	struct ustar *ustar = a->format_data; 	int ret = ARCHIVE_FAILED;  	if (strcmp(key, "hdrcharset")  == 0) {@@ -234,14 +233,12 @@ static int archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry) {+	struct ustar *ustar = a->format_data; 	char buff[512]; 	int ret, ret2;-	struct ustar *ustar; 	struct archive_entry *entry_main; 	struct archive_string_conv *sconv; -	ustar = (struct ustar *)a->format_data;- 	/* Setup default string conversion. */ 	if (ustar->opt_sconv == NULL) { 		if (!ustar->init_default_conversion) {@@ -736,9 +733,8 @@ static int archive_write_ustar_free(struct archive_write *a) {-	struct ustar *ustar;+	struct ustar *ustar = a->format_data; -	ustar = (struct ustar *)a->format_data; 	free(ustar); 	a->format_data = NULL; 	return (ARCHIVE_OK);@@ -747,12 +743,11 @@ static int archive_write_ustar_finish_entry(struct archive_write *a) {-	struct ustar *ustar;+	struct ustar *ustar = a->format_data; 	int ret; -	ustar = (struct ustar *)a->format_data; 	ret = __archive_write_nulls(a,-	    (size_t)(ustar->entry_bytes_remaining + ustar->entry_padding));+	    ustar->entry_bytes_remaining + ustar->entry_padding); 	ustar->entry_bytes_remaining = ustar->entry_padding = 0; 	return (ret); }@@ -760,10 +755,9 @@ static ssize_t archive_write_ustar_data(struct archive_write *a, const void *buff, size_t s) {-	struct ustar *ustar;+	struct ustar *ustar = a->format_data; 	int ret; -	ustar = (struct ustar *)a->format_data; 	if (s > ustar->entry_bytes_remaining) 		s = (size_t)ustar->entry_bytes_remaining; 	ret = __archive_write_output(a, buff, s);
c/archive_write_set_format_v7tar.c view
@@ -149,8 +149,7 @@ 	    ARCHIVE_STATE_NEW, "archive_write_set_format_v7tar");  	/* If someone else was already registered, unregister them. */-	if (a->format_free != NULL)-		(a->format_free)(a);+	(void)__archive_write_unregister_format(a);  	/* Basic internal sanity test. */ 	if (sizeof(template_header) != 512) {@@ -183,7 +182,7 @@ archive_write_v7tar_options(struct archive_write *a, const char *key,     const char *val) {-	struct v7tar *v7tar = (struct v7tar *)a->format_data;+	struct v7tar *v7tar = a->format_data; 	int ret = ARCHIVE_FAILED;  	if (strcmp(key, "hdrcharset")  == 0) {@@ -211,14 +210,12 @@ static int archive_write_v7tar_header(struct archive_write *a, struct archive_entry *entry) {+	struct v7tar *v7tar = a->format_data; 	char buff[512]; 	int ret, ret2;-	struct v7tar *v7tar; 	struct archive_entry *entry_main; 	struct archive_string_conv *sconv; -	v7tar = (struct v7tar *)a->format_data;- 	/* Setup default string conversion. */ 	if (v7tar->opt_sconv == NULL) { 		if (!v7tar->init_default_conversion) {@@ -616,9 +613,8 @@ static int archive_write_v7tar_free(struct archive_write *a) {-	struct v7tar *v7tar;+	struct v7tar *v7tar = a->format_data; -	v7tar = (struct v7tar *)a->format_data; 	free(v7tar); 	a->format_data = NULL; 	return (ARCHIVE_OK);@@ -627,12 +623,11 @@ static int archive_write_v7tar_finish_entry(struct archive_write *a) {-	struct v7tar *v7tar;+	struct v7tar *v7tar = a->format_data; 	int ret; -	v7tar = (struct v7tar *)a->format_data; 	ret = __archive_write_nulls(a,-	    (size_t)(v7tar->entry_bytes_remaining + v7tar->entry_padding));+	    v7tar->entry_bytes_remaining + v7tar->entry_padding); 	v7tar->entry_bytes_remaining = v7tar->entry_padding = 0; 	return (ret); }@@ -640,10 +635,9 @@ static ssize_t archive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s) {-	struct v7tar *v7tar;+	struct v7tar *v7tar = a->format_data; 	int ret; -	v7tar = (struct v7tar *)a->format_data; 	if (s > v7tar->entry_bytes_remaining) 		s = (size_t)v7tar->entry_bytes_remaining; 	ret = __archive_write_output(a, buff, s);
c/archive_write_set_format_warc.c view
@@ -49,68 +49,81 @@ #include "archive_write_private.h" #include "archive_write_set_format_private.h" -struct warc_s {+/*+ * Overview of the WARC writer:+ *+ * This writer emits WARC/1.0 resource records for regular files.  It+ * writes a warcinfo record once by default, unless the omit-warcinfo+ * option is used.  Each resource record gets a WARC-Target-URI from+ * the entry pathname, a generated WARC-Record-ID, and a mandatory+ * Content-Length header.+ */++struct warc { 	unsigned int omit_warcinfo:1;  	time_t now;-	mode_t typ;-	unsigned int rng;-	/* populated size */-	uint64_t populz;+	mode_t filetype;+	/* Remaining bytes to write for the current entry */+	uint64_t entry_bytes_remaining; }; -static const char warcinfo[] =+#define WARC_HEADER_MAX_SIZE 512++static const char warcinfo_payload[] =     "software: libarchive/" ARCHIVE_VERSION_ONLY_STRING "\r\n"     "format: WARC file version 1.0\r\n"; -typedef enum {-	WT_NONE,-	/* warcinfo */-	WT_INFO,-	/* metadata */-	WT_META,-	/* resource */-	WT_RSRC,-	/* request, unsupported */-	WT_REQ,-	/* response, unsupported */-	WT_RSP,-	/* revisit, unsupported */-	WT_RVIS,-	/* conversion, unsupported */-	WT_CONV,-	/* continuation, unsupported at the moment */-	WT_CONT,-	/* invalid type */-	LAST_WT-} warc_type_t;+enum warc_type {+	WARC_TYPE_NONE,+	/* WARC info */+	WARC_TYPE_INFO,+	/* Metadata */+	WARC_TYPE_METADATA,+	/* Resource */+	WARC_TYPE_RESOURCE,+	/* Request, unsupported */+	WARC_TYPE_REQUEST,+	/* Response, unsupported by this writer */+	WARC_TYPE_RESPONSE,+	/* Revisit, unsupported */+	WARC_TYPE_REVISIT,+	/* Conversion, unsupported */+	WARC_TYPE_CONVERSION,+	/* Continuation, currently unsupported */+	WARC_TYPE_CONTINUATION,+	WARC_TYPE_LAST+}; -typedef struct {-	warc_type_t type;-	const char *tgturi;-	const char *recid;-	time_t rtime;-	time_t mtime;-	const char *cnttyp;-	uint64_t cntlen;-} warc_essential_hdr_t;+struct warc_header {+	enum warc_type type;+	const char *target_uri;+	const char *record_id;+	time_t record_time;+	time_t modification_time;+	const char *content_type;+	uint64_t content_length;+}; -typedef struct {-	unsigned int u[4U];-} warc_uuid_t;+struct warc_uuid {+	unsigned int value[4U];+}; -static int _warc_options(struct archive_write*, const char *key, const char *v);-static int _warc_header(struct archive_write *a, struct archive_entry *entry);-static ssize_t _warc_data(struct archive_write *a, const void *buf, size_t sz);-static int _warc_finish_entry(struct archive_write *a);-static int _warc_close(struct archive_write *a);-static int _warc_free(struct archive_write *a);+static int	archive_write_warc_options(struct archive_write *,+		    const char *, const char *);+static int	archive_write_warc_header(struct archive_write *,+		    struct archive_entry *);+static ssize_t	archive_write_warc_data(struct archive_write *, const void *,+		    size_t);+static int	archive_write_warc_finish_entry(struct archive_write *);+static int	archive_write_warc_close(struct archive_write *);+static int	archive_write_warc_free(struct archive_write *); -/* private routines */-static ssize_t _popul_ehdr(struct archive_string *t, size_t z, warc_essential_hdr_t);-static int _gen_uuid(warc_uuid_t *tgt);+static void	warc_format_time(struct archive_string *, const char *, time_t);+static ssize_t	warc_populate_header(struct archive_string *, size_t,+		    struct warc_header);+static void	warc_generate_uuid(struct warc_uuid *); - /*  * Set output format to ISO 28500 (aka WARC) format.  */@@ -118,103 +131,110 @@ archive_write_set_format_warc(struct archive *_a) { 	struct archive_write *a = (struct archive_write *)_a;-	struct warc_s *w;+	struct warc *warc;  	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, 	    ARCHIVE_STATE_NEW, "archive_write_set_format_warc");  	/* If another format was already registered, unregister it. */-	if (a->format_free != NULL) {-		(a->format_free)(a);-	}+	(void)__archive_write_unregister_format(a); -	w = malloc(sizeof(*w));-	if (w == NULL) {+	warc = malloc(sizeof(*warc));+	if (warc == NULL) { 		archive_set_error(&a->archive, ENOMEM, 		    "Can't allocate warc data"); 		return (ARCHIVE_FATAL); 	}-	/* by default we're emitting a file wide header */-	w->omit_warcinfo = 0U;-	/* obtain current time for date fields */-	w->now = time(NULL);-	/* reset file type info */-	w->typ = 0;-	/* also initialise our rng */-	w->rng = (unsigned int)w->now;+	/* Emit a warcinfo record by default. */+	warc->omit_warcinfo = 0U;+	/* Use the current time for WARC-Date values. */+	warc->now = time(NULL);+	/* Reset file type information. */+	warc->filetype = 0; -	a->format_data = w;+	a->format_data = warc; 	a->format_name = "WARC/1.0";-	a->format_options = _warc_options;-	a->format_write_header = _warc_header;-	a->format_write_data = _warc_data;-	a->format_close = _warc_close;-	a->format_free = _warc_free;-	a->format_finish_entry = _warc_finish_entry;+	a->format_options = archive_write_warc_options;+	a->format_write_header = archive_write_warc_header;+	a->format_write_data = archive_write_warc_data;+	a->format_close = archive_write_warc_close;+	a->format_free = archive_write_warc_free;+	a->format_finish_entry = archive_write_warc_finish_entry; 	a->archive.archive_format = ARCHIVE_FORMAT_WARC; 	a->archive.archive_format_name = "WARC/1.0"; 	return (ARCHIVE_OK); } --/* archive methods */ static int-_warc_options(struct archive_write *a, const char *key, const char *val)+archive_write_warc_options(struct archive_write *a, const char *key,+    const char *val) {-	struct warc_s *w = a->format_data;+	struct warc *warc = a->format_data;  	if (strcmp(key, "omit-warcinfo") == 0) { 		if (val == NULL || strcmp(val, "true") == 0) {-			/* great */-			w->omit_warcinfo = 1U;+			/* Option accepted. */+			warc->omit_warcinfo = 1U; 			return (ARCHIVE_OK); 		} 	} -	/* Note: The "warn" return is just to inform the options-	 * supervisor that we didn't handle it.  It will generate-	 * a suitable error if no one used this option. */+	/* ARCHIVE_WARN tells the options supervisor that this option was not+	 * handled here.  It will report an error if no module uses it. */ 	return (ARCHIVE_WARN); }  static int-_warc_header(struct archive_write *a, struct archive_entry *entry)+archive_write_warc_header(struct archive_write *a, struct archive_entry *entry) {-	struct warc_s *w = a->format_data;-	struct archive_string hdr;-#define MAX_HDR_SIZE 512+	struct warc *warc = a->format_data;+	struct archive_string header; -	/* check whether warcinfo record needs outputting */-	if (!w->omit_warcinfo) {-		ssize_t r;-		warc_essential_hdr_t wi = {-			WT_INFO,-			/*uri*/NULL,-			/*urn*/NULL,-			/*rtm*/0,-			/*mtm*/0,-			/*cty*/"application/warc-fields",-			/*len*/sizeof(warcinfo) - 1U,+	/* Emit the warcinfo record if needed. */+	if (!warc->omit_warcinfo) {+		ssize_t header_size;+		int ret;+		struct warc_header warcinfo_header = {+			WARC_TYPE_INFO,+			/* URI */NULL,+			/* Record ID */NULL,+			/* Record time */0,+			/* Modified time */0,+			/* Content type */"application/warc-fields",+			/* Content length */sizeof(warcinfo_payload) - 1U, 		};-		wi.rtime = w->now;-		wi.mtime = w->now;+		warcinfo_header.record_time = warc->now;+		warcinfo_header.modification_time = warc->now; -		archive_string_init(&hdr);-		r = _popul_ehdr(&hdr, MAX_HDR_SIZE, wi);-		if (r >= 0) {-			/* jackpot! */-			/* now also use HDR buffer for the actual warcinfo */-			archive_strncat(&hdr, warcinfo, sizeof(warcinfo) -1);+		archive_string_init(&header);+		header_size = warc_populate_header(&header,+		    WARC_HEADER_MAX_SIZE, warcinfo_header);+		if (header_size < 0) {+			archive_string_free(&header);+			archive_set_error(&a->archive,+			    ARCHIVE_ERRNO_FILE_FORMAT,+			    "Cannot archive warcinfo record");+			return (ARCHIVE_FAILED);+		} -			/* append end-of-record indicator */-			archive_strncat(&hdr, "\r\n\r\n", 4);+		/* Reuse the header buffer for the warcinfo payload. */+		archive_strncat(&header, warcinfo_payload,+		    sizeof(warcinfo_payload) - 1); -			/* write to output stream */-			__archive_write_output(a, hdr.s, archive_strlen(&hdr));+		/* Append the end-of-record indicator. */+		archive_strncat(&header, "\r\n\r\n", 4);++		/* Write the warcinfo record to the output stream. */+		ret = __archive_write_output(a, header.s,+		    archive_strlen(&header));+		if (ret != ARCHIVE_OK) {+			archive_string_free(&header);+			return (ret); 		}-		/* indicate we're done with file header writing */-		w->omit_warcinfo = 1U;-		archive_string_free(&hdr);++		/* Mark the file header as written. */+		warc->omit_warcinfo = 1U;+		archive_string_free(&header); 	}  	if (archive_entry_pathname(entry) == NULL) {@@ -223,222 +243,249 @@ 		return (ARCHIVE_WARN); 	} -	w->typ = archive_entry_filetype(entry);-	w->populz = 0U;-	if (w->typ == AE_IFREG) {-		warc_essential_hdr_t rh = {-			WT_RSRC,-			/*uri*/NULL,-			/*urn*/NULL,-			/*rtm*/0,-			/*mtm*/0,-			/*cty*/NULL,-			/*len*/0,+	warc->filetype = archive_entry_filetype(entry);+	warc->entry_bytes_remaining = 0U;+	if (warc->filetype == AE_IFREG) {+		struct warc_header resource_header = {+			WARC_TYPE_RESOURCE,+			/* URI */NULL,+			/* Record ID */NULL,+			/* Record time */0,+			/* Modified time */0,+			/* Content type */NULL,+			/* Content length */0, 		};-		ssize_t r;-		rh.tgturi = archive_entry_pathname(entry);-		rh.rtime = w->now;-		rh.mtime = archive_entry_mtime(entry);-		rh.cntlen = (size_t)archive_entry_size(entry);+		ssize_t header_size;+		int ret;+		int64_t size; -		archive_string_init(&hdr);-		r = _popul_ehdr(&hdr, MAX_HDR_SIZE, rh);-		if (r < 0) {-			/* don't bother */-			archive_string_free(&hdr);-			archive_set_error(-				&a->archive,-				ARCHIVE_ERRNO_FILE_FORMAT,-				"cannot archive file");-			return (ARCHIVE_WARN);+		resource_header.target_uri = archive_entry_pathname(entry);+		resource_header.record_time = warc->now;+		resource_header.modification_time = archive_entry_mtime(entry);+		if (!archive_entry_size_is_set(entry)) {+			archive_set_error(&a->archive, -1,+			    "Size required");+			return (ARCHIVE_FAILED); 		}-		/* otherwise append to output stream */-		__archive_write_output(a, hdr.s, r);-		/* and let subsequent calls to _data() know about the size */-		w->populz = rh.cntlen;-		archive_string_free(&hdr);+		size = archive_entry_size(entry);+		if (size < 0) {+			archive_set_error(&a->archive, -1,+			    "Size required");+			return (ARCHIVE_FAILED);+		}+		resource_header.content_length = (uint64_t)size;++		archive_string_init(&header);+		header_size = warc_populate_header(&header,+		    WARC_HEADER_MAX_SIZE, resource_header);+		if (header_size < 0) {+			/* Header generation failed. */+			archive_string_free(&header);+			archive_set_error(&a->archive,+			    ARCHIVE_ERRNO_FILE_FORMAT,+			    "WARC resource header is too large");+			return (ARCHIVE_FATAL);+		}+		/* Append the header to the output stream. */+		ret = __archive_write_output(a, header.s, header_size);+		if (ret != ARCHIVE_OK) {+			archive_string_free(&header);+			return (ret);+		}+		/* Save the remaining size for subsequent data callbacks. */+		warc->entry_bytes_remaining = resource_header.content_length;+		archive_string_free(&header); 		return (ARCHIVE_OK); 	}-	/* just resort to erroring as per Tim's advice */+	/* Report unsupported file types through the common helper. */ 	__archive_write_entry_filetype_unsupported( 	    &a->archive, entry, "WARC"); 	return (ARCHIVE_FAILED); }  static ssize_t-_warc_data(struct archive_write *a, const void *buf, size_t len)+archive_write_warc_data(struct archive_write *a, const void *buf, size_t len) {-	struct warc_s *w = a->format_data;+	struct warc *warc = a->format_data; -	if (w->typ == AE_IFREG) {-		int rc;+	if (warc->filetype == AE_IFREG) {+		int ret; -		/* never write more bytes than announced */-		if (len > w->populz) {-			len = (size_t)w->populz;+		/* Never write more bytes than announced. */+		if ((uint64_t)len > warc->entry_bytes_remaining) {+			len = (size_t)warc->entry_bytes_remaining; 		} -		/* now then, out we put the whole shebang */-		rc = __archive_write_output(a, buf, len);-		if (rc != ARCHIVE_OK) {-			return rc;+		/* Write the entry data. */+		ret = __archive_write_output(a, buf, len);+		if (ret != ARCHIVE_OK) {+			return (ret); 		}+		warc->entry_bytes_remaining -= len; 	}-	return len;+	return (len); }  static int-_warc_finish_entry(struct archive_write *a)+archive_write_warc_finish_entry(struct archive_write *a) {-	static const char _eor[] = "\r\n\r\n";-	struct warc_s *w = a->format_data;+	static const char end_of_record[] = "\r\n\r\n";+	struct warc *warc = a->format_data; -	if (w->typ == AE_IFREG) {-		int rc = __archive_write_output(a, _eor, sizeof(_eor) - 1U);+	if (warc->filetype == AE_IFREG) {+		int ret; -		if (rc != ARCHIVE_OK) {-			return rc;+		if (warc->entry_bytes_remaining != 0U) {+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+			    "WARC entry is shorter than Content-Length");+			return (ARCHIVE_FATAL); 		}++		ret = __archive_write_output(a, end_of_record,+		    sizeof(end_of_record) - 1U);+		if (ret != ARCHIVE_OK) {+			return (ret);+		} 	}-	/* reset type info */-	w->typ = 0;+	/* Reset file type information. */+	warc->filetype = 0; 	return (ARCHIVE_OK); }  static int-_warc_close(struct archive_write *a)+archive_write_warc_close(struct archive_write *a) { 	(void)a; /* UNUSED */ 	return (ARCHIVE_OK); }  static int-_warc_free(struct archive_write *a)+archive_write_warc_free(struct archive_write *a) {-	struct warc_s *w = a->format_data;+	struct warc *warc = a->format_data; -	free(w);+	free(warc); 	a->format_data = NULL; 	return (ARCHIVE_OK); } --/* private routines */+/* Like strftime(3), but for time_t objects. */ static void-xstrftime(struct archive_string *as, const char *fmt, time_t t)+warc_format_time(struct archive_string *str, const char *format, time_t t) {-/** like strftime(3) but for time_t objects */-	struct tm *rt;+	struct tm *tm; #if defined(HAVE_GMTIME_R) || defined(HAVE_GMTIME_S)-	struct tm timeHere;+	struct tm tm_storage; #endif-	char strtime[100];+	char time_string[100]; 	size_t len;  #if defined(HAVE_GMTIME_S)-	rt = gmtime_s(&timeHere, &t) ? NULL : &timeHere;+	tm = gmtime_s(&tm_storage, &t) ? NULL : &tm_storage; #elif defined(HAVE_GMTIME_R)-	rt = gmtime_r(&t, &timeHere);+	tm = gmtime_r(&t, &tm_storage); #else-	rt = gmtime(&t);+	tm = gmtime(&t); #endif-	if (!rt)+	if (tm == NULL) 		return;-	/* leave the hard yacker to our role model strftime() */-	len = strftime(strtime, sizeof(strtime)-1, fmt, rt);-	archive_strncat(as, strtime, len);+	/* Let strftime() handle the actual formatting. */+	len = strftime(time_string, sizeof(time_string) - 1, format, tm);+	archive_strncat(str, time_string, len); }  static ssize_t-_popul_ehdr(struct archive_string *tgt, size_t tsz, warc_essential_hdr_t hdr)+warc_populate_header(struct archive_string *header_string, size_t max_size,+    struct warc_header header) {-	static const char _ver[] = "WARC/1.0\r\n";-	static const char * const _typ[LAST_WT] = {+	static const char version[] = "WARC/1.0\r\n";+	static const char * const record_types[WARC_TYPE_LAST] = { 		NULL, "warcinfo", "metadata", "resource", NULL 	};-	char std_uuid[48U];+	char generated_record_id[48U]; -	if (hdr.type == WT_NONE || hdr.type > WT_RSRC) {-		/* brilliant, how exactly did we get here? */-		return -1;+	if (header.type == WARC_TYPE_NONE || header.type > WARC_TYPE_RESOURCE) {+		/* Invalid record type for this writer. */+		return (-1); 	} -	archive_strcpy(tgt, _ver);+	archive_strcpy(header_string, version); -	archive_string_sprintf(tgt, "WARC-Type: %s\r\n", _typ[hdr.type]);+	archive_string_sprintf(header_string, "WARC-Type: %s\r\n",+	    record_types[header.type]); -	if (hdr.tgturi != NULL) {-		/* check if there's a xyz:// */-		static const char _uri[] = "";-		static const char _fil[] = "file://";-		const char *u;-		const char *chk = strchr(hdr.tgturi, ':');+	if (header.target_uri != NULL) {+		const char *uri_prefix;+		const char *scheme = strchr(header.target_uri, ':'); -		if (chk != NULL && chk[1U] == '/' && chk[2U] == '/') {-			/* yep, it's definitely a URI */-			u = _uri;+		/* Check whether the value already contains ://. */+		if (scheme != NULL && scheme[1U] == '/' && scheme[2U] == '/') {+			/* Already has a scheme-style :// prefix. */+			uri_prefix = ""; 		} else {-			/* hm, best to prepend file:// then */-			u = _fil;+			/* Prepend file:// for local paths. */+			uri_prefix = "file://"; 		}-		archive_string_sprintf(tgt,-			"WARC-Target-URI: %s%s\r\n", u, hdr.tgturi);+		archive_string_sprintf(header_string,+		    "WARC-Target-URI: %s%s\r\n", uri_prefix,+		    header.target_uri); 	} -	/* record time is usually when the http is sent off,-	 * just treat the archive writing as such for a moment */-	xstrftime(tgt, "WARC-Date: %Y-%m-%dT%H:%M:%SZ\r\n", hdr.rtime);+	/* Write WARC-Date from header.record_time. */+	warc_format_time(header_string,+	    "WARC-Date: %Y-%m-%dT%H:%M:%SZ\r\n", header.record_time); -	/* while we're at it, record the mtime */-	xstrftime(tgt, "Last-Modified: %Y-%m-%dT%H:%M:%SZ\r\n", hdr.mtime);+	/* Also write Last-Modified from header.modification_time. */+	warc_format_time(header_string,+	    "Last-Modified: %Y-%m-%dT%H:%M:%SZ\r\n",+	    header.modification_time); -	if (hdr.recid == NULL) {-		/* generate one, grrrr */-		warc_uuid_t u;+	if (header.record_id == NULL) {+		/* Generate a record ID when one was not provided. */+		struct warc_uuid uuid; -		_gen_uuid(&u);-		/* Unfortunately, archive_string_sprintf does not-		 * handle the minimum number following '%'.-		 * So we have to use snprintf function here instead-		 * of archive_string_snprintf function. */-#if defined(_WIN32) && !defined(__CYGWIN__) && !( defined(_MSC_VER) && _MSC_VER >= 1900)+		warc_generate_uuid(&uuid);+		/* archive_string_sprintf() does not support minimum field widths, so+		 * use snprintf() for UUID formatting. */+#if defined(_WIN32) && !defined(__CYGWIN__) && \+    !(defined(_MSC_VER) && _MSC_VER >= 1900) #define snprintf _snprintf #endif-		snprintf(-			std_uuid, sizeof(std_uuid),-			"<urn:uuid:%08x-%04x-%04x-%04x-%04x%08x>",-			u.u[0U],-			u.u[1U] >> 16U, u.u[1U] & 0xffffU,-			u.u[2U] >> 16U, u.u[2U] & 0xffffU,-			u.u[3U]);-		hdr.recid = std_uuid;+		snprintf(generated_record_id, sizeof(generated_record_id),+		    "<urn:uuid:%08x-%04x-%04x-%04x-%04x%08x>",+		    uuid.value[0U],+		    uuid.value[1U] >> 16U, uuid.value[1U] & 0xffffU,+		    uuid.value[2U] >> 16U, uuid.value[2U] & 0xffffU,+		    uuid.value[3U]);+		header.record_id = generated_record_id; 	} -	/* record-id is mandatory, fingers crossed we won't fail */-	archive_string_sprintf(tgt, "WARC-Record-ID: %s\r\n", hdr.recid);+	/* WARC-Record-ID is mandatory. */+	archive_string_sprintf(header_string, "WARC-Record-ID: %s\r\n",+	    header.record_id); -	if (hdr.cnttyp != NULL) {-		archive_string_sprintf(tgt, "Content-Type: %s\r\n", hdr.cnttyp);+	if (header.content_type != NULL) {+		archive_string_sprintf(header_string, "Content-Type: %s\r\n",+		    header.content_type); 	} -	/* next one is mandatory */-	archive_string_sprintf(tgt, "Content-Length: %ju\r\n", (uintmax_t)hdr.cntlen);-	/**/-	archive_strncat(tgt, "\r\n", 2);+	/* Content-Length is mandatory. */+	archive_string_sprintf(header_string, "Content-Length: %ju\r\n",+	    (uintmax_t)header.content_length);+	/* End of header. */+	archive_strncat(header_string, "\r\n", 2); -	return (archive_strlen(tgt) >= tsz)? -1: (ssize_t)archive_strlen(tgt);+	return (archive_strlen(header_string) >= max_size) ?+	    -1 : (ssize_t)archive_strlen(header_string); } -static int-_gen_uuid(warc_uuid_t *tgt)+static void+warc_generate_uuid(struct warc_uuid *uuid) {-	archive_random(tgt->u, sizeof(tgt->u));-	/* obey uuid version 4 rules */-	tgt->u[1U] &= 0xffff0fffU;-	tgt->u[1U] |= 0x4000U;-	tgt->u[2U] &= 0x3fffffffU;-	tgt->u[2U] |= 0x80000000U;-	return 0;+	archive_random(uuid->value, sizeof(uuid->value));+	/* Apply UUID version 4 rules. */+	uuid->value[1U] &= 0xffff0fffU;+	uuid->value[1U] |= 0x4000U;+	uuid->value[2U] &= 0x3fffffffU;+	uuid->value[2U] |= 0x80000000U; }--/* archive_write_set_format_warc.c ends here */
c/archive_write_set_format_xar.c view
@@ -111,7 +111,7 @@ static int xml_writer_write_attribute(struct xml_writer *ctx, const char *key,     const char *value); static int xml_writer_write_attributef(struct xml_writer *ctx, const char *key,-    const char *format, ...);+    const char *format, ...) __LA_PRINTF(3, 4); static int xml_writer_write_string(struct xml_writer *ctx, const char *string); static int xml_writer_write_base64(struct xml_writer* ctx,     const char *data, size_t start, size_t len);@@ -129,14 +129,20 @@ enum sumalg { 	CKSUM_NONE = 0, 	CKSUM_SHA1 = 1,-	CKSUM_MD5 = 2+	CKSUM_MD5 = 2,+	CKSUM_SHA256 = 3,+	CKSUM_SHA512 = 4 };  #define MD5_SIZE	16 #define SHA1_SIZE	20-#define MAX_SUM_SIZE	20+#define SHA256_SIZE	32+#define SHA512_SIZE	64+#define MAX_SUM_SIZE	64 #define MD5_NAME	"md5" #define SHA1_NAME	"sha1"+#define SHA256_NAME	"sha256"+#define SHA512_NAME	"sha512"  enum enctype { 	NONE,@@ -154,6 +160,12 @@ #ifdef ARCHIVE_HAS_SHA1 	archive_sha1_ctx	 sha1ctx; #endif+#ifdef ARCHIVE_HAS_SHA256+	archive_sha256_ctx	 sha256ctx;+#endif+#ifdef ARCHIVE_HAS_SHA512+	archive_sha512_ctx	 sha512ctx;+#endif };  enum la_zaction {@@ -366,8 +378,7 @@ 	    ARCHIVE_STATE_NEW, "archive_write_set_format_xar");  	/* If another format was already registered, unregister it. */-	if (a->format_free != NULL)-		(a->format_free)(a);+	(void)__archive_write_unregister_format(a);  	xar = calloc(1, sizeof(*xar)); 	if (xar == NULL) {@@ -380,22 +391,19 @@ 	file_init_hardlinks(xar); 	archive_string_init(&(xar->tstr)); 	archive_string_init(&(xar->vstr));+	archive_string_init(&(xar->cur_dirstr));  	/* 	 * Create the root directory. 	 */ 	xar->root = file_create_virtual_dir(a, xar, "");-	if (xar->root == NULL) {-		free(xar);-		archive_set_error(&a->archive, ENOMEM,-		    "Can't allocate xar data");-		return (ARCHIVE_FATAL);-	}+	if (xar->root == NULL)+		goto memerr; 	xar->root->parent = xar->root; 	file_register(xar, xar->root); 	xar->cur_dirent = xar->root;-	archive_string_init(&(xar->cur_dirstr));-	archive_string_ensure(&(xar->cur_dirstr), 1);+	if (archive_string_ensure(&(xar->cur_dirstr), 1) == NULL)+		goto memerr; 	xar->cur_dirstr.s[0] = 0;  	/*@@ -422,14 +430,23 @@ 	a->archive.archive_format_name = "xar";  	return (ARCHIVE_OK);++memerr:+	archive_string_free(&(xar->cur_dirstr));+	archive_string_free(&(xar->tstr));+	archive_string_free(&(xar->vstr));+	file_free_hardlinks(xar);+	file_free_register(xar);+	free(xar);+	archive_set_error(&a->archive, ENOMEM,+	    "Can't allocate xar data");+	return (ARCHIVE_FATAL); }  static int xar_options(struct archive_write *a, const char *key, const char *value) {-	struct xar *xar;--	xar = (struct xar *)a->format_data;+	struct xar *xar = a->format_data;  	if (strcmp(key, "checksum") == 0) { 		if (value == NULL)@@ -440,6 +457,14 @@ 			xar->opt_sumalg = CKSUM_SHA1; 		else if (strcmp(value, "md5") == 0) 			xar->opt_sumalg = CKSUM_MD5;+#ifdef ARCHIVE_HAS_SHA256+		else if (strcmp(value, "sha256") == 0)+			xar->opt_sumalg = CKSUM_SHA256;+#endif+#ifdef ARCHIVE_HAS_SHA512+		else if (strcmp(value, "sha512") == 0)+			xar->opt_sumalg = CKSUM_SHA512;+#endif 		else { 			archive_set_error(&(a->archive), 			    ARCHIVE_ERRNO_MISC,@@ -515,6 +540,14 @@ 			xar->opt_toc_sumalg = CKSUM_SHA1; 		else if (strcmp(value, "md5") == 0) 			xar->opt_toc_sumalg = CKSUM_MD5;+#ifdef ARCHIVE_HAS_SHA256+		else if (strcmp(value, "sha256") == 0)+			xar->opt_toc_sumalg = CKSUM_SHA256;+#endif+#ifdef ARCHIVE_HAS_SHA512+		else if (strcmp(value, "sha512") == 0)+			xar->opt_toc_sumalg = CKSUM_SHA512;+#endif 		else { 			archive_set_error(&(a->archive), 			    ARCHIVE_ERRNO_MISC,@@ -559,12 +592,11 @@ static int xar_write_header(struct archive_write *a, struct archive_entry *entry) {-	struct xar *xar;+	struct xar *xar = a->format_data; 	struct file *file; 	struct archive_entry *file_entry; 	int r, r2; -	xar = (struct xar *)a->format_data; 	xar->cur_file = NULL; 	xar->bytes_remaining = 0; @@ -582,8 +614,10 @@ 		return (ARCHIVE_FATAL); 	} 	r2 = file_gen_utility_names(a, file);-	if (r2 < ARCHIVE_WARN)+	if (r2 < ARCHIVE_WARN) {+		file_free(file); 		return (r2);+	}  	/* 	 * Ignore a path which looks like the top of directory name@@ -672,20 +706,25 @@ 	checksum_init(&(xar->e_sumwrk), xar->opt_sumalg); 	r = xar_compression_init_encoder(a); -	if (r != ARCHIVE_OK)+	if (r != ARCHIVE_OK) {+		struct chksumval sumval;++		checksum_final(&(xar->a_sumwrk), &sumval);+		checksum_final(&(xar->e_sumwrk), &sumval);+		xar->a_sumwrk.alg = CKSUM_NONE;+		xar->e_sumwrk.alg = CKSUM_NONE; 		return (r);-	else+	} else 		return (r2); }  static int write_to_temp(struct archive_write *a, const void *buff, size_t s) {-	struct xar *xar;+	struct xar *xar = a->format_data; 	const unsigned char *p; 	ssize_t ws; -	xar = (struct xar *)a->format_data; 	p = (const unsigned char *)buff; 	while (s) { 		ws = write(xar->temp_fd, p, s);@@ -704,14 +743,12 @@ static ssize_t xar_write_data(struct archive_write *a, const void *buff, size_t s) {-	struct xar *xar;+	struct xar *xar = a->format_data; 	enum la_zaction run; 	size_t size = 0; 	size_t rsize; 	int r; -	xar = (struct xar *)a->format_data;- 	if (s > xar->bytes_remaining) 		s = (size_t)xar->bytes_remaining; 	if (s == 0 || xar->cur_file == NULL)@@ -805,12 +842,11 @@ static int xar_finish_entry(struct archive_write *a) {-	struct xar *xar;+	struct xar *xar = a->format_data; 	struct file *file; 	size_t s; 	ssize_t w; -	xar = (struct xar *)a->format_data; 	if (xar->cur_file == NULL) 		return (ARCHIVE_OK); @@ -907,14 +943,13 @@ 	return (ARCHIVE_OK); } -static int+static int __LA_PRINTF(4, 5) xmlwrite_fstring(struct archive_write *a, struct xml_writer *writer, 	const char *key, const char *fmt, ...) {-	struct xar *xar;+	struct xar *xar = a->format_data; 	va_list ap; -	xar = (struct xar *)a->format_data; 	va_start(ap, fmt); 	archive_string_empty(&xar->vstr); 	archive_string_vsprintf(&xar->vstr, fmt, ap);@@ -1202,7 +1237,7 @@ make_file_entry(struct archive_write *a, struct xml_writer *writer,     struct file *file) {-	struct xar *xar;+	struct xar *xar = a->format_data; 	const char *filetype, *filelink, *fflags; 	struct archive_string linkto; 	struct heap_data *heap;@@ -1210,7 +1245,6 @@ 	size_t len; 	int r, r2; -	xar = (struct xar *)a->format_data; 	r2 = ARCHIVE_OK;  	/*@@ -1333,11 +1367,11 @@ 			return (ARCHIVE_FATAL); 		} 		r = xmlwrite_fstring(a, writer, "major",-		    "%d", archive_entry_rdevmajor(file->entry));+		    "%ld", (long)archive_entry_rdevmajor(file->entry)); 		if (r < 0) 			return (ARCHIVE_FATAL); 		r = xmlwrite_fstring(a, writer, "minor",-		    "%d", archive_entry_rdevminor(file->entry));+		    "%ld", (long)archive_entry_rdevminor(file->entry)); 		if (r < 0) 			return (ARCHIVE_FATAL); 		r = xml_writer_end_element(writer);@@ -1361,7 +1395,7 @@ 		return (ARCHIVE_FATAL); 	if (archive_entry_dev(file->entry) != 0) { 		r = xmlwrite_fstring(a, writer, "deviceno",-		    "%d", archive_entry_dev(file->entry));+		    "%ld", (long)archive_entry_dev(file->entry)); 		if (r < 0) 			return (ARCHIVE_FATAL); 	}@@ -1572,7 +1606,7 @@ static int make_toc(struct archive_write *a) {-	struct xar *xar;+	struct xar *xar = a->format_data; 	struct file *np; 	struct xml_writer *writer; 	const char* content;@@ -1580,8 +1614,6 @@ 	int algsize; 	int r, ret; -	xar = (struct xar *)a->format_data;- 	ret = ARCHIVE_FATAL;  	/*@@ -1822,11 +1854,10 @@ static int flush_wbuff(struct archive_write *a) {-	struct xar *xar;+	struct xar *xar = a->format_data; 	int r; 	size_t s; -	xar = (struct xar *)a->format_data; 	s = sizeof(xar->wbuff) - xar->wbuff_remaining; 	r = __archive_write_output(a, xar->wbuff, s); 	if (r != ARCHIVE_OK)@@ -1838,10 +1869,9 @@ static int copy_out(struct archive_write *a, uint64_t offset, uint64_t length) {-	struct xar *xar;+	struct xar *xar = a->format_data; 	int r; -	xar = (struct xar *)a->format_data; 	if (lseek(xar->temp_fd, offset, SEEK_SET) < 0) { 		archive_set_error(&(a->archive), errno, "lseek failed"); 		return (ARCHIVE_FATAL);@@ -1883,13 +1913,11 @@ static int xar_close(struct archive_write *a) {-	struct xar *xar;+	struct xar *xar = a->format_data; 	unsigned char *wb; 	uint64_t length; 	int r; -	xar = (struct xar *)a->format_data;- 	/* Empty! */ 	if (xar->root->children.first == NULL) 		return (ARCHIVE_OK);@@ -1949,9 +1977,7 @@ static int xar_free(struct archive_write *a) {-	struct xar *xar;--	xar = (struct xar *)a->format_data;+	struct xar *xar = a->format_data;  	/* Close the temporary file. */ 	if (xar->temp_fd >= 0)@@ -2109,13 +2135,12 @@ static int file_gen_utility_names(struct archive_write *a, struct file *file) {-	struct xar *xar;+	struct xar *xar = a->format_data; 	const char *pp; 	char *p, *dirname, *slash; 	size_t len; 	int r = ARCHIVE_OK; -	xar = (struct xar *)a->format_data; 	archive_string_empty(&(file->parentdir)); 	archive_string_empty(&(file->basename)); 	archive_string_empty(&(file->symlink));@@ -2303,6 +2328,7 @@ static int file_tree(struct archive_write *a, struct file **filepp) {+	struct xar *xar = a->format_data; #if defined(_WIN32) && !defined(__CYGWIN__) 	char name[_MAX_FNAME];/* Included null terminator size. */ #elif defined(NAME_MAX) && NAME_MAX >= 255@@ -2310,7 +2336,6 @@ #else 	char name[256]; #endif-	struct xar *xar = (struct xar *)a->format_data; 	struct file *dent, *file, *np; 	struct archive_entry *ent; 	const char *fn, *p;@@ -2414,8 +2439,12 @@ 				return (ARCHIVE_FATAL); 			} 			archive_string_free(&as);-			if (file_gen_utility_names(a, vp) <= ARCHIVE_FAILED)+			if (file_gen_utility_names(a, vp) <= ARCHIVE_FAILED) {+				file_free(vp);+				file_free(file);+				*filepp = NULL; 				return (ARCHIVE_FATAL);+			} 			file_add_child_tail(dent, vp); 			file_register(xar, vp); 			np = vp;@@ -2526,7 +2555,7 @@ static int file_register_hardlink(struct archive_write *a, struct file *file) {-	struct xar *xar = (struct xar *)a->format_data;+	struct xar *xar = a->format_data; 	struct hardlink *hl; 	const char *pathname; @@ -2648,6 +2677,16 @@ 	case CKSUM_MD5: 		archive_md5_init(&(sumwrk->md5ctx)); 		break;+#ifdef ARCHIVE_HAS_SHA256+	case CKSUM_SHA256:+		archive_sha256_init(&(sumwrk->sha256ctx));+		break;+#endif+#ifdef ARCHIVE_HAS_SHA512+	case CKSUM_SHA512:+		archive_sha512_init(&(sumwrk->sha512ctx));+		break;+#endif 	} } @@ -2664,6 +2703,16 @@ 	case CKSUM_MD5: 		archive_md5_update(&(sumwrk->md5ctx), buff, size); 		break;+#ifdef ARCHIVE_HAS_SHA256+	case CKSUM_SHA256:+		archive_sha256_update(&(sumwrk->sha256ctx), buff, size);+		break;+#endif+#ifdef ARCHIVE_HAS_SHA512+	case CKSUM_SHA512:+		archive_sha512_update(&(sumwrk->sha512ctx), buff, size);+		break;+#endif 	} } @@ -2683,6 +2732,18 @@ 		archive_md5_final(&(sumwrk->md5ctx), sumval->val); 		sumval->len = MD5_SIZE; 		break;+#ifdef ARCHIVE_HAS_SHA256+	case CKSUM_SHA256:+		archive_sha256_final(&(sumwrk->sha256ctx), sumval->val);+		sumval->len = SHA256_SIZE;+		break;+#endif+#ifdef ARCHIVE_HAS_SHA512+	case CKSUM_SHA512:+		archive_sha512_final(&(sumwrk->sha512ctx), sumval->val);+		sumval->len = SHA512_SIZE;+		break;+#endif 	} 	sumval->alg = sumwrk->alg; }@@ -3132,10 +3193,9 @@ static int xar_compression_init_encoder(struct archive_write *a) {-	struct xar *xar;+	struct xar *xar = a->format_data; 	int r; -	xar = (struct xar *)a->format_data; 	switch (xar->opt_compression) { 	case GZIP: 		r = compression_init_encoder_gzip(@@ -3192,14 +3252,13 @@ static int save_xattrs(struct archive_write *a, struct file *file) {-	struct xar *xar;+	struct xar *xar = a->format_data; 	const char *name; 	const void *value; 	struct heap_data *heap; 	size_t size; 	int count, r; -	xar = (struct xar *)a->format_data; 	count = archive_entry_xattr_reset(file->entry); 	if (count == 0) 		return (ARCHIVE_OK);@@ -3211,6 +3270,12 @@  		heap = calloc(1, sizeof(*heap)); 		if (heap == NULL) {+			struct chksumval sumval;++			checksum_final(&(xar->a_sumwrk), &sumval);+			checksum_final(&(xar->e_sumwrk), &sumval);+			xar->a_sumwrk.alg = CKSUM_NONE;+			xar->e_sumwrk.alg = CKSUM_NONE; 			archive_set_error(&a->archive, ENOMEM, 			    "Can't allocate memory for xattr"); 			return (ARCHIVE_FATAL);@@ -3248,6 +3313,10 @@ 		 */ 		r = xar_compression_init_encoder(a); 		if (r != ARCHIVE_OK) {+			struct chksumval sumval;++			checksum_final(&(xar->a_sumwrk), &sumval);+			xar->a_sumwrk.alg = CKSUM_NONE; 			free(heap); 			return (ARCHIVE_FATAL); 		}@@ -3302,6 +3371,10 @@ 		return (SHA1_SIZE); 	case CKSUM_MD5: 		return (MD5_SIZE);+	case CKSUM_SHA256:+		return (SHA256_SIZE);+	case CKSUM_SHA512:+		return (SHA512_SIZE); 	} } @@ -3316,6 +3389,10 @@ 		return (SHA1_NAME); 	case CKSUM_MD5: 		return (MD5_NAME);+	case CKSUM_SHA256:+		return (SHA256_NAME);+	case CKSUM_SHA512:+		return (SHA512_NAME); 	} } 
c/archive_write_set_format_zip.c view
@@ -68,6 +68,7 @@ #include "archive_entry.h" #include "archive_entry_locale.h" #include "archive_hmac_private.h"+#include "archive_integer.h" #include "archive_private.h" #include "archive_random_private.h" #include "archive_time_private.h"@@ -154,7 +155,6 @@ 	enum compression entry_compression; 	enum encryption  entry_encryption; 	int entry_flags;-	int experiments; 	struct trad_enc_ctx tctx; 	char tctx_valid; 	unsigned char trad_chkdat;@@ -235,7 +235,6 @@ 	      struct archive_entry *); static int archive_write_zip_options(struct archive_write *, 	      const char *, const char *);-static size_t path_length(struct archive_entry *); static int write_path(struct archive_entry *, struct archive_write *); static void copy_path(struct archive_entry *, unsigned char *); static struct archive_string_conv *get_sconv(struct archive_write *, struct zip *);@@ -730,8 +729,7 @@ 	    ARCHIVE_STATE_NEW, "archive_write_set_format_zip");  	/* If another format was already registered, unregister it. */-	if (a->format_free != NULL)-		(a->format_free)(a);+	(void)__archive_write_unregister_format(a);  	zip = calloc(1, sizeof(*zip)); 	if (zip == NULL) {@@ -791,9 +789,9 @@ static int archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) {+	struct zip *zip = a->format_data; 	unsigned char local_header[32]; 	unsigned char local_extra[144];-	struct zip *zip = a->format_data; 	unsigned char *e; 	unsigned char *cd_extra; 	size_t filename_length;@@ -959,8 +957,6 @@ #endif 		} 	}-	filename_length = path_length(zip->entry);- 	/* Reject empty or overlong pathnames */ 	path = archive_entry_pathname(zip->entry); 	if (path == NULL || path[0] == '\0') {@@ -968,6 +964,10 @@ 		    "ZIP format requires a non-empty pathname"); 		return (ARCHIVE_FAILED); 	}+	filename_length = strlen(path);+	/* Include the trailing slash added to directories. */+	if (type == AE_IFDIR && path[filename_length - 1] != '/')+		filename_length++; 	if (filename_length > 0xffff) { 		archive_set_error(&a->archive, ENAMETOOLONG, 		    "Pathname too long for ZIP format");@@ -1066,8 +1066,13 @@ 			default: 				break; 			}-			if (zip->entry_compression == COMPRESSION_STORE)-				zip->entry_compressed_size += additional_size;+			if (zip->entry_compression == COMPRESSION_STORE &&+			    archive_ckd_add_i64(&zip->entry_compressed_size,+				zip->entry_compressed_size, additional_size)) {+				archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,+				    "File size too large for encrypted ZIP entry");+				return (ARCHIVE_FAILED);+			} 		}  		/*@@ -1081,7 +1086,7 @@ 		 *    (compression might make file larger) 		 */ 		if ((zip->flags & ZIP_FLAG_FORCE_ZIP64)-		    || (zip->entry_uncompressed_size + additional_size > ZIP_4GB_MAX)+		    || (zip->entry_uncompressed_size > ZIP_4GB_MAX - additional_size) 		    || (zip->entry_uncompressed_size > ZIP_4GB_MAX_UNCOMPRESSED 			&& zip->entry_compression != COMPRESSION_STORE)) { 			MIN_VERSION_NEEDED(45);@@ -1515,8 +1520,8 @@ static ssize_t archive_write_zip_data(struct archive_write *a, const void *buff, size_t s) {-	int ret; 	struct zip *zip = a->format_data;+	int ret;  	if ((int64_t)s > zip->entry_uncompressed_limit) 		s = (size_t)zip->entry_uncompressed_limit;@@ -2184,9 +2189,9 @@ static int archive_write_zip_close(struct archive_write *a) {+	struct zip *zip = a->format_data; 	uint8_t buff[64]; 	int64_t offset_start, offset_end;-	struct zip *zip = a->format_data; 	struct cd_segment *segment; 	int ret; @@ -2256,10 +2261,9 @@ static int archive_write_zip_free(struct archive_write *a) {-	struct zip *zip;+	struct zip *zip = a->format_data; 	struct cd_segment *segment; -	zip = a->format_data; 	while (zip->central_directory != NULL) { 		segment = zip->central_directory; 		zip->central_directory = segment->next;@@ -2277,24 +2281,6 @@ 	free(zip); 	a->format_data = NULL; 	return (ARCHIVE_OK);-}--static size_t-path_length(struct archive_entry *entry)-{-	mode_t type;-	const char *path;-	size_t len;--	type = archive_entry_filetype(entry);-	path = archive_entry_pathname(entry);--	if (path == NULL)-		return (0);-	len = strlen(path);-	if (type == AE_IFDIR && (path[0] == '\0' || path[len - 1] != '/'))-		++len; /* Space for the trailing / */-	return len; }  static int
libarchive-clib.cabal view
@@ -2,7 +2,7 @@ name:               libarchive-clib -- this is actually corresponding to upstream's 3.8.6, -- but we had to fix configure.ac and PVP has no patch versions-version:            3.8.8+version:            3.8.9 license:            BSD-2-Clause license-file:       LICENSE copyright:          Copyright: (c) 2018-2020 Vanessa McHale