From aa1b83ec5aebd91e9dba559c14f1ec4bc6792357 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dag-Erling=20Sm=C3=B8rgrav?= <des@FreeBSD.org>
Date: Thu, 3 Jan 2008 18:30:37 +0000
Subject: [PATCH] Crib {be,le}{16,32,64}{dec,enc} from src/sys/sys/endian.h and
 use it instead of home-rolled [iu][248] in the ZIP support code.

Approved by:	kientzle
---
 lib/libarchive/archive_endian.h               | 142 ++++++++++++++++++
 .../archive_read_support_format_zip.c         |  79 +++-------
 2 files changed, 164 insertions(+), 57 deletions(-)
 create mode 100644 lib/libarchive/archive_endian.h

diff --git a/lib/libarchive/archive_endian.h b/lib/libarchive/archive_endian.h
new file mode 100644
index 000000000000..0df32d5d9ff0
--- /dev/null
+++ b/lib/libarchive/archive_endian.h
@@ -0,0 +1,142 @@
+/*-
+ * Copyright (c) 2002 Thomas Moestl <tmm@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ * Borrowed from FreeBSD's <sys/endian.h>
+ */
+
+#ifndef ARCHIVE_ENDIAN_H_INCLUDED
+#define ARCHIVE_ENDIAN_H_INCLUDED
+
+/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */
+
+static inline uint16_t
+be16dec(const void *pp)
+{
+	unsigned char const *p = (unsigned char const *)pp;
+
+	return ((p[0] << 8) | p[1]);
+}
+
+static inline uint32_t
+be32dec(const void *pp)
+{
+	unsigned char const *p = (unsigned char const *)pp;
+
+	return ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+}
+
+static inline uint64_t
+be64dec(const void *pp)
+{
+	unsigned char const *p = (unsigned char const *)pp;
+
+	return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4));
+}
+
+static inline uint16_t
+le16dec(const void *pp)
+{
+	unsigned char const *p = (unsigned char const *)pp;
+
+	return ((p[1] << 8) | p[0]);
+}
+
+static inline uint32_t
+le32dec(const void *pp)
+{
+	unsigned char const *p = (unsigned char const *)pp;
+
+	return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
+}
+
+static inline uint64_t
+le64dec(const void *pp)
+{
+	unsigned char const *p = (unsigned char const *)pp;
+
+	return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p));
+}
+
+static inline void
+be16enc(void *pp, uint16_t u)
+{
+	unsigned char *p = (unsigned char *)pp;
+
+	p[0] = (u >> 8) & 0xff;
+	p[1] = u & 0xff;
+}
+
+static inline void
+be32enc(void *pp, uint32_t u)
+{
+	unsigned char *p = (unsigned char *)pp;
+
+	p[0] = (u >> 24) & 0xff;
+	p[1] = (u >> 16) & 0xff;
+	p[2] = (u >> 8) & 0xff;
+	p[3] = u & 0xff;
+}
+
+static inline void
+be64enc(void *pp, uint64_t u)
+{
+	unsigned char *p = (unsigned char *)pp;
+
+	be32enc(p, u >> 32);
+	be32enc(p + 4, u & 0xffffffff);
+}
+
+static inline void
+le16enc(void *pp, uint16_t u)
+{
+	unsigned char *p = (unsigned char *)pp;
+
+	p[0] = u & 0xff;
+	p[1] = (u >> 8) & 0xff;
+}
+
+static inline void
+le32enc(void *pp, uint32_t u)
+{
+	unsigned char *p = (unsigned char *)pp;
+
+	p[0] = u & 0xff;
+	p[1] = (u >> 8) & 0xff;
+	p[2] = (u >> 16) & 0xff;
+	p[3] = (u >> 24) & 0xff;
+}
+
+static inline void
+le64enc(void *pp, uint64_t u)
+{
+	unsigned char *p = (unsigned char *)pp;
+
+	le32enc(p, u & 0xffffffff);
+	le32enc(p + 4, u >> 32);
+}
+
+#endif
diff --git a/lib/libarchive/archive_read_support_format_zip.c b/lib/libarchive/archive_read_support_format_zip.c
index 5e38ea2339ac..24a689c0634f 100644
--- a/lib/libarchive/archive_read_support_format_zip.c
+++ b/lib/libarchive/archive_read_support_format_zip.c
@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
 #include "archive_entry.h"
 #include "archive_private.h"
 #include "archive_read_private.h"
+#include "archive_endian.h"
 
 struct zip {
 	/* entry_bytes_remaining is the number of bytes we expect. */
@@ -121,11 +122,6 @@ static int	archive_read_format_zip_read_data(struct archive_read *,
 static int	archive_read_format_zip_read_data_skip(struct archive_read *a);
 static int	archive_read_format_zip_read_header(struct archive_read *,
 		    struct archive_entry *);
-static int	i2(const char *);
-static int	i4(const char *);
-static unsigned int	u2(const char *);
-static unsigned int	u4(const char *);
-static uint64_t	u8(const char *);
 static int	zip_read_data_deflate(struct archive_read *a, const void **buff,
 		    size_t *size, off_t *offset);
 static int	zip_read_data_none(struct archive_read *a, const void **buff,
@@ -264,8 +260,8 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry,
 
 	zip->version = p->version[0];
 	zip->system = p->version[1];
-	zip->flags = i2(p->flags);
-	zip->compression = i2(p->compression);
+	zip->flags = le16dec(p->flags);
+	zip->compression = le16dec(p->compression);
 	if (zip->compression <
 	    sizeof(compression_names)/sizeof(compression_names[0]))
 		zip->compression_name = compression_names[zip->compression];
@@ -277,11 +273,11 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry,
 	zip->mode = 0;
 	zip->uid = 0;
 	zip->gid = 0;
-	zip->crc32 = i4(p->crc32);
-	zip->filename_length = i2(p->filename_length);
-	zip->extra_length = i2(p->extra_length);
-	zip->uncompressed_size = u4(p->uncompressed_size);
-	zip->compressed_size = u4(p->compressed_size);
+	zip->crc32 = le32dec(p->crc32);
+	zip->filename_length = le16dec(p->filename_length);
+	zip->extra_length = le16dec(p->extra_length);
+	zip->uncompressed_size = le32dec(p->uncompressed_size);
+	zip->compressed_size = le32dec(p->compressed_size);
 
 	(a->decompressor->consume)(a, sizeof(struct zip_file_header));
 
@@ -383,9 +379,9 @@ archive_read_format_zip_read_data(struct archive_read *a,
 					    "Truncated ZIP end-of-file record");
 					return (ARCHIVE_FATAL);
 				}
-				zip->crc32 = i4(p + 4);
-				zip->compressed_size = u4(p + 8);
-				zip->uncompressed_size = u4(p + 12);
+				zip->crc32 = le32dec(p + 4);
+				zip->compressed_size = le32dec(p + 8);
+				zip->uncompressed_size = le32dec(p + 12);
 				(a->decompressor->consume)(a, 16);
 			}
 
@@ -681,37 +677,6 @@ archive_read_format_zip_cleanup(struct archive_read *a)
 	return (ARCHIVE_OK);
 }
 
-static int
-i2(const char *p)
-{
-	return ((0xff & (int)p[0]) + 256 * (0xff & (int)p[1]));
-}
-
-
-static int
-i4(const char *p)
-{
-	return ((0xffff & i2(p)) + 0x10000 * (0xffff & i2(p+2)));
-}
-
-static unsigned int
-u2(const char *p)
-{
-	return ((0xff & (unsigned int)p[0]) + 256 * (0xff & (unsigned int)p[1]));
-}
-
-static unsigned int
-u4(const char *p)
-{
-	return u2(p) + 0x10000 * u2(p+2);
-}
-
-static uint64_t
-u8(const char *p)
-{
-	return u4(p) + 0x100000000LL * u4(p+4);
-}
-
 /*
  * The extra data is stored as a list of
  *	id1+size1+data1 + id2+size2+data2 ...
@@ -724,8 +689,8 @@ process_extra(const void* extra, struct zip* zip)
 	const char *p = (const char *)extra;
 	while (offset < zip->extra_length - 4)
 	{
-		unsigned short headerid = u2(p + offset);
-		unsigned short datasize = u2(p + offset + 2);
+		unsigned short headerid = le16dec(p + offset);
+		unsigned short datasize = le16dec(p + offset + 2);
 		offset += 4;
 		if (offset + datasize > zip->extra_length)
 			break;
@@ -737,9 +702,9 @@ process_extra(const void* extra, struct zip* zip)
 		case 0x0001:
 			/* Zip64 extended information extra field. */
 			if (datasize >= 8)
-				zip->uncompressed_size = u8(p + offset);
+				zip->uncompressed_size = le64dec(p + offset);
 			if (datasize >= 16)
-				zip->compressed_size = u8(p + offset + 8);
+				zip->compressed_size = le64dec(p + offset + 8);
 			break;
 		case 0x5455:
 		{
@@ -752,11 +717,11 @@ process_extra(const void* extra, struct zip* zip)
 			{
 #ifdef DEBUG
 				fprintf(stderr, "mtime: %lld -> %d\n",
-				    (long long)zip->mtime, i4(p + offset));
+				    (long long)zip->mtime, le32dec(p + offset));
 #endif
 				if (datasize < 4)
 					break;
-				zip->mtime = i4(p + offset);
+				zip->mtime = le32dec(p + offset);
 				offset += 4;
 				datasize -= 4;
 			}
@@ -764,7 +729,7 @@ process_extra(const void* extra, struct zip* zip)
 			{
 				if (datasize < 4)
 					break;
-				zip->atime = i4(p + offset);
+				zip->atime = le32dec(p + offset);
 				offset += 4;
 				datasize -= 4;
 			}
@@ -772,7 +737,7 @@ process_extra(const void* extra, struct zip* zip)
 			{
 				if (datasize < 4)
 					break;
-				zip->ctime = i4(p + offset);
+				zip->ctime = le32dec(p + offset);
 				offset += 4;
 				datasize -= 4;
 			}
@@ -782,12 +747,12 @@ process_extra(const void* extra, struct zip* zip)
 			/* Info-ZIP Unix Extra Field (type 2) "Ux". */
 #ifdef DEBUG
 			fprintf(stderr, "uid %d gid %d\n",
-			    i2(p + offset), i2(p + offset + 2));
+			    le16dec(p + offset), le16dec(p + offset + 2));
 #endif
 			if (datasize >= 2)
-				zip->uid = i2(p + offset);
+				zip->uid = le16dec(p + offset);
 			if (datasize >= 4)
-				zip->gid = i2(p + offset + 2);
+				zip->gid = le16dec(p + offset + 2);
 			break;
 		default:
 			break;