diff --git a/c/archive.h b/c/archive.h
--- a/c/archive.h
+++ b/c/archive.h
@@ -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 3008006
+#define	ARCHIVE_VERSION_NUMBER 3008007
 
 #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.6"
+#define	ARCHIVE_VERSION_ONLY_STRING "3.8.7"
 #define	ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
 __LA_DECL const char *	archive_version_string(void);
 
diff --git a/c/archive_check_magic.c b/c/archive_check_magic.c
--- a/c/archive_check_magic.c
+++ b/c/archive_check_magic.c
@@ -148,14 +148,14 @@
 	if (!handle_type) {
 		errmsg("PROGRAMMER ERROR: Function ");
 		errmsg(function);
-		errmsg(" invoked with invalid archive handle.\n");
+		errmsg(" invoked with invalid archive handle\n");
 		diediedie();
 	}
 
 	if (a->magic != magic) {
 		archive_set_error(a, -1,
 		    "PROGRAMMER ERROR: Function '%s' invoked"
-		    " on '%s' archive object, which is not supported.",
+		    " on '%s' archive object, which is not supported",
 		    function,
 		    handle_type);
 		a->state = ARCHIVE_STATE_FATAL;
diff --git a/c/archive_entry.h b/c/archive_entry.h
--- a/c/archive_entry.h
+++ b/c/archive_entry.h
@@ -28,7 +28,7 @@
 #define	ARCHIVE_ENTRY_H_INCLUDED
 
 /* Note: Compiler will complain if this does not match archive.h! */
-#define	ARCHIVE_VERSION_NUMBER 3008006
+#define	ARCHIVE_VERSION_NUMBER 3008007
 
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
diff --git a/c/archive_options.c b/c/archive_options.c
--- a/c/archive_options.c
+++ b/c/archive_options.c
@@ -90,7 +90,9 @@
 	if (r2 == ARCHIVE_FATAL)
 		return (ARCHIVE_FATAL);
 
-	if (r2 == ARCHIVE_WARN - 1)
+	if (r1 == ARCHIVE_WARN - 1)
+		return r2;
+	if (r2 == ARCHIVE_WARN -1)
 		return r1;
 	return r1 > r2 ? r1 : r2;
 }
diff --git a/c/archive_pathmatch.c b/c/archive_pathmatch.c
--- a/c/archive_pathmatch.c
+++ b/c/archive_pathmatch.c
@@ -202,7 +202,7 @@
 			if (*p == '\0')
 				return (1);
 			while (*s) {
-				if (archive_pathmatch(p, s, flags))
+				if (pm(p, s, flags))
 					return (1);
 				++s;
 			}
@@ -307,7 +307,7 @@
 			if (*p == L'\0')
 				return (1);
 			while (*s) {
-				if (archive_pathmatch_w(p, s, flags))
+				if (pm_w(p, s, flags))
 					return (1);
 				++s;
 			}
diff --git a/c/archive_ppmd8.c b/c/archive_ppmd8.c
--- a/c/archive_ppmd8.c
+++ b/c/archive_ppmd8.c
@@ -61,7 +61,7 @@
 
 #define EMPTY_NODE 0xFFFFFFFF
 
-void Ppmd8_Construct(CPpmd8 *p)
+static void Ppmd8_Construct(CPpmd8 *p)
 {
   unsigned i, k, m;
 
@@ -89,14 +89,14 @@
   }
 }
 
-void Ppmd8_Free(CPpmd8 *p)
+static void Ppmd8_Free(CPpmd8 *p)
 {
   free(p->Base);
   p->Size = 0;
   p->Base = 0;
 }
 
-Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size)
+static Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size)
 {
   if (p->Base == 0 || p->Size != size)
   {
@@ -407,7 +407,7 @@
   }
 }
 
-void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod)
+static void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod)
 {
   p->MaxOrder = maxOrder;
   p->RestoreMethod = restoreMethod;
@@ -1042,7 +1042,7 @@
   p->FoundState = STATS(p->MinContext);
 }
 
-CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq)
+static CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq)
 {
   CPpmd_See *see;
   if (p->MinContext->NumStats != 0xFF)
@@ -1078,7 +1078,7 @@
   }
 }
 
-void Ppmd8_Update1(CPpmd8 *p)
+static void Ppmd8_Update1(CPpmd8 *p)
 {
   CPpmd_State *s = p->FoundState;
   s->Freq += 4;
@@ -1093,7 +1093,7 @@
   NextContext(p);
 }
 
-void Ppmd8_Update1_0(CPpmd8 *p)
+static void Ppmd8_Update1_0(CPpmd8 *p)
 {
   p->PrevSuccess = (2 * p->FoundState->Freq >= p->MinContext->SummFreq);
   p->RunLength += p->PrevSuccess;
@@ -1103,7 +1103,7 @@
   NextContext(p);
 }
 
-void Ppmd8_UpdateBin(CPpmd8 *p)
+static void Ppmd8_UpdateBin(CPpmd8 *p)
 {
   p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 196));
   p->PrevSuccess = 1;
@@ -1111,7 +1111,7 @@
   NextContext(p);
 }
 
-void Ppmd8_Update2(CPpmd8 *p)
+static void Ppmd8_Update2(CPpmd8 *p)
 {
   p->MinContext->SummFreq += 4;
   if ((p->FoundState->Freq += 4) > MAX_FREQ)
@@ -1127,7 +1127,7 @@
   PPMd var.I (2002): Dmitry Shkarin : Public domain
   Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
 
-Bool Ppmd8_RangeDec_Init(CPpmd8 *p)
+static Bool Ppmd8_RangeDec_Init(CPpmd8 *p)
 {
   unsigned i;
   p->Low = 0;
@@ -1161,7 +1161,7 @@
 
 #define MASK(sym) ((signed char *)charMask)[sym]
 
-int Ppmd8_DecodeSymbol(CPpmd8 *p)
+static int Ppmd8_DecodeSymbol(CPpmd8 *p)
 {
   size_t charMask[256 / sizeof(size_t)];
   if (p->MinContext->NumStats != 0)
diff --git a/c/archive_ppmd8_private.h b/c/archive_ppmd8_private.h
--- a/c/archive_ppmd8_private.h
+++ b/c/archive_ppmd8_private.h
@@ -83,13 +83,7 @@
   UInt16 BinSumm[25][64];
 } CPpmd8;
 
-void Ppmd8_Construct(CPpmd8 *p);
-Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size);
-void Ppmd8_Free(CPpmd8 *p);
-void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod);
-#define Ppmd8_WasAllocated(p) ((p)->Base != NULL)
 
-
 /* ---------- Internal Functions ---------- */
 
 extern const Byte PPMD8_kExpEscape[16];
@@ -104,30 +98,11 @@
   #define Ppmd8_GetStats(p, ctx) ((CPpmd_State *)Ppmd8_GetPtr((p), ((ctx)->Stats)))
 #endif
 
-void Ppmd8_Update1(CPpmd8 *p);
-void Ppmd8_Update1_0(CPpmd8 *p);
-void Ppmd8_Update2(CPpmd8 *p);
-void Ppmd8_UpdateBin(CPpmd8 *p);
-
 #define Ppmd8_GetBinSumm(p) \
     &p->BinSumm[p->NS2Indx[Ppmd8Context_OneState(p->MinContext)->Freq - 1]][ \
     p->NS2BSIndx[Ppmd8_GetContext(p, p->MinContext->Suffix)->NumStats] + \
     p->PrevSuccess + p->MinContext->Flags + ((p->RunLength >> 26) & 0x20)]
 
-CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked, UInt32 *scale);
-
-
-/* ---------- Decode ---------- */
-
-Bool Ppmd8_RangeDec_Init(CPpmd8 *p);
-#define Ppmd8_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
-int Ppmd8_DecodeSymbol(CPpmd8 *p); /* returns: -1 as EndMarker, -2 as DataError */
-
-/* ---------- Encode ---------- */
-
-#define Ppmd8_RangeEnc_Init(p) { (p)->Low = 0; (p)->Range = 0xFFFFFFFF; }
-void Ppmd8_RangeEnc_FlushData(CPpmd8 *p);
-void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol); /* symbol = -1 means EndMarker */
 
 typedef struct
 {
diff --git a/c/archive_read.c b/c/archive_read.c
--- a/c/archive_read.c
+++ b/c/archive_read.c
@@ -171,7 +171,7 @@
 client_skip_proxy(struct archive_read_filter *self, int64_t request)
 {
 	if (request < 0)
-		__archive_errx(1, "Negative skip requested.");
+		__archive_errx(1, "Negative skip requested");
 	if (request == 0)
 		return 0;
 
@@ -379,7 +379,7 @@
 		if (a->client.dataset == NULL)
 		{
 			archive_set_error(&a->archive, ENOMEM,
-				"No memory.");
+				"No memory");
 			return ARCHIVE_FATAL;
 		}
 		a->client.nodes = 1;
@@ -388,7 +388,7 @@
 	if (iindex > a->client.nodes - 1)
 	{
 		archive_set_error(&a->archive, EINVAL,
-			"Invalid index specified.");
+			"Invalid index specified");
 		return ARCHIVE_FATAL;
 	}
 	a->client.dataset[iindex].data = client_data;
@@ -409,14 +409,14 @@
 	    "archive_read_add_callback_data");
 	if (iindex > a->client.nodes) {
 		archive_set_error(&a->archive, EINVAL,
-			"Invalid index specified.");
+			"Invalid index specified");
 		return ARCHIVE_FATAL;
 	}
 	p = realloc(a->client.dataset, sizeof(*a->client.dataset)
 		* (++(a->client.nodes)));
 	if (p == NULL) {
 		archive_set_error(&a->archive, ENOMEM,
-			"No memory.");
+			"No memory");
 		return ARCHIVE_FATAL;
 	}
 	a->client.dataset = (struct archive_read_data_node *)p;
@@ -625,7 +625,7 @@
 		r1 = archive_read_data_skip(&a->archive);
 		if (r1 == ARCHIVE_EOF)
 			archive_set_error(&a->archive, EIO,
-			    "Premature end-of-file.");
+			    "Premature end-of-file");
 		if (r1 == ARCHIVE_EOF || r1 == ARCHIVE_FATAL) {
 			a->archive.state = ARCHIVE_STATE_FATAL;
 			return (ARCHIVE_FATAL);
diff --git a/c/archive_read_append_filter.c b/c/archive_read_append_filter.c
--- a/c/archive_read_append_filter.c
+++ b/c/archive_read_append_filter.c
@@ -104,6 +104,10 @@
       strcpy(str, "lrzip");
       r1 = archive_read_support_filter_lrzip(_a);
       break;
+    case ARCHIVE_FILTER_GRZIP:
+      strcpy(str, "grzip");
+      r1 = archive_read_support_filter_grzip(_a);
+      break;
     default:
       archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
           "Invalid filter code specified");
diff --git a/c/archive_read_disk_posix.c b/c/archive_read_disk_posix.c
--- a/c/archive_read_disk_posix.c
+++ b/c/archive_read_disk_posix.c
@@ -921,7 +921,7 @@
 		r = archive_match_path_excluded(a->matching, entry);
 		if (r < 0) {
 			archive_set_error(&(a->archive), errno,
-			    "Failed : %s", archive_error_string(a->matching));
+			    "%s", archive_error_string(a->matching));
 			return (r);
 		}
 		if (r) {
@@ -1035,7 +1035,7 @@
 		r = archive_match_time_excluded(a->matching, entry);
 		if (r < 0) {
 			archive_set_error(&(a->archive), errno,
-			    "Failed : %s", archive_error_string(a->matching));
+			    "%s", archive_error_string(a->matching));
 			return (r);
 		}
 		if (r) {
@@ -1061,7 +1061,7 @@
 		r = archive_match_owner_excluded(a->matching, entry);
 		if (r < 0) {
 			archive_set_error(&(a->archive), errno,
-			    "Failed : %s", archive_error_string(a->matching));
+			    "%s", archive_error_string(a->matching));
 			return (r);
 		}
 		if (r) {
diff --git a/c/archive_read_disk_windows.c b/c/archive_read_disk_windows.c
--- a/c/archive_read_disk_windows.c
+++ b/c/archive_read_disk_windows.c
@@ -947,7 +947,7 @@
 		r = archive_match_path_excluded(a->matching, entry);
 		if (r < 0) {
 			archive_set_error(&(a->archive), errno,
-			    "Failed : %s", archive_error_string(a->matching));
+			    "%s", archive_error_string(a->matching));
 			return (r);
 		}
 		if (r) {
@@ -1019,7 +1019,7 @@
 		r = archive_match_time_excluded(a->matching, entry);
 		if (r < 0) {
 			archive_set_error(&(a->archive), errno,
-			    "Failed : %s", archive_error_string(a->matching));
+			    "%s", archive_error_string(a->matching));
 			return (r);
 		}
 		if (r) {
@@ -1045,7 +1045,7 @@
 		r = archive_match_owner_excluded(a->matching, entry);
 		if (r < 0) {
 			archive_set_error(&(a->archive), errno,
-			    "Failed : %s", archive_error_string(a->matching));
+			    "%s", archive_error_string(a->matching));
 			return (r);
 		}
 		if (r) {
diff --git a/c/archive_read_support_filter_grzip.c b/c/archive_read_support_filter_grzip.c
--- a/c/archive_read_support_filter_grzip.c
+++ b/c/archive_read_support_filter_grzip.c
@@ -62,7 +62,7 @@
 {
 	struct archive_read *a = (struct archive_read *)_a;
 
-	if (__archive_read_register_bidder(a, NULL, NULL,
+	if (__archive_read_register_bidder(a, NULL, "grzip",
 				&grzip_bidder_vtable) != ARCHIVE_OK)
 		return (ARCHIVE_FATAL);
 
diff --git a/c/archive_read_support_filter_lz4.c b/c/archive_read_support_filter_lz4.c
--- a/c/archive_read_support_filter_lz4.c
+++ b/c/archive_read_support_filter_lz4.c
@@ -363,7 +363,7 @@
 	case READ_LEGACY_STREAM:
 		/* Reading a lz4 stream already failed. */
 		archive_set_error(&self->archive->archive,
-		    ARCHIVE_ERRNO_MISC, "Invalid sequence.");
+		    ARCHIVE_ERRNO_MISC, "Invalid sequence");
 		return (ARCHIVE_FATAL);
 	case READ_DEFAULT_BLOCK:
 		ret = lz4_filter_read_default_stream(self, p);
@@ -377,7 +377,7 @@
 		break;
 	default:
 		archive_set_error(&self->archive->archive,
-		    ARCHIVE_ERRNO_MISC, "Program error.");
+		    ARCHIVE_ERRNO_MISC, "Program error");
 		return (ARCHIVE_FATAL);
 	}
 
diff --git a/c/archive_read_support_filter_lzop.c b/c/archive_read_support_filter_lzop.c
--- a/c/archive_read_support_filter_lzop.c
+++ b/c/archive_read_support_filter_lzop.c
@@ -110,7 +110,7 @@
 {
 	struct archive_read *a = (struct archive_read *)_a;
 
-	if (__archive_read_register_bidder(a, NULL, NULL,
+	if (__archive_read_register_bidder(a, NULL, "lzop",
 				&lzop_bidder_vtable) != ARCHIVE_OK)
 		return (ARCHIVE_FATAL);
 
diff --git a/c/archive_read_support_format_7zip.c b/c/archive_read_support_format_7zip.c
--- a/c/archive_read_support_format_7zip.c
+++ b/c/archive_read_support_format_7zip.c
@@ -975,7 +975,7 @@
 		archive_set_error(&a->archive,
 		    ARCHIVE_ERRNO_FILE_FORMAT,
 		    "Pathname cannot be converted "
-		    "from %s to current locale.",
+		    "from %s to current locale",
 		    archive_string_conversion_charset_name(zip->sconv));
 		ret = ARCHIVE_WARN;
 	}
@@ -1581,7 +1581,7 @@
 			    -15 /* Don't check for zlib header */);
 		if (r != Z_OK) {
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "Couldn't initialize zlib stream.");
+			    "Couldn't initialize zlib stream");
 			return (ARCHIVE_FAILED);
 		}
 		zip->stream_valid = 1;
@@ -1723,7 +1723,7 @@
 			if (bytes < 0) {
 				archive_set_error(&(a->archive),
 				    ARCHIVE_ERRNO_MISC,
-				    "BCJ2 conversion Failed");
+				    "BCJ2 conversion failed");
 				return (ARCHIVE_FAILED);
 			}
 			zip->main_stream_bytes_remaining -=
@@ -1777,7 +1777,7 @@
 		default:
 			archive_set_error(&(a->archive),
 			    ARCHIVE_ERRNO_MISC,
-				"Decompression failed(%d)",
+				"Decompression failed (%d)",
 			    r);
 			return (ARCHIVE_FAILED);
 		}
@@ -1979,7 +1979,7 @@
 		bytes = Bcj2_Decode(zip, bcj2_next_out, bcj2_avail_out);
 		if (bytes < 0) {
 			archive_set_error(&(a->archive),
-			    ARCHIVE_ERRNO_MISC, "BCJ2 conversion Failed");
+			    ARCHIVE_ERRNO_MISC, "BCJ2 conversion failed");
 			return (ARCHIVE_FAILED);
 		}
 		zip->main_stream_bytes_remaining -=
diff --git a/c/archive_read_support_format_cab.c b/c/archive_read_support_format_cab.c
--- a/c/archive_read_support_format_cab.c
+++ b/c/archive_read_support_format_cab.c
@@ -980,7 +980,7 @@
 		archive_set_error(&a->archive,
 		    ARCHIVE_ERRNO_FILE_FORMAT,
 		    "Pathname cannot be converted "
-		    "from %s to current locale.",
+		    "from %s to current locale",
 		    archive_string_conversion_charset_name(sconv));
 		err = ARCHIVE_WARN;
 	}
@@ -1026,7 +1026,7 @@
 		*offset = 0;
 		archive_clear_error(&a->archive);
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-		    "Cannot restore this file split in multivolume.");
+		    "Cannot restore this file split in multivolume");
 		return (ARCHIVE_FAILED);
 	default:
 		break;
@@ -1175,6 +1175,9 @@
 	l = 4;
 	if (cab->cfheader.flags & RESERVE_PRESENT)
 		l += cab->cfheader.cfdata;
+	if (cfdata->memimage == NULL) {
+		return (ARCHIVE_FAILED);
+	}
 	cfdata->sum_calculated = cab_checksum_cfdata(
 	    cfdata->memimage + CFDATA_cbData, l, cfdata->sum_calculated);
 	if (cfdata->sum_calculated != cfdata->sum) {
@@ -1362,7 +1365,7 @@
 		return (cab_read_ahead_cfdata_lzx(a, avail));
 	default: /* Unsupported compression. */
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-		    "Unsupported CAB compression : %s",
+		    "Unsupported CAB compression: %s",
 		    cab->entry_cffolder->compname);
 		*avail = ARCHIVE_FAILED;
 		return (NULL);
@@ -1449,7 +1452,7 @@
 			    -15 /* Don't check for zlib header */);
 		if (r != Z_OK) {
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "Can't initialize deflate decompression.");
+			    "Can't initialize deflate decompression");
 			*avail = ARCHIVE_FATAL;
 			return (NULL);
 		}
@@ -1669,7 +1672,7 @@
 		    cab->entry_cffolder->compdata);
 		if (r != ARCHIVE_OK) {
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "Can't initialize LZX decompression.");
+			    "Can't initialize LZX decompression");
 			*avail = ARCHIVE_FATAL;
 			return (NULL);
 		}
@@ -1687,6 +1690,13 @@
 		    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) {
diff --git a/c/archive_read_support_format_cpio.c b/c/archive_read_support_format_cpio.c
--- a/c/archive_read_support_format_cpio.c
+++ b/c/archive_read_support_format_cpio.c
@@ -397,7 +397,7 @@
 			return (ARCHIVE_FATAL);
 		}
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-		    "Pathname can't be converted from %s to current locale.",
+		    "Pathname can't be converted from %s to current locale",
 		    archive_string_conversion_charset_name(sconv));
 		r = ARCHIVE_WARN;
 	}
@@ -426,7 +426,7 @@
 			archive_set_error(&a->archive,
 			    ARCHIVE_ERRNO_FILE_FORMAT,
 			    "Linkname can't be converted from %s to "
-			    "current locale.",
+			    "current locale",
 			    archive_string_conversion_charset_name(sconv));
 			r = ARCHIVE_WARN;
 		}
diff --git a/c/archive_read_support_format_iso9660.c b/c/archive_read_support_format_iso9660.c
--- a/c/archive_read_support_format_iso9660.c
+++ b/c/archive_read_support_format_iso9660.c
@@ -1322,7 +1322,7 @@
 			archive_set_error(&a->archive,
 			    ARCHIVE_ERRNO_FILE_FORMAT,
 			    "Pathname cannot be converted "
-			    "from %s to current locale.",
+			    "from %s to current locale",
 			    archive_string_conversion_charset_name(
 			      iso9660->sconv_utf16be));
 
@@ -1400,7 +1400,7 @@
 				archive_set_error(&a->archive,
 				    ARCHIVE_ERRNO_FILE_FORMAT,
 				    "Linkname cannot be converted "
-				    "from %s to current locale.",
+				    "from %s to current locale",
 				    archive_string_conversion_charset_name(
 				      iso9660->sconv_utf16be));
 				rd_r = ARCHIVE_WARN;
@@ -1663,7 +1663,7 @@
 			r = inflateInit(&zisofs->stream);
 		if (r != Z_OK) {
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "Can't initialize zisofs decompression.");
+			    "Can't initialize zisofs decompression");
 			return (ARCHIVE_FATAL);
 		}
 		zisofs->stream_valid = 1;
@@ -1728,7 +1728,7 @@
 	(void)size;/* UNUSED */
 	(void)offset;/* UNUSED */
 	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-	    "zisofs is not supported on this platform.");
+	    "zisofs is not supported on this platform");
 	return (ARCHIVE_FAILED);
 }
 
@@ -2756,11 +2756,19 @@
 {
 
 	if (data[0] == 0x70 && data[1] == 0x7a && data_length == 12) {
-		/* paged zlib */
-		file->pz = 1;
-		file->pz_log2_bs = data[3];
-		file->pz_uncompressed_size = archive_le32dec(&data[4]);
-	}
+        /* paged zlib */
+        file->pz = 1;
+        file->pz_log2_bs = data[3];
+        if (file->pz_log2_bs < 15 || file->pz_log2_bs > 17) {
+            /* TODO: Return an error here instead of silently
+             * disabling zisofs. That requires propagating an
+             * error return through parse_rockridge() and its
+             * callers. */
+            file->pz = 0;
+            return;
+        }
+        file->pz_uncompressed_size = archive_le32dec(&data[4]);
+    }
 }
 
 static void
diff --git a/c/archive_read_support_format_lha.c b/c/archive_read_support_format_lha.c
--- a/c/archive_read_support_format_lha.c
+++ b/c/archive_read_support_format_lha.c
@@ -613,7 +613,7 @@
 		archive_set_error(&a->archive,
 			ARCHIVE_ERRNO_FILE_FORMAT,
 			"Pathname cannot be converted "
-			"from %s to Unicode.",
+			"from %s to Unicode",
 			archive_string_conversion_charset_name(lha->sconv_dir));
 		err = ARCHIVE_FATAL;
 	} else if (0 != archive_mstring_get_wcs(&a->archive, &conv_buffer, &conv_buffer_p))
@@ -634,7 +634,7 @@
 		archive_set_error(&a->archive,
 			ARCHIVE_ERRNO_FILE_FORMAT,
 			"Pathname cannot be converted "
-			"from %s to Unicode.",
+			"from %s to Unicode",
 			archive_string_conversion_charset_name(lha->sconv_fname));
 		err = ARCHIVE_FATAL;
 	}
diff --git a/c/archive_read_support_format_rar.c b/c/archive_read_support_format_rar.c
--- a/c/archive_read_support_format_rar.c
+++ b/c/archive_read_support_format_rar.c
@@ -955,7 +955,7 @@
 
     if ((h = __archive_read_ahead(a, 7, NULL)) == NULL) {
       archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                        "Failed to read next header.");
+                        "Failed to read next header");
       return (ARCHIVE_FATAL);
     }
     p = h;
@@ -1005,7 +1005,7 @@
         archive_entry_set_is_data_encrypted(entry, 1);
         rar->has_encrypted_entries = 1;
          archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                          "RAR encryption support unavailable.");
+                          "RAR encryption support unavailable");
         return (ARCHIVE_FATAL);
       }
 
@@ -1141,7 +1141,7 @@
 
   default:
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                      "Unsupported compression method for RAR file.");
+                      "Unsupported compression method for RAR file");
     ret = ARCHIVE_FATAL;
     break;
   }
@@ -1432,14 +1432,14 @@
   else
   {
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                      "RAR solid archive support unavailable.");
+                      "RAR solid archive support unavailable");
     return (ARCHIVE_FATAL);
   }
 
   if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL)
   {
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                      "Failed to read full header content.");
+                      "Failed to read full header content");
     return (ARCHIVE_FATAL);
   }
 
@@ -1471,7 +1471,7 @@
     archive_entry_set_is_data_encrypted(entry, 1);
     rar->has_encrypted_entries = 1;
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                      "RAR encryption support unavailable.");
+                      "RAR encryption support unavailable");
     /* Since it is only the data part itself that is encrypted we can at least
        extract information about the currently processed entry and don't need
        to return ARCHIVE_FATAL here. */
@@ -1503,7 +1503,7 @@
   if (rar->packed_size < 0 || rar->unp_size < 0)
   {
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                      "Invalid sizes specified.");
+                      "Invalid sizes specified");
     return (ARCHIVE_FATAL);
   }
 
@@ -1516,19 +1516,19 @@
     size_t distance = p - (const char *)h;
     if (rar->packed_size > INT64_MAX - header_size) {
       archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                        "Extended header size too large.");
+                        "Extended header size too large");
       return (ARCHIVE_FATAL);
     }
     header_size += rar->packed_size;
     if ((uintmax_t)header_size > SIZE_MAX) {
       archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                        "Unable to read extended header data.");
+                        "Unable to read extended header data");
       return (ARCHIVE_FATAL);
     }
     /* Make sure we have the extended data. */
     if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL) {
       archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                        "Failed to read extended header data.");
+                        "Failed to read extended header data");
       return (ARCHIVE_FATAL);
     }
     p = h;
@@ -1547,7 +1547,7 @@
     newptr = realloc(rar->filename, newsize);
     if (newptr == NULL) {
       archive_set_error(&a->archive, ENOMEM,
-                        "Couldn't allocate memory.");
+                        "Couldn't allocate memory");
       return (ARCHIVE_FATAL);
     }
     rar->filename = newptr;
@@ -1701,7 +1701,7 @@
       newsize = sizeof(*rar->dbo) * (rar->nodes + 1);
       if ((newdbo = realloc(rar->dbo, newsize)) == NULL)
       {
-        archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory.");
+        archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory");
         return (ARCHIVE_FATAL);
       }
       rar->dbo = newdbo;
@@ -1715,7 +1715,7 @@
       if (rar->packed_size > INT64_MAX - a->filter->position)
       {
         archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                          "Unable to store offsets.");
+                          "Unable to store offsets");
         return (ARCHIVE_FATAL);
       }
       rar->dbo[rar->cursor].start_offset = a->filter->position;
@@ -1734,7 +1734,7 @@
   newsize = filename_size + 1;
   if ((newptr = realloc(rar->filename_save, newsize)) == NULL)
   {
-    archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory.");
+    archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory");
     return (ARCHIVE_FATAL);
   }
   rar->filename_save = newptr;
@@ -1745,7 +1745,7 @@
   free(rar->dbo);
   if ((rar->dbo = calloc(1, sizeof(*rar->dbo))) == NULL)
   {
-    archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory.");
+    archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory");
     return (ARCHIVE_FATAL);
   }
   rar->dbo[0].header_size = header_size;
@@ -1776,7 +1776,7 @@
   __archive_read_consume(a, header_size - 7);
   if (rar->packed_size > INT64_MAX - a->filter->position) {
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                      "Unable to store offsets.");
+                      "Unable to store offsets");
     return (ARCHIVE_FATAL);
   }
   rar->dbo[0].start_offset = a->filter->position;
@@ -1848,7 +1848,7 @@
       return (ARCHIVE_FATAL);
     }
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                      "Pathname cannot be converted from %s to current locale.",
+                      "Pathname cannot be converted from %s to current locale",
                       archive_string_conversion_charset_name(fn_sconv));
     ret = (ARCHIVE_WARN);
   }
@@ -1979,13 +1979,13 @@
   if ((uintmax_t)rar->packed_size > SIZE_MAX)
   {
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                      "Unable to read link.");
+                      "Unable to read link");
     return (ARCHIVE_FATAL);
   }
   if ((h = rar_read_ahead(a, (size_t)rar->packed_size, NULL)) == NULL)
   {
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                      "Failed to read link.");
+                      "Failed to read link");
     return (ARCHIVE_FATAL);
   }
   p = h;
@@ -2000,7 +2000,7 @@
       return (ARCHIVE_FATAL);
     }
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                      "link cannot be converted from %s to current locale.",
+                      "link cannot be converted from %s to current locale",
                       archive_string_conversion_charset_name(sconv));
     ret = (ARCHIVE_WARN);
   }
@@ -2201,7 +2201,7 @@
 
           case 3:
             archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                              "Parsing filters is unsupported.");
+                              "Parsing filters is unsupported");
             return (ARCHIVE_FAILED);
 
           case 4:
@@ -2473,7 +2473,7 @@
           free(precode.tree);
           free(precode.table);
           archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                            "Internal error extracting RAR file.");
+                            "Internal error extracting RAR file");
           return (ARCHIVE_FATAL);
         }
 
@@ -2548,7 +2548,8 @@
       return (r);
   }
 
-  if (!rar->dictionary_size || !rar->lzss.window)
+  if (!rar->dictionary_size || !rar->lzss.window ||
+      (unsigned int)(rar->lzss.mask + 1) < rar->dictionary_size)
   {
     /* Seems as though dictionary sizes are not used. Even so, minimize
      * memory usage as much as possible.
@@ -2562,13 +2563,13 @@
       new_size = rar_fls((unsigned int)rar->unp_size) << 1;
     if (new_size == 0) {
       archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                        "Zero window size is invalid.");
+                        "Zero window size is invalid");
       return (ARCHIVE_FATAL);
     }
     new_window = realloc(rar->lzss.window, new_size);
     if (new_window == NULL) {
       archive_set_error(&a->archive, ENOMEM,
-                        "Unable to allocate memory for uncompressed data.");
+                        "Unable to allocate memory for uncompressed data");
       return (ARCHIVE_FATAL);
     }
     rar->lzss.window = (unsigned char *)new_window;
@@ -2686,7 +2687,7 @@
   code->numallocatedentries = 0;
   if (new_node(code) < 0) {
     archive_set_error(&a->archive, ENOMEM,
-                      "Unable to allocate memory for node data.");
+                      "Unable to allocate memory for node data");
     return (ARCHIVE_FATAL);
   }
   code->numentries = 1;
@@ -2769,12 +2770,12 @@
 
       if ((repeatnode = new_node(code)) < 0) {
         archive_set_error(&a->archive, ENOMEM,
-                          "Unable to allocate memory for node data.");
+                          "Unable to allocate memory for node data");
         return (ARCHIVE_FATAL);
       }
       if ((nextnode = new_node(code)) < 0) {
         archive_set_error(&a->archive, ENOMEM,
-                          "Unable to allocate memory for node data.");
+                          "Unable to allocate memory for node data");
         return (ARCHIVE_FATAL);
       }
 
@@ -2794,7 +2795,7 @@
       {
         if (new_node(code) < 0) {
           archive_set_error(&a->archive, ENOMEM,
-                            "Unable to allocate memory for node data.");
+                            "Unable to allocate memory for node data");
           return (ARCHIVE_FATAL);
         }
         code->tree[lastnode].branches[bit] = code->numentries++;
@@ -2863,13 +2864,13 @@
   if (!code->tree)
   {
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                      "Huffman tree was not created.");
+                      "Huffman tree was not created");
     return (ARCHIVE_FATAL);
   }
   if (node < 0 || node >= code->numentries)
   {
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                      "Invalid location to Huffman tree specified.");
+                      "Invalid location to Huffman tree specified");
     return (ARCHIVE_FATAL);
   }
 
@@ -3149,6 +3150,11 @@
 
   windowoffs = lzss_offset_for_position(&rar->lzss, startpos);
   firstpart = lzss_size(&rar->lzss) - windowoffs;
+  if (length > lzss_size(&rar->lzss)) {
+    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+                      "Bad RAR file data");
+    return (ARCHIVE_FATAL);
+  }
   if (firstpart < 0) {
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
                       "Bad RAR file data");
@@ -3180,7 +3186,7 @@
     if ((rar->unp_buffer = malloc(rar->unp_buffer_size)) == NULL)
     {
       archive_set_error(&a->archive, ENOMEM,
-                        "Unable to allocate memory for uncompressed data.");
+                        "Unable to allocate memory for uncompressed data");
       return (ARCHIVE_FATAL);
     }
   }
@@ -3315,7 +3321,8 @@
   else
     blocklength = prog ? prog->oldfilterlength : 0;
 
-  if (blocklength > rar->dictionary_size)
+  if (blocklength > rar->dictionary_size ||
+      blocklength > (uint32_t)(rar->lzss.mask + 1))
     return 0;
 
   registers[3] = PROGRAM_SYSTEM_GLOBAL_ADDRESS;
diff --git a/c/archive_read_support_format_rar5.c b/c/archive_read_support_format_rar5.c
--- a/c/archive_read_support_format_rar5.c
+++ b/c/archive_read_support_format_rar5.c
@@ -675,7 +675,7 @@
 	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.");
+		    "Can't allocate memory for filter data");
 		return ARCHIVE_FATAL;
 	}
 
@@ -1851,7 +1851,7 @@
 	    rar->cstate.window_buf == NULL) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 				  "Declared solid file, but no window buffer "
-				  "initialized yet.");
+				  "initialized yet");
 		return ARCHIVE_FATAL;
 	}
 
@@ -1861,7 +1861,7 @@
 	    (rar->file.dir == 0 && window_size == 0))
 	{
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-		    "Declared dictionary size is not supported.");
+		    "Declared dictionary size is not supported");
 		return ARCHIVE_FATAL;
 	}
 
@@ -1873,7 +1873,7 @@
 		{
 			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. ");
+			    "the window size used in previous solid file");
 			return ARCHIVE_FATAL;
 		}
 	}
@@ -1899,7 +1899,7 @@
 		if(!new_window_buf) {
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
 				"Not enough memory when trying to realloc the window "
-				"buffer.");
+				"buffer");
 			return ARCHIVE_FATAL;
 		}
 
@@ -3057,7 +3057,7 @@
 	filt = add_new_filter(rar);
 	if(filt == NULL) {
 		archive_set_error(&ar->archive, ENOMEM,
-		    "Can't allocate memory for a filter descriptor.");
+		    "Can't allocate memory for a filter descriptor");
 		return ARCHIVE_FATAL;
 	}
 
@@ -3506,7 +3506,7 @@
 	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.");
+		    "Can't allocate memory for a merge block buffer");
 		return ARCHIVE_FATAL;
 	}
 
@@ -3539,7 +3539,7 @@
 		if(partial_offset + cur_block_size > block_size) {
 			archive_set_error(&a->archive,
 			    ARCHIVE_ERRNO_PROGRAMMER,
-			    "Consumed too much data when merging blocks.");
+			    "Consumed too much data when merging blocks");
 			return ARCHIVE_FATAL;
 		}
 
@@ -3808,7 +3808,7 @@
 	 * as an internal error. */
 
 	archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
-	    "Error: premature end of data_ready stack");
+	    "Premature end of data_ready stack");
 	return ARCHIVE_FATAL;
 }
 
diff --git a/c/archive_read_support_format_tar.c b/c/archive_read_support_format_tar.c
--- a/c/archive_read_support_format_tar.c
+++ b/c/archive_read_support_format_tar.c
@@ -1202,7 +1202,7 @@
 		return (ARCHIVE_FATAL);
 	}
 	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-	    "%s can't be converted from %s to current locale.",
+	    "%s can't be converted from %s to current locale",
 	    name, archive_string_conversion_charset_name(sconv));
 	return (ARCHIVE_WARN);
 }
@@ -2255,12 +2255,12 @@
 	if (r != ARCHIVE_OK) {
 		if (r == ARCHIVE_FATAL) {
 			archive_set_error(&a->archive, ENOMEM,
-			    "%s %s", "Can't allocate memory for ",
+			    "%s %s", "Can't allocate memory for",
 			    errstr);
 			return (r);
 		}
 		archive_set_error(&a->archive,
-		    ARCHIVE_ERRNO_MISC, "%s %s", "Parse error: ", errstr);
+		    ARCHIVE_ERRNO_MISC, "%s %s", "Parse error:", errstr);
 	}
 	return (r);
 }
diff --git a/c/archive_read_support_format_xar.c b/c/archive_read_support_format_xar.c
--- a/c/archive_read_support_format_xar.c
+++ b/c/archive_read_support_format_xar.c
@@ -733,7 +733,7 @@
 		}
 		archive_set_error(&a->archive,
 		    ARCHIVE_ERRNO_FILE_FORMAT,
-		    "Gname cannot be converted from %s to current locale.",
+		    "Gname cannot be converted from %s to current locale",
 		    archive_string_conversion_charset_name(xar->sconv));
 		r = ARCHIVE_WARN;
 	}
@@ -748,7 +748,7 @@
 		}
 		archive_set_error(&a->archive,
 		    ARCHIVE_ERRNO_FILE_FORMAT,
-		    "Uname cannot be converted from %s to current locale.",
+		    "Uname cannot be converted from %s to current locale",
 		    archive_string_conversion_charset_name(xar->sconv));
 		r = ARCHIVE_WARN;
 	}
@@ -762,7 +762,7 @@
 		}
 		archive_set_error(&a->archive,
 		    ARCHIVE_ERRNO_FILE_FORMAT,
-		    "Pathname cannot be converted from %s to current locale.",
+		    "Pathname cannot be converted from %s to current locale",
 		    archive_string_conversion_charset_name(xar->sconv));
 		r = ARCHIVE_WARN;
 	}
@@ -778,7 +778,7 @@
 		}
 		archive_set_error(&a->archive,
 		    ARCHIVE_ERRNO_FILE_FORMAT,
-		    "Linkname cannot be converted from %s to current locale.",
+		    "Linkname cannot be converted from %s to current locale",
 		    archive_string_conversion_charset_name(xar->sconv));
 		r = ARCHIVE_WARN;
 	}
@@ -1008,7 +1008,7 @@
 			if (pos == ARCHIVE_FAILED) {
 				archive_set_error(&(a->archive),
 				    ARCHIVE_ERRNO_MISC,
-				    "Cannot seek.");
+				    "Cannot seek");
 				return (ARCHIVE_FAILED);
 			}
 			xar->offset = pos;
@@ -1476,7 +1476,7 @@
 			r = inflateInit(&(xar->stream));
 		if (r != Z_OK) {
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "Couldn't initialize zlib stream.");
+			    "Couldn't initialize zlib stream");
 			return (ARCHIVE_FATAL);
 		}
 		xar->stream_valid = 1;
@@ -1691,7 +1691,7 @@
 		default:
 			archive_set_error(&(a->archive),
 			    ARCHIVE_ERRNO_MISC,
-			    "%s decompression failed(%d)",
+			    "%s decompression failed (%d)",
 			    (xar->entry_encoding == XZ)?"xz":"lzma",
 			    r);
 			return (ARCHIVE_FATAL);
diff --git a/c/archive_read_support_format_zip.c b/c/archive_read_support_format_zip.c
--- a/c/archive_read_support_format_zip.c
+++ b/c/archive_read_support_format_zip.c
@@ -1008,7 +1008,7 @@
 		archive_set_error(&a->archive,
 		    ARCHIVE_ERRNO_FILE_FORMAT,
 		    "Pathname cannot be converted "
-		    "from %s to current locale.",
+		    "from %s to current locale",
 		    archive_string_conversion_charset_name(sconv));
 		ret = ARCHIVE_WARN;
 	}
@@ -1256,7 +1256,7 @@
 				archive_set_error(&a->archive,
 				    ARCHIVE_ERRNO_FILE_FORMAT,
 				    "Symlink cannot be converted "
-				    "from %s to current locale.",
+				    "from %s to current locale",
 				    archive_string_conversion_charset_name(
 					sconv));
 				ret = ARCHIVE_WARN;
@@ -1726,7 +1726,7 @@
 	r = lzma_stream_decoder(&zip->zipx_lzma_stream, UINT64_MAX, 0);
 	if (r != LZMA_OK) {
 		archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
-		    "xz initialization failed(%d)",
+		    "xz initialization failed (%d)",
 		    r);
 
 		return (ARCHIVE_FAILED);
@@ -1778,7 +1778,7 @@
 	r = lzma_alone_decoder(&zip->zipx_lzma_stream, UINT64_MAX);
 	if (r != LZMA_OK) {
 		archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
-		    "lzma initialization failed(%d)", r);
+		    "lzma initialization failed (%d)", r);
 
 		return (ARCHIVE_FAILED);
 	}
@@ -1921,7 +1921,7 @@
 	switch(lz_ret) {
 		case LZMA_DATA_ERROR:
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "xz data error (error %d)", (int) lz_ret);
+			    "xz data error (%d)", (int) lz_ret);
 			return (ARCHIVE_FATAL);
 
 		case LZMA_NO_CHECK:
@@ -1930,7 +1930,7 @@
 
 		default:
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "xz unknown error %d", (int) lz_ret);
+			    "xz unknown error (%d)", (int) lz_ret);
 			return (ARCHIVE_FATAL);
 
 		case LZMA_STREAM_END:
@@ -2018,7 +2018,7 @@
 	switch(lz_ret) {
 		case LZMA_DATA_ERROR:
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "lzma data error (error %d)", (int) lz_ret);
+			    "lzma data error (%d)", (int) lz_ret);
 			return (ARCHIVE_FATAL);
 
 		/* This case is optional in lzma alone format. It can happen,
@@ -2041,7 +2041,7 @@
 
 		default:
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "lzma unknown error %d", (int) lz_ret);
+			    "lzma unknown error (%d)", (int) lz_ret);
 			return (ARCHIVE_FATAL);
 	}
 
@@ -2261,7 +2261,7 @@
 	r = BZ2_bzDecompressInit(&zip->bzstream, 0, 1);
 	if(r != BZ_OK) {
 		archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
-		    "bzip2 initialization failed(%d)",
+		    "bzip2 initialization failed (%d)",
 		    r);
 
 		return ARCHIVE_FAILED;
@@ -2527,7 +2527,7 @@
 			    -15 /* Don't check for zlib header */);
 		if (r != Z_OK) {
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "Can't initialize ZIP decompression.");
+			    "Can't initialize ZIP decompression");
 			return (ARCHIVE_FATAL);
 		}
 		/* Stream structure has been set up. */
@@ -3193,7 +3193,7 @@
 		    != (zip->entry_uncompressed_bytes_read & UINT32_MAX)) {
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 			    "ZIP uncompressed data is wrong size "
-			    "(read %jd, expected %jd)\n",
+			    "(read %jd, expected %jd)",
 			    (intmax_t)zip->entry_uncompressed_bytes_read,
 			    (intmax_t)zip->entry->uncompressed_size);
 			return (ARCHIVE_FAILED);
diff --git a/c/archive_string.c b/c/archive_string.c
--- a/c/archive_string.c
+++ b/c/archive_string.c
@@ -1713,7 +1713,7 @@
 		if (a != NULL) {
 #if HAVE_ICONV
 			archive_set_error(a, ARCHIVE_ERRNO_MISC,
-			    "iconv_open failed : Cannot handle ``%s''",
+			    "iconv_open failed: Cannot handle ``%s''",
 			    (flag & SCONV_TO_CHARSET)?tc:fc);
 #else
 			archive_set_error(a, ARCHIVE_ERRNO_MISC,
diff --git a/c/archive_write.c b/c/archive_write.c
--- a/c/archive_write.c
+++ b/c/archive_write.c
@@ -742,7 +742,7 @@
 
 	if (a->format_write_header == NULL) {
 		archive_set_error(&(a->archive), -1,
-		    "Format must be set before you can write to an archive.");
+		    "Format must be set before you can write to an archive");
 		a->archive.state = ARCHIVE_STATE_FATAL;
 		return (ARCHIVE_FATAL);
 	}
diff --git a/c/archive_write_add_filter_b64encode.c b/c/archive_write_add_filter_b64encode.c
--- a/c/archive_write_add_filter_b64encode.c
+++ b/c/archive_write_add_filter_b64encode.c
@@ -28,6 +28,9 @@
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
@@ -116,12 +119,20 @@
 	struct private_b64encode *state = (struct private_b64encode *)f->data;
 
 	if (strcmp(key, "mode") == 0) {
+		int64_t val;
+
 		if (value == NULL) {
 			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
 			    "mode option requires octal digits");
 			return (ARCHIVE_FAILED);
 		}
-		state->mode = (int)atol8(value, strlen(value)) & 0777;
+		val = atol8(value, strlen(value));
+		if (val < 0 || val > INT_MAX) {
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "invalid mode option");
+			return (ARCHIVE_FAILED);
+		}
+		state->mode = (int)val & 0777;
 		return (ARCHIVE_OK);
 	} else if (strcmp(key, "name") == 0) {
 		if (value == NULL) {
@@ -286,14 +297,19 @@
 {
 	int64_t l;
 	int digit;
-        
+
+	if (char_cnt == 0)
+		return (-1);
+
 	l = 0;
 	while (char_cnt-- > 0) {
 		if (*p >= '0' && *p <= '7')
 			digit = *p - '0';
 		else
-			break;
+			return (-1);
 		p++;
+		if (l > (INT64_MAX >> 3))
+			return (-1);
 		l <<= 3;
 		l |= digit;
 	}
diff --git a/c/archive_write_add_filter_bzip2.c b/c/archive_write_add_filter_bzip2.c
--- a/c/archive_write_add_filter_bzip2.c
+++ b/c/archive_write_add_filter_bzip2.c
@@ -127,8 +127,11 @@
 
 	if (strcmp(key, "compression-level") == 0) {
 		if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
-		    value[1] != '\0')
-			return (ARCHIVE_WARN);
+		    value[1] != '\0') {
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "compression-level invalid");
+			return (ARCHIVE_FAILED);
+		}
 		data->compression_level = value[0] - '0';
 		/* Make '0' be a synonym for '1'. */
 		/* This way, bzip2 compressor supports the same 0..9
diff --git a/c/archive_write_add_filter_gzip.c b/c/archive_write_add_filter_gzip.c
--- a/c/archive_write_add_filter_gzip.c
+++ b/c/archive_write_add_filter_gzip.c
@@ -160,8 +160,11 @@
 
 	if (strcmp(key, "compression-level") == 0) {
 		if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
-		    value[1] != '\0')
-			return (ARCHIVE_WARN);
+		    value[1] != '\0') {
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "compression-level invalid");
+			return (ARCHIVE_FAILED);
+		}
 		data->compression_level = value[0] - '0';
 		return (ARCHIVE_OK);
 	}
@@ -172,8 +175,11 @@
 	if (strcmp(key, "original-filename") == 0) {
 		free((void*)data->original_filename);
 		data->original_filename = NULL;
-		if (value)
+		if (value) {
 			data->original_filename = strdup(value);
+			if (data->original_filename == NULL)
+				return (ARCHIVE_WARN);
+		}
 		return (ARCHIVE_OK);
 	}
 
diff --git a/c/archive_write_add_filter_lrzip.c b/c/archive_write_add_filter_lrzip.c
--- a/c/archive_write_add_filter_lrzip.c
+++ b/c/archive_write_add_filter_lrzip.c
@@ -97,8 +97,11 @@
 	struct write_lrzip *data = (struct write_lrzip *)f->data;
 
 	if (strcmp(key, "compression") == 0) {
-		if (value == NULL)
-			return (ARCHIVE_WARN);
+		if (value == NULL) {
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "compression option requires an argument");
+			return (ARCHIVE_FAILED);
+		}
 		else if (strcmp(value, "bzip2") == 0)
 			data->compression = bzip2;
 		else if (strcmp(value, "gzip") == 0)
@@ -109,13 +112,19 @@
 			data->compression = none;
 		else if (strcmp(value, "zpaq") == 0)
 			data->compression = zpaq;
-		else
-			return (ARCHIVE_WARN);
+		else {
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "compression invalid");
+			return (ARCHIVE_FAILED);
+		}
 		return (ARCHIVE_OK);
 	} else if (strcmp(key, "compression-level") == 0) {
 		if (value == NULL || !(value[0] >= '1' && value[0] <= '9') ||
-		    value[1] != '\0')
-			return (ARCHIVE_WARN);
+		    value[1] != '\0') {
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "compression-level invalid");
+			return (ARCHIVE_FAILED);
+		}
 		data->compression_level = value[0] - '0';
 		return (ARCHIVE_OK);
 	}
diff --git a/c/archive_write_add_filter_lz4.c b/c/archive_write_add_filter_lz4.c
--- a/c/archive_write_add_filter_lz4.c
+++ b/c/archive_write_add_filter_lz4.c
@@ -160,8 +160,11 @@
 	if (strcmp(key, "compression-level") == 0) {
 		int val;
 		if (value == NULL || !((val = value[0] - '0') >= 1 && val <= 9) ||
-		    value[1] != '\0')
-			return (ARCHIVE_WARN);
+		    value[1] != '\0') {
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "compression-level invalid");
+			return (ARCHIVE_FAILED);
+		}
 
 #ifndef HAVE_LZ4HC_H
 		if(val >= 3)
@@ -184,8 +187,11 @@
 	}
 	if (strcmp(key, "block-size") == 0) {
 		if (value == NULL || !(value[0] >= '4' && value[0] <= '7') ||
-		    value[1] != '\0')
-			return (ARCHIVE_WARN);
+		    value[1] != '\0') {
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "block-size invalid");
+			return (ARCHIVE_FAILED);
+		}
 		data->block_maximum_size = value[0] - '0';
 		return (ARCHIVE_OK);
 	}
diff --git a/c/archive_write_add_filter_lzop.c b/c/archive_write_add_filter_lzop.c
--- a/c/archive_write_add_filter_lzop.c
+++ b/c/archive_write_add_filter_lzop.c
@@ -211,8 +211,11 @@
 
 	if (strcmp(key, "compression-level") == 0) {
 		if (value == NULL || !(value[0] >= '1' && value[0] <= '9') ||
-		    value[1] != '\0')
-			return (ARCHIVE_WARN);
+		    value[1] != '\0') {
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "compression-level invalid");
+			return (ARCHIVE_FAILED);
+		}
 		data->compression_level = value[0] - '0';
 		return (ARCHIVE_OK);
 	}
diff --git a/c/archive_write_add_filter_uuencode.c b/c/archive_write_add_filter_uuencode.c
--- a/c/archive_write_add_filter_uuencode.c
+++ b/c/archive_write_add_filter_uuencode.c
@@ -28,6 +28,9 @@
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
@@ -105,12 +108,20 @@
 	struct private_uuencode *state = (struct private_uuencode *)f->data;
 
 	if (strcmp(key, "mode") == 0) {
+		int64_t val;
+
 		if (value == NULL) {
 			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
 			    "mode option requires octal digits");
 			return (ARCHIVE_FAILED);
 		}
-		state->mode = (int)atol8(value, strlen(value)) & 0777;
+		val = atol8(value, strlen(value));
+		if (val < 0 || val > INT_MAX) {
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "invalid mode option");
+			return (ARCHIVE_FAILED);
+		}
+		state->mode = (int)val & 0777;
 		return (ARCHIVE_OK);
 	} else if (strcmp(key, "name") == 0) {
 		if (value == NULL) {
@@ -277,14 +288,19 @@
 {
 	int64_t l;
 	int digit;
-        
+
+	if (char_cnt == 0)
+		return (-1);
+
 	l = 0;
 	while (char_cnt-- > 0) {
 		if (*p >= '0' && *p <= '7')
 			digit = *p - '0';
 		else
-			break;
+			return (-1);
 		p++;
+		if (l > (INT64_MAX >> 3))
+			return (-1);
 		l <<= 3;
 		l |= digit;
 	}
diff --git a/c/archive_write_add_filter_xz.c b/c/archive_write_add_filter_xz.c
--- a/c/archive_write_add_filter_xz.c
+++ b/c/archive_write_add_filter_xz.c
@@ -29,6 +29,9 @@
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
@@ -376,23 +379,33 @@
 
 	if (strcmp(key, "compression-level") == 0) {
 		if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
-		    value[1] != '\0')
-			return (ARCHIVE_WARN);
+		    value[1] != '\0') {
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "compression-level invalid");
+			return (ARCHIVE_FAILED);
+		}
 		data->compression_level = value[0] - '0';
 		if (data->compression_level > 9)
 			data->compression_level = 9;
 		return (ARCHIVE_OK);
 	} else if (strcmp(key, "threads") == 0) {
 		char *endptr;
+		unsigned long val;
 
-		if (value == NULL)
-			return (ARCHIVE_WARN);
+		if (value == NULL) {
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "threads option requires an argument");
+			return (ARCHIVE_FAILED);
+		}
 		errno = 0;
-		data->threads = (int)strtoul(value, &endptr, 10);
-		if (errno != 0 || *endptr != '\0') {
+		val = strtoul(value, &endptr, 10);
+		if (errno != 0 || *endptr != '\0' || val > (unsigned)INT_MAX) {
 			data->threads = 1;
-			return (ARCHIVE_WARN);
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "threads invalid");
+			return (ARCHIVE_FAILED);
 		}
+		data->threads = (int)val;
 		if (data->threads == 0) {
 #ifdef HAVE_LZMA_STREAM_ENCODER_MT
 			data->threads = lzma_cputhreads();
diff --git a/c/archive_write_add_filter_zstd.c b/c/archive_write_add_filter_zstd.c
--- a/c/archive_write_add_filter_zstd.c
+++ b/c/archive_write_add_filter_zstd.c
@@ -245,7 +245,9 @@
 	if (strcmp(key, "compression-level") == 0) {
 		intmax_t level;
 		if (string_to_number(value, &level) != ARCHIVE_OK) {
-			return (ARCHIVE_WARN);
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "compression-level invalid");
+			return (ARCHIVE_FAILED);
 		}
 		/* If we don't have the library, hard-code the max level */
 		int minimum = CLEVEL_MIN;
@@ -263,14 +265,18 @@
 		}
 #endif
 		if (level < minimum || level > maximum) {
-			return (ARCHIVE_WARN);
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "compression-level out of range");
+			return (ARCHIVE_FAILED);
 		}
 		data->compression_level = (int)level;
 		return (ARCHIVE_OK);
 	} else if (strcmp(key, "threads") == 0) {
 		intmax_t threads;
 		if (string_to_number(value, &threads) != ARCHIVE_OK) {
-			return (ARCHIVE_WARN);
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "threads invalid");
+			return (ARCHIVE_FAILED);
 		}
 
 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
@@ -286,7 +292,9 @@
 		}
 #endif
 		if (threads < 0 || threads > INT_MAX) {
-			return (ARCHIVE_WARN);
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "threads out of rnage");
+			return (ARCHIVE_FAILED);
 		}
 		data->threads = (int)threads;
 		return (ARCHIVE_OK);
@@ -296,26 +304,34 @@
 		return (ARCHIVE_OK);
 	} else if (strcmp(key, "min-frame-in") == 0) {
 		if (string_to_size(value, &data->min_frame_in) != ARCHIVE_OK) {
-			return (ARCHIVE_WARN);
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "min-frame-in invalid");
+			return (ARCHIVE_FAILED);
 		}
 		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) {
-			return (ARCHIVE_WARN);
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "min-frame-out invalid");
+			return (ARCHIVE_FAILED);
 		}
 		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) {
-			return (ARCHIVE_WARN);
+			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) {
-			return (ARCHIVE_WARN);
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "max-frame-out invalid");
+			return (ARCHIVE_FAILED);
 		}
 		return (ARCHIVE_OK);
 #endif
@@ -323,22 +339,30 @@
 	else if (strcmp(key, "long") == 0) {
 		intmax_t long_distance;
 		if (string_to_number(value, &long_distance) != ARCHIVE_OK) {
-			return (ARCHIVE_WARN);
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "long invalid");
+			return (ARCHIVE_FAILED);
 		}
 #if HAVE_ZSTD_H && HAVE_ZSTD_compressStream && ZSTD_VERSION_NUMBER >= MINVER_LONG
 		ZSTD_bounds bounds = ZSTD_cParam_getBounds(ZSTD_c_windowLog);
 		if (ZSTD_isError(bounds.error)) {
 			int max_distance = ((int)(sizeof(size_t) == 4 ? 30 : 31));
-			if (((int)long_distance) < 10 || (int)long_distance > max_distance)
-				return (ARCHIVE_WARN);
+			if (((int)long_distance) < 10 || (int)long_distance > max_distance) {
+				archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "long out of range");
+				return (ARCHIVE_FAILED);
+			}
 		} else {
-			if ((int)long_distance < bounds.lowerBound || (int)long_distance > bounds.upperBound)
-				return (ARCHIVE_WARN);
+			if ((int)long_distance < bounds.lowerBound || (int)long_distance > bounds.upperBound) {
+				archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "long out of range");
+				return (ARCHIVE_FAILED);
+			}
 		}
 #else
 		int max_distance = ((int)(sizeof(size_t) == 4 ? 30 : 31));
 		if (((int)long_distance) < 10 || (int)long_distance > max_distance)
-		    return (ARCHIVE_WARN);
+		    return (ARCHIVE_FAILED);
 #endif
 		data->long_distance = (int)long_distance;
 		return (ARCHIVE_OK);
diff --git a/c/archive_write_disk_posix.c b/c/archive_write_disk_posix.c
--- a/c/archive_write_disk_posix.c
+++ b/c/archive_write_disk_posix.c
@@ -2119,7 +2119,7 @@
 
 	if ((en == ENOENT) && (archive_entry_hardlink(a->entry) != NULL)) {
 		archive_set_error(&a->archive, en,
-		    "Hard-link target '%s' does not exist.",
+		    "Hard-link target '%s' does not exist",
 		    archive_entry_hardlink(a->entry));
 		return (ARCHIVE_FAILED);
 	}
@@ -4019,7 +4019,7 @@
 #elif defined(HAVE_CHFLAGS)
 	if (S_ISLNK(a->st.st_mode)) {
 		archive_set_error(&a->archive, errno,
-		    "Can't set file flags on symlink.");
+		    "Can't set file flags on symlink");
 		return (ARCHIVE_WARN);
 	}
 	if (chflags(name, a->st.st_flags) == 0)
@@ -4578,7 +4578,7 @@
 		} else
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 			    "Cannot restore extended "
-			    "attributes on this file system.");
+			    "attributes on this file system");
 	}
 
 	archive_string_free(&errlist);
@@ -4680,7 +4680,7 @@
 		} else
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 			    "Cannot restore extended "
-			    "attributes on this file system.");
+			    "attributes on this file system");
 	}
 
 	archive_string_free(&errlist);
diff --git a/c/archive_write_disk_windows.c b/c/archive_write_disk_windows.c
--- a/c/archive_write_disk_windows.c
+++ b/c/archive_write_disk_windows.c
@@ -1516,7 +1516,7 @@
 
 	if ((en == ENOENT) && (archive_entry_hardlink(a->entry) != NULL)) {
 		archive_set_error(&a->archive, en,
-			"Hard-link target '%s' does not exist.",
+			"Hard-link target '%s' does not exist",
 			archive_entry_hardlink(a->entry));
 		return (ARCHIVE_FAILED);
 	}
diff --git a/c/archive_write_set_format_7zip.c b/c/archive_write_set_format_7zip.c
--- a/c/archive_write_set_format_7zip.c
+++ b/c/archive_write_set_format_7zip.c
@@ -28,6 +28,9 @@
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
@@ -333,6 +336,7 @@
 
 	if (string == NULL || *string == '\0')
 		return (ARCHIVE_WARN);
+	errno = 0;
 	*numberp = strtoimax(string, &end, 10);
 	if (end == string || *end != '\0' || errno == EOVERFLOW) {
 		*numberp = 0;
@@ -487,8 +491,9 @@
 		}
 
 		char *end = NULL;
+		errno = 0;
 		long lvl = strtol(value, &end, 10);
-		if (end == NULL || *end != '\0') {
+		if (errno != 0 || end == NULL || *end != '\0') {
 			archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
 				"parsing compression-level option value failed `%s'", value);
 			return (ARCHIVE_FAILED);
@@ -525,7 +530,7 @@
 		if (string_to_number(value, &threads) != ARCHIVE_OK) {
 			return (ARCHIVE_WARN);
 		}
-		if (threads < 0) {
+		if (threads < 0 || threads > INT_MAX) {
 			return (ARCHIVE_WARN);
 		}
 		if (threads == 0) {
diff --git a/c/archive_write_set_format_cpio_binary.c b/c/archive_write_set_format_cpio_binary.c
--- a/c/archive_write_set_format_cpio_binary.c
+++ b/c/archive_write_set_format_cpio_binary.c
@@ -506,12 +506,12 @@
 		if ((a->archive.archive_format == ARCHIVE_FORMAT_CPIO_PWB) &&
 		    (archive_entry_size(entry) > 256*256*256-1)) {
 			archive_set_error(&a->archive, ERANGE,
-					  "File is too large for PWB binary cpio format.");
+					  "File is too large for PWB binary cpio format");
 			ret_final = ARCHIVE_FAILED;
 			goto exit_write_header;
 		} else if (archive_entry_size(entry) > INT32_MAX) {
 			archive_set_error(&a->archive, ERANGE,
-					  "File is too large for binary cpio format.");
+					  "File is too large for binary cpio format");
 			ret_final = ARCHIVE_FAILED;
 			goto exit_write_header;
 		}
diff --git a/c/archive_write_set_format_cpio_newc.c b/c/archive_write_set_format_cpio_newc.c
--- a/c/archive_write_set_format_cpio_newc.c
+++ b/c/archive_write_set_format_cpio_newc.c
@@ -322,7 +322,7 @@
 		    h + c_filesize_offset, c_filesize_size);
 	if (ret) {
 		archive_set_error(&a->archive, ERANGE,
-		    "File is too large for this format.");
+		    "File is too large for this format");
 		ret_final = ARCHIVE_FAILED;
 		goto exit_write_header;
 	}
diff --git a/c/archive_write_set_format_cpio_odc.c b/c/archive_write_set_format_cpio_odc.c
--- a/c/archive_write_set_format_cpio_odc.c
+++ b/c/archive_write_set_format_cpio_odc.c
@@ -380,7 +380,7 @@
 		    h + c_filesize_offset, c_filesize_size);
 	if (ret) {
 		archive_set_error(&a->archive, ERANGE,
-		    "File is too large for cpio format.");
+		    "File is too large for cpio format");
 		ret_final = ARCHIVE_FAILED;
 		goto exit_write_header;
 	}
diff --git a/c/archive_write_set_format_iso9660.c b/c/archive_write_set_format_iso9660.c
--- a/c/archive_write_set_format_iso9660.c
+++ b/c/archive_write_set_format_iso9660.c
@@ -1381,7 +1381,7 @@
 			archive_set_error(&a->archive,
 			    ARCHIVE_ERRNO_MISC,
 			    "Option ``%s'' "
-			    "is not supported on this platform.", key);
+			    "is not supported on this platform", key);
 			return (ARCHIVE_FATAL);
 #endif
 		}
@@ -1503,7 +1503,7 @@
 				archive_set_error(&a->archive,
 				    ARCHIVE_ERRNO_MISC,
 				    "``zisofs'' "
-				    "is not supported on this platform.");
+				    "is not supported on this platform");
 				return (ARCHIVE_FATAL);
 #endif
 			}
@@ -1539,7 +1539,7 @@
 	if (archive_entry_filetype(entry) == AE_IFLNK
 	    && iso9660->opt.rr == OPT_RR_DISABLED) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "Ignore symlink file.");
+		    "Ignore symlink file");
 		iso9660->cur_file = NULL;
 		return (ARCHIVE_WARN);
 	}
@@ -1549,7 +1549,7 @@
 			archive_set_error(&a->archive,
 			    ARCHIVE_ERRNO_MISC,
 			    "Ignore over %lld bytes file. "
-			    "This file too large.",
+			    "This file too large",
 			    MULTI_EXTENT_SIZE);
 				iso9660->cur_file = NULL;
 			return (ARCHIVE_WARN);
@@ -2103,7 +2103,7 @@
 
 	if (iso9660->directories_too_deep != NULL) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "%s: Directories too deep.",
+		    "%s: Directories too deep",
 		    archive_entry_pathname(
 			iso9660->directories_too_deep->file->entry));
 		return (ARCHIVE_WARN);
@@ -3799,7 +3799,7 @@
 		isoent = isoent_find_entry(vdd->rootent, ids);
 		if (isoent == NULL) {
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "Not Found %s `%s'.",
+			    "Not Found %s `%s'",
 			    label, ids);
 			return (ARCHIVE_FATAL);
 		}
@@ -7080,7 +7080,7 @@
 		 * See also ISO9660 Standard 9.4.
 		 */
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "Too many directories(%d) over 65535.", dir_number);
+		    "Too many directories(%d) over 65535", dir_number);
 		return (ARCHIVE_FATAL);
 	}
 
@@ -7203,7 +7203,7 @@
 		else {
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 			    "Boot image file(``%s'') size is too big "
-			    "for fd type.",
+			    "for fd type",
 			    iso9660->el_torito.boot_filename.s);
 			return (ARCHIVE_FATAL);
 		}
@@ -7964,7 +7964,7 @@
 			r = inflateInit(&zisofs->stream);
 		if (r != Z_OK) {
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "Can't initialize zisofs decompression.");
+			    "Can't initialize zisofs decompression");
 			return (ARCHIVE_FATAL);
 		}
 		zisofs->stream_valid = 1;
diff --git a/c/archive_write_set_format_mtree.c b/c/archive_write_set_format_mtree.c
--- a/c/archive_write_set_format_mtree.c
+++ b/c/archive_write_set_format_mtree.c
@@ -2262,7 +2262,7 @@
 	if ((np->mode & AE_IFMT) != (file->mode & AE_IFMT)) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 		    "Found duplicate entries for `%s' with "
-		    "differing file types.",
+		    "differing file types",
 		    np->pathname.s);
 		return (ARCHIVE_FAILED);
 	}
diff --git a/c/archive_write_set_format_pax.c b/c/archive_write_set_format_pax.c
--- a/c/archive_write_set_format_pax.c
+++ b/c/archive_write_set_format_pax.c
@@ -1062,7 +1062,7 @@
 	}
 
 	/* If numeric GID is too large, add 'gid' to pax extended attrs. */
-	if ((unsigned int)archive_entry_gid(entry_main) >= (1 << 18)) {
+	if (archive_entry_gid(entry_main) >= (1 << 18)) {
 		add_pax_attr_int(&(pax->pax_header), "gid",
 		    archive_entry_gid(entry_main));
 		need_extension = 1;
@@ -1078,7 +1078,7 @@
 	}
 
 	/* If numeric UID is too large, add 'uid' to pax extended attrs. */
-	if ((unsigned int)archive_entry_uid(entry_main) >= (1 << 18)) {
+	if (archive_entry_uid(entry_main) >= (1 << 18)) {
 		add_pax_attr_int(&(pax->pax_header), "uid",
 		    archive_entry_uid(entry_main));
 		need_extension = 1;
@@ -1471,7 +1471,7 @@
 		if (r < ARCHIVE_WARN) {
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 			    "archive_write_pax_header: "
-			    "'x' header failed?!  This can't happen.\n");
+			    "'x' header failed?!  This can't happen");
 			archive_entry_free(entry_main);
 			archive_string_free(&entry_name);
 			return (ARCHIVE_FATAL);
diff --git a/c/archive_write_set_format_xar.c b/c/archive_write_set_format_xar.c
--- a/c/archive_write_set_format_xar.c
+++ b/c/archive_write_set_format_xar.c
@@ -526,12 +526,13 @@
 	}
 	if (strcmp(key, "threads") == 0) {
 		char *endptr;
+		unsigned long val;
 
 		if (value == NULL)
 			return (ARCHIVE_FAILED);
 		errno = 0;
-		xar->opt_threads = (int)strtoul(value, &endptr, 10);
-		if (errno != 0 || *endptr != '\0') {
+		val = strtoul(value, &endptr, 10);
+		if (errno != 0 || *endptr != '\0' || val > (unsigned)INT_MAX) {
 			xar->opt_threads = 1;
 			archive_set_error(&(a->archive),
 			    ARCHIVE_ERRNO_MISC,
@@ -539,6 +540,7 @@
 			    value);
 			return (ARCHIVE_FAILED);
 		}
+		xar->opt_threads = (int)val;
 		if (xar->opt_threads == 0) {
 #ifdef HAVE_LZMA_STREAM_ENCODER_MT
 			xar->opt_threads = lzma_cputhreads();
diff --git a/c/archive_write_set_format_zip.c b/c/archive_write_set_format_zip.c
--- a/c/archive_write_set_format_zip.c
+++ b/c/archive_write_set_format_zip.c
@@ -398,16 +398,17 @@
 		return (ret);
 	} else if (strcmp(key, "compression-level") == 0) {
 		char *endptr;
+		unsigned long v;
 
 		if (val == NULL)
 			return (ARCHIVE_WARN);
 		errno = 0;
-		zip->compression_level = (short)strtoul(val, &endptr, 10);
-		if (errno != 0 || *endptr != '\0' || zip->compression_level < 0 ||
-			zip->compression_level > 9) {
+		v = strtoul(val, &endptr, 10);
+		if (errno != 0 || *endptr != '\0' || v > 9) {
 			zip->compression_level = 6; // set to default
 			return (ARCHIVE_WARN);
 		}
+		zip->compression_level = (short)v;
 
 		if (zip->compression_level == 0) {
 			zip->requested_compression = COMPRESSION_STORE;
@@ -435,17 +436,19 @@
 		}
 	} else if (strcmp(key, "threads") == 0) {
 		char *endptr;
+		unsigned long v;
 
 		if (val == NULL)
 			return (ARCHIVE_FAILED);
 		errno = 0;
-		zip->threads = (short)strtoul(val, &endptr, 10);
-		if (errno != 0 || *endptr != '\0') {
+		v = strtoul(val, &endptr, 10);
+		if (errno != 0 || *endptr != '\0' || v > SHRT_MAX) {
 			zip->threads = 1;
 			archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
 			    "Illegal value `%s'", val);
 			return (ARCHIVE_FAILED);
 		}
+		zip->threads = (short)v;
 		if (zip->threads == 0) {
 #ifdef HAVE_LZMA_STREAM_ENCODER_MT
 			zip->threads = lzma_cputhreads();
diff --git a/libarchive-clib.cabal b/libarchive-clib.cabal
--- a/libarchive-clib.cabal
+++ b/libarchive-clib.cabal
@@ -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.6.2
+version:            3.8.7
 license:            OtherLicense
 license-file:       LICENSE
 copyright:          Copyright: (c) 2018-2020 Vanessa McHale
