summaryrefslogtreecommitdiff
path: root/release/src/router/busybox/archival/libunarchive
diff options
context:
space:
mode:
Diffstat (limited to 'release/src/router/busybox/archival/libunarchive')
-rw-r--r--release/src/router/busybox/archival/libunarchive/Kbuild51
-rw-r--r--release/src/router/busybox/archival/libunarchive/Makefile30
-rwxr-xr-xrelease/src/router/busybox/archival/libunarchive/Makefile.in79
-rw-r--r--release/src/router/busybox/archival/libunarchive/archive_copy_file.c44
-rw-r--r--release/src/router/busybox/archival/libunarchive/archive_xread.c33
-rw-r--r--release/src/router/busybox/archival/libunarchive/archive_xread_all.c32
-rw-r--r--release/src/router/busybox/archival/libunarchive/archive_xread_all_eof.c32
-rw-r--r--release/src/router/busybox/archival/libunarchive/archive_xread_char.c30
-rw-r--r--release/src/router/busybox/archival/libunarchive/check_header_gzip.c57
-rw-r--r--release/src/router/busybox/archival/libunarchive/data_align.c27
-rw-r--r--release/src/router/busybox/archival/libunarchive/data_extract_all.c174
-rw-r--r--release/src/router/busybox/archival/libunarchive/data_extract_to_buffer.c25
-rw-r--r--release/src/router/busybox/archival/libunarchive/data_extract_to_stdout.c22
-rw-r--r--release/src/router/busybox/archival/libunarchive/data_skip.c23
-rw-r--r--release/src/router/busybox/archival/libunarchive/decompress_bunzip2.c2202
-rw-r--r--release/src/router/busybox/archival/libunarchive/decompress_uncompress.c307
-rw-r--r--release/src/router/busybox/archival/libunarchive/decompress_unlzma.c503
-rw-r--r--release/src/router/busybox/archival/libunarchive/decompress_unzip.c1252
-rw-r--r--release/src/router/busybox/archival/libunarchive/filter_accept_all.c31
-rw-r--r--release/src/router/busybox/archival/libunarchive/filter_accept_list.c31
-rw-r--r--release/src/router/busybox/archival/libunarchive/filter_accept_list_reassign.c63
-rw-r--r--release/src/router/busybox/archival/libunarchive/filter_accept_reject_list.c41
-rw-r--r--release/src/router/busybox/archival/libunarchive/find_list_entry.c56
-rw-r--r--release/src/router/busybox/archival/libunarchive/get_header_ar.c139
-rw-r--r--release/src/router/busybox/archival/libunarchive/get_header_cpio.c287
-rw-r--r--release/src/router/busybox/archival/libunarchive/get_header_tar.c535
-rw-r--r--release/src/router/busybox/archival/libunarchive/get_header_tar_bz2.c41
-rw-r--r--release/src/router/busybox/archival/libunarchive/get_header_tar_gz.c55
-rw-r--r--release/src/router/busybox/archival/libunarchive/get_header_tar_lzma.c24
-rw-r--r--release/src/router/busybox/archival/libunarchive/header_list.c8
-rw-r--r--release/src/router/busybox/archival/libunarchive/header_skip.c9
-rw-r--r--release/src/router/busybox/archival/libunarchive/header_verbose_list.c51
-rw-r--r--release/src/router/busybox/archival/libunarchive/init_handle.c29
-rw-r--r--release/src/router/busybox/archival/libunarchive/open_transformer.c64
-rw-r--r--release/src/router/busybox/archival/libunarchive/seek_by_char.c25
-rw-r--r--release/src/router/busybox/archival/libunarchive/seek_by_jump.c36
-rw-r--r--release/src/router/busybox/archival/libunarchive/seek_by_read.c16
-rw-r--r--release/src/router/busybox/archival/libunarchive/uncompress.c298
-rw-r--r--release/src/router/busybox/archival/libunarchive/unpack_ar_archive.c31
-rw-r--r--release/src/router/busybox/archival/libunarchive/unzip.c1040
40 files changed, 3803 insertions, 4030 deletions
diff --git a/release/src/router/busybox/archival/libunarchive/Kbuild b/release/src/router/busybox/archival/libunarchive/Kbuild
new file mode 100644
index 00000000..364f9174
--- /dev/null
+++ b/release/src/router/busybox/archival/libunarchive/Kbuild
@@ -0,0 +1,51 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+
+lib-y:= \
+\
+ data_skip.o \
+ data_extract_all.o \
+ data_extract_to_stdout.o \
+ data_extract_to_buffer.o \
+\
+ filter_accept_all.o \
+ filter_accept_list.o \
+ filter_accept_reject_list.o \
+\
+ header_skip.o \
+ header_list.o \
+ header_verbose_list.o \
+\
+ seek_by_read.o \
+ seek_by_jump.o \
+\
+ data_align.o \
+ find_list_entry.o \
+ init_handle.o
+
+DPKG_FILES:= \
+ get_header_ar.o \
+ unpack_ar_archive.o \
+ get_header_tar.o \
+ filter_accept_list_reassign.o
+
+lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o
+lib-$(CONFIG_BUNZIP2) += decompress_bunzip2.o
+lib-$(CONFIG_UNLZMA) += decompress_unlzma.o
+lib-$(CONFIG_CPIO) += get_header_cpio.o
+lib-$(CONFIG_DPKG) += $(DPKG_FILES)
+lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES)
+lib-$(CONFIG_GUNZIP) += decompress_unzip.o
+lib-$(CONFIG_RPM2CPIO) += decompress_unzip.o get_header_cpio.o
+lib-$(CONFIG_RPM) += open_transformer.o decompress_unzip.o get_header_cpio.o
+lib-$(CONFIG_TAR) += get_header_tar.o
+lib-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o
+lib-$(CONFIG_UNZIP) += decompress_unzip.o
+lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o
+lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_unzip.o get_header_tar_gz.o
+lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o get_header_tar_bz2.o
+lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o get_header_tar_lzma.o
+lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o
diff --git a/release/src/router/busybox/archival/libunarchive/Makefile b/release/src/router/busybox/archival/libunarchive/Makefile
deleted file mode 100644
index 272ca243..00000000
--- a/release/src/router/busybox/archival/libunarchive/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-# Makefile for busybox
-#
-# Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-
-TOPDIR:= ../../
-LIBUNARCHIVE_DIR:=./
-include $(TOPDIR).config
-include $(TOPDIR)Rules.mak
-include Makefile.in
-all: $(libraries-y)
--include $(TOPDIR).depend
-
-clean:
- rm -f *.o *.a $(AR_TARGET)
-
diff --git a/release/src/router/busybox/archival/libunarchive/Makefile.in b/release/src/router/busybox/archival/libunarchive/Makefile.in
deleted file mode 100755
index 2b32aaa5..00000000
--- a/release/src/router/busybox/archival/libunarchive/Makefile.in
+++ /dev/null
@@ -1,79 +0,0 @@
-# Makefile for busybox
-#
-# Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-
-LIBUNARCHIVE_AR:=libunarchive.a
-ifndef $(LIBUNARCHIVE_DIR)
-LIBUNARCHIVE_DIR:=$(TOPDIR)archival/libunarchive/
-endif
-
-LIBUNARCHIVE-y:= \
-\
- data_skip.o \
- data_extract_all.o \
- data_extract_to_stdout.o \
- data_extract_to_buffer.o \
-\
- filter_accept_all.o \
- filter_accept_list.o \
- filter_accept_list_reassign.o \
- filter_accept_reject_list.o \
-\
- get_header_ar.o \
- get_header_cpio.o \
- get_header_tar.o \
- get_header_tar_bz2.o \
- get_header_tar_gz.o \
-\
- header_skip.o \
- header_list.o \
- header_verbose_list.o \
-\
- archive_xread.o \
- archive_xread_all.o \
- archive_xread_all_eof.o \
- archive_xread_char.o \
-\
- seek_by_char.o \
- seek_by_jump.o \
-\
- archive_copy_file.o \
-\
- check_header_gzip.o \
- data_align.o \
- decompress_bunzip2.o \
- find_list_entry.o \
- init_handle.o \
- uncompress.o \
- unpack_ar_archive.o \
- unzip.o
-
-LIBUNARCHIVE-$(CONFIG_DPKG) +=
-LIBUNARCHIVE-$(CONFIG_DPKG_DEB) +=
-LIBUNARCHIVE-$(CONFIG_AR) +=
-LIBUNARCHIVE-$(CONFIG_CPIO) +=
-LIBUNARCHIVE-$(CONFIG_GUNZIP) +=
-LIBUNARCHIVE-$(CONFIG_RPM2CPIO) +=
-LIBUNARCHIVE-$(CONFIG_TAR) +=
-LIBUNARCHIVE-$(CONFIG_UNZIP) +=
-
-libraries-y+=$(LIBUNARCHIVE_DIR)$(LIBUNARCHIVE_AR)
-
-$(LIBUNARCHIVE_DIR)$(LIBUNARCHIVE_AR): $(patsubst %,$(LIBUNARCHIVE_DIR)%, $(LIBUNARCHIVE-y))
- $(AR) -ro $@ $(patsubst %,$(LIBUNARCHIVE_DIR)%, $(LIBUNARCHIVE-y))
-
diff --git a/release/src/router/busybox/archival/libunarchive/archive_copy_file.c b/release/src/router/busybox/archival/libunarchive/archive_copy_file.c
deleted file mode 100644
index 675bc6ff..00000000
--- a/release/src/router/busybox/archival/libunarchive/archive_copy_file.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <unistd.h>
-
-#include "libbb.h"
-#include "unarchive.h"
-
-extern void archive_copy_file(const archive_handle_t *archive_handle, const int dst_fd)
-{
- char buffer[512];
- off_t chunksize = archive_handle->file_header->size;
-
- while (chunksize != 0) {
- size_t size;
- if (chunksize > 512) {
- size = 512;
- } else {
- size = chunksize;
- }
-// archive_xread_all(archive_handle, buffer, size);
- size = archive_xread(archive_handle, buffer, size);
-
- if (write(dst_fd, buffer, size) != size) {
- bb_error_msg_and_die ("Short write");
- }
- chunksize -= size;
- }
-
- return;
-}
diff --git a/release/src/router/busybox/archival/libunarchive/archive_xread.c b/release/src/router/busybox/archival/libunarchive/archive_xread.c
deleted file mode 100644
index d63d0d5a..00000000
--- a/release/src/router/busybox/archival/libunarchive/archive_xread.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "unarchive.h"
-#include "libbb.h"
-
-extern ssize_t archive_xread(const archive_handle_t *archive_handle, unsigned char *buf, const size_t count)
-{
- ssize_t size;
-
- size = archive_handle->read(archive_handle->src_fd, buf, count);
- if (size < 0) {
- bb_perror_msg_and_die("Read error");
- }
-
- return(size);
-}
diff --git a/release/src/router/busybox/archival/libunarchive/archive_xread_all.c b/release/src/router/busybox/archival/libunarchive/archive_xread_all.c
deleted file mode 100644
index cfe046b2..00000000
--- a/release/src/router/busybox/archival/libunarchive/archive_xread_all.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "unarchive.h"
-#include "libbb.h"
-
-extern void archive_xread_all(const archive_handle_t *archive_handle, void *buf, const size_t count)
-{
- ssize_t size;
-
- size = archive_xread(archive_handle, buf, count);
- if (size != count) {
- bb_error_msg_and_die("Short read");
- }
- return;
-}
diff --git a/release/src/router/busybox/archival/libunarchive/archive_xread_all_eof.c b/release/src/router/busybox/archival/libunarchive/archive_xread_all_eof.c
deleted file mode 100644
index 23719cd7..00000000
--- a/release/src/router/busybox/archival/libunarchive/archive_xread_all_eof.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "unarchive.h"
-#include "libbb.h"
-
-extern ssize_t archive_xread_all_eof(archive_handle_t *archive_handle, unsigned char *buf, size_t count)
-{
- ssize_t size;
-
- size = archive_xread(archive_handle, buf, count);
- if ((size != 0) && (size != count)) {
- bb_perror_msg_and_die("Short read, read %d of %d", size, count);
- }
- return(size);
-}
diff --git a/release/src/router/busybox/archival/libunarchive/archive_xread_char.c b/release/src/router/busybox/archival/libunarchive/archive_xread_char.c
deleted file mode 100644
index 4c665e15..00000000
--- a/release/src/router/busybox/archival/libunarchive/archive_xread_char.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "unarchive.h"
-#include "libbb.h"
-
-extern unsigned char archive_xread_char(const archive_handle_t *archive_handle)
-{
- unsigned char tmp;
-
- archive_xread(archive_handle, &tmp, 1);
-
- return(tmp);
-}
diff --git a/release/src/router/busybox/archival/libunarchive/check_header_gzip.c b/release/src/router/busybox/archival/libunarchive/check_header_gzip.c
deleted file mode 100644
index 13832c24..00000000
--- a/release/src/router/busybox/archival/libunarchive/check_header_gzip.c
+++ /dev/null
@@ -1,57 +0,0 @@
-#include <stdlib.h>
-#include <unistd.h>
-#include "libbb.h"
-
-extern void check_header_gzip(int src_fd)
-{
- union {
- unsigned char raw[8];
- struct {
- unsigned char method;
- unsigned char flags;
- unsigned int mtime;
- unsigned char xtra_flags;
- unsigned char os_flags;
- } formated;
- } header;
-
- bb_xread_all(src_fd, header.raw, 8);
-
- /* Check the compression method */
- if (header.formated.method != 8) {
- bb_error_msg_and_die("Unknown compression method %d",
- header.formated.method);
- }
-
- if (header.formated.flags & 0x04) {
- /* bit 2 set: extra field present */
- unsigned char extra_short;
-
- extra_short = bb_xread_char(src_fd) + (bb_xread_char(src_fd) << 8);
- while (extra_short > 0) {
- /* Ignore extra field */
- bb_xread_char(src_fd);
- extra_short--;
- }
- }
-
- /* Discard original name if any */
- if (header.formated.flags & 0x08) {
- /* bit 3 set: original file name present */
- while(bb_xread_char(src_fd) != 0);
- }
-
- /* Discard file comment if any */
- if (header.formated.flags & 0x10) {
- /* bit 4 set: file comment present */
- while(bb_xread_char(src_fd) != 0);
- }
-
- /* Read the header checksum */
- if (header.formated.flags & 0x02) {
- bb_xread_char(src_fd);
- bb_xread_char(src_fd);
- }
-
- return;
-}
diff --git a/release/src/router/busybox/archival/libunarchive/data_align.c b/release/src/router/busybox/archival/libunarchive/data_align.c
index 037242f2..9f2e8432 100644
--- a/release/src/router/busybox/archival/libunarchive/data_align.c
+++ b/release/src/router/busybox/archival/libunarchive/data_align.c
@@ -1,34 +1,15 @@
+/* vi: set sw=4 ts=4: */
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <sys/types.h>
-
-#include <errno.h>
-#include <unistd.h>
-
#include "libbb.h"
#include "unarchive.h"
-extern void data_align(archive_handle_t *archive_handle, const unsigned short boundary)
+void FAST_FUNC data_align(archive_handle_t *archive_handle, unsigned boundary)
{
- const unsigned short skip_amount = (boundary - (archive_handle->offset % boundary)) % boundary;
+ unsigned skip_amount = (boundary - (archive_handle->offset % boundary)) % boundary;
archive_handle->seek(archive_handle, skip_amount);
-
archive_handle->offset += skip_amount;
-
- return;
}
diff --git a/release/src/router/busybox/archival/libunarchive/data_extract_all.c b/release/src/router/busybox/archival/libunarchive/data_extract_all.c
index bd264dd7..8b1ee2a6 100644
--- a/release/src/router/busybox/archival/libunarchive/data_extract_all.c
+++ b/release/src/router/busybox/archival/libunarchive/data_extract_all.c
@@ -1,100 +1,148 @@
+/* vi: set sw=4 ts=4: */
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <sys/types.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <utime.h>
-#include <unistd.h>
-#include <stdlib.h>
-
#include "libbb.h"
#include "unarchive.h"
-extern void data_extract_all(archive_handle_t *archive_handle)
+void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
{
file_header_t *file_header = archive_handle->file_header;
int dst_fd;
int res;
- if (archive_handle->flags & ARCHIVE_CREATE_LEADING_DIRS) {
- char *name = bb_xstrdup(file_header->name);
- bb_make_directory (dirname(name), 0777, FILEUTILS_RECUR);
+ if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) {
+ char *name = xstrdup(file_header->name);
+ bb_make_directory(dirname(name), -1, FILEUTILS_RECUR);
free(name);
- }
+ }
- /* Create the filesystem entry */
- switch(file_header->mode & S_IFMT) {
- case S_IFREG: {
-#ifdef CONFIG_CPIO
- if (file_header->link_name && file_header->size == 0) {
- /* hard link */
- res = link(file_header->link_name, file_header->name);
- if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
- bb_perror_msg("Couldnt create hard link");
- }
- } else
-#endif
- {
- /* Regular file */
- unlink(file_header->name);
- dst_fd = bb_xopen(file_header->name, O_WRONLY | O_CREAT | O_EXCL);
- archive_copy_file(archive_handle, dst_fd);
- close(dst_fd);
+ /* Check if the file already exists */
+ if (archive_handle->ah_flags & ARCHIVE_EXTRACT_UNCONDITIONAL) {
+ /* Remove the entry if it exists */
+ if (((file_header->mode & S_IFMT) != S_IFDIR)
+ && (unlink(file_header->name) == -1)
+ && (errno != ENOENT)
+ ) {
+ bb_perror_msg_and_die("cannot remove old file %s",
+ file_header->name);
+ }
+ }
+ else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) {
+ /* Remove the existing entry if its older than the extracted entry */
+ struct stat statbuf;
+ if (lstat(file_header->name, &statbuf) == -1) {
+ if (errno != ENOENT) {
+ bb_perror_msg_and_die("cannot stat old file");
+ }
+ }
+ else if (statbuf.st_mtime <= file_header->mtime) {
+ if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) {
+ bb_error_msg("%s not created: newer or "
+ "same age file exists", file_header->name);
}
+ data_skip(archive_handle);
+ return;
+ }
+ else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) {
+ bb_perror_msg_and_die("cannot remove old file %s",
+ file_header->name);
+ }
+ }
+
+ /* Handle hard links separately
+ * We identified hard links as regular files of size 0 with a symlink */
+ if (S_ISREG(file_header->mode) && (file_header->link_target)
+ && (file_header->size == 0)
+ ) {
+ /* hard link */
+ res = link(file_header->link_target, file_header->name);
+ if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) {
+ bb_perror_msg("cannot create %slink "
+ "from %s to %s", "hard",
+ file_header->name,
+ file_header->link_target);
+ }
+ } else {
+ /* Create the filesystem entry */
+ switch (file_header->mode & S_IFMT) {
+ case S_IFREG: {
+ /* Regular file */
+ dst_fd = xopen3(file_header->name, O_WRONLY | O_CREAT | O_EXCL,
+ file_header->mode);
+ bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size);
+ close(dst_fd);
break;
}
case S_IFDIR:
- unlink(file_header->name);
res = mkdir(file_header->name, file_header->mode);
- if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
- bb_perror_msg("extract_archive: %s", file_header->name);
+ if ((res == -1)
+ && (errno != EISDIR) /* btw, Linux doesn't return this */
+ && (errno != EEXIST)
+ && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
+ ) {
+ bb_perror_msg("cannot make dir %s", file_header->name);
}
break;
case S_IFLNK:
/* Symlink */
- unlink(file_header->name);
- res = symlink(file_header->link_name, file_header->name);
- if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
- bb_perror_msg("Cannot create symlink from %s to '%s'", file_header->name, file_header->link_name);
+ res = symlink(file_header->link_target, file_header->name);
+ if ((res == -1)
+ && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
+ ) {
+ bb_perror_msg("cannot create %slink "
+ "from %s to %s", "sym",
+ file_header->name,
+ file_header->link_target);
}
break;
case S_IFSOCK:
case S_IFBLK:
case S_IFCHR:
case S_IFIFO:
- unlink(file_header->name);
res = mknod(file_header->name, file_header->mode, file_header->device);
- if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
- bb_perror_msg("Cannot create node %s", file_header->name);
+ if ((res == -1)
+ && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
+ ) {
+ bb_perror_msg("cannot create node %s", file_header->name);
}
break;
default:
- bb_error_msg_and_die("Unrecognised file type");
+ bb_error_msg_and_die("unrecognized file type");
+ }
}
- chmod(file_header->name, file_header->mode);
- chown(file_header->name, file_header->uid, file_header->gid);
+ if (!(archive_handle->ah_flags & ARCHIVE_NOPRESERVE_OWN)) {
+#if ENABLE_FEATURE_TAR_UNAME_GNAME
+ uid_t uid = file_header->uid;
+ gid_t gid = file_header->gid;
- if (archive_handle->flags & ARCHIVE_PRESERVE_DATE) {
- struct utimbuf t;
- t.actime = t.modtime = file_header->mtime;
- utime(file_header->name, &t);
+ if (file_header->uname) {
+ struct passwd *pwd = getpwnam(file_header->uname);
+ if (pwd) uid = pwd->pw_uid;
+ }
+ if (file_header->gname) {
+ struct group *grp = getgrnam(file_header->gname);
+ if (grp) gid = grp->gr_gid;
+ }
+ lchown(file_header->name, uid, gid);
+#else
+ lchown(file_header->name, file_header->uid, file_header->gid);
+#endif
+ }
+ if ((file_header->mode & S_IFMT) != S_IFLNK) {
+ /* uclibc has no lchmod, glibc is even stranger -
+ * it has lchmod which seems to do nothing!
+ * so we use chmod... */
+ if (!(archive_handle->ah_flags & ARCHIVE_NOPRESERVE_PERM)) {
+ chmod(file_header->name, file_header->mode);
+ }
+ /* same for utime */
+ if (archive_handle->ah_flags & ARCHIVE_PRESERVE_DATE) {
+ struct utimbuf t;
+ t.actime = t.modtime = file_header->mtime;
+ utime(file_header->name, &t);
+ }
}
}
diff --git a/release/src/router/busybox/archival/libunarchive/data_extract_to_buffer.c b/release/src/router/busybox/archival/libunarchive/data_extract_to_buffer.c
index db5521bc..1d74e033 100644
--- a/release/src/router/busybox/archival/libunarchive/data_extract_to_buffer.c
+++ b/release/src/router/busybox/archival/libunarchive/data_extract_to_buffer.c
@@ -1,28 +1,17 @@
+/* vi: set sw=4 ts=4: */
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * Copyright 2002 Glenn McGrath
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
#include "libbb.h"
#include "unarchive.h"
-extern void data_extract_to_buffer(archive_handle_t *archive_handle)
+void FAST_FUNC data_extract_to_buffer(archive_handle_t *archive_handle)
{
- const unsigned int size = archive_handle->file_header->size;
-
- archive_handle->buffer = xmalloc(size + 1);
+ unsigned int size = archive_handle->file_header->size;
- archive_xread_all(archive_handle, archive_handle->buffer, size);
- archive_handle->buffer[size] = '\0';
+ archive_handle->buffer = xzalloc(size + 1);
+ xread(archive_handle->src_fd, archive_handle->buffer, size);
}
diff --git a/release/src/router/busybox/archival/libunarchive/data_extract_to_stdout.c b/release/src/router/busybox/archival/libunarchive/data_extract_to_stdout.c
index 8be2fa2e..a3efea16 100644
--- a/release/src/router/busybox/archival/libunarchive/data_extract_to_stdout.c
+++ b/release/src/router/busybox/archival/libunarchive/data_extract_to_stdout.c
@@ -1,22 +1,14 @@
+/* vi: set sw=4 ts=4: */
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
+#include "libbb.h"
#include "unarchive.h"
-extern void data_extract_to_stdout(archive_handle_t *archive_handle)
+void FAST_FUNC data_extract_to_stdout(archive_handle_t *archive_handle)
{
- archive_copy_file(archive_handle, fileno(stdout));
+ bb_copyfd_exact_size(archive_handle->src_fd,
+ STDOUT_FILENO,
+ archive_handle->file_header->size);
}
diff --git a/release/src/router/busybox/archival/libunarchive/data_skip.c b/release/src/router/busybox/archival/libunarchive/data_skip.c
index b82c9065..438750fe 100644
--- a/release/src/router/busybox/archival/libunarchive/data_skip.c
+++ b/release/src/router/busybox/archival/libunarchive/data_skip.c
@@ -1,27 +1,12 @@
+/* vi: set sw=4 ts=4: */
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <sys/types.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "unarchive.h"
#include "libbb.h"
+#include "unarchive.h"
-extern void data_skip(archive_handle_t *archive_handle)
+void FAST_FUNC data_skip(archive_handle_t *archive_handle)
{
archive_handle->seek(archive_handle, archive_handle->file_header->size);
}
diff --git a/release/src/router/busybox/archival/libunarchive/decompress_bunzip2.c b/release/src/router/busybox/archival/libunarchive/decompress_bunzip2.c
index 0164b77e..b53720f2 100644
--- a/release/src/router/busybox/archival/libunarchive/decompress_bunzip2.c
+++ b/release/src/router/busybox/archival/libunarchive/decompress_bunzip2.c
@@ -1,1658 +1,724 @@
-/*--
- This file is a part of bzip2 and/or libbzip2, a program and
- library for lossless, block-sorting data compression.
-
- Copyright (C) 1996-2000 Julian R Seward. 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. The origin of this software must not be misrepresented; you must
- not claim that you wrote the original software. If you use this
- software in a product, an acknowledgment in the product
- documentation would be appreciated but is not required.
-
- 3. Altered source versions must be plainly marked as such, and must
- not be misrepresented as being the original software.
-
- 4. The name of the author may not be used to endorse or promote
- products derived from this software without specific prior written
- permission.
-
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
-
- Julian Seward, Cambridge, UK.
- jseward@acm.org
- bzip2/libbzip2 version 1.0 of 21 March 2000
-
- This program is based on (at least) the work of:
- Mike Burrows
- David Wheeler
- Peter Fenwick
- Alistair Moffat
- Radford Neal
- Ian H. Witten
- Robert Sedgewick
- Jon L. Bentley
-
- For more information on these sources, see the manual.
---*/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <getopt.h>
-#include <unistd.h>
-
-#include "busybox.h"
-
-#define MTFA_SIZE 4096
-#define MTFL_SIZE 16
-#define BZ_N_GROUPS 6
-#define BZ_G_SIZE 50
-#define BZ_MAX_ALPHA_SIZE 258
-
-#define BZ_OK 0
-#define BZ_STREAM_END 4
-#define BZ_SEQUENCE_ERROR (-1)
-#define BZ_DATA_ERROR (-4)
-#define BZ_DATA_ERROR_MAGIC (-5)
-#define BZ_IO_ERROR (-6)
-#define BZ_UNEXPECTED_EOF (-7)
-
-#define BZ_RUNA 0
-#define BZ_RUNB 1
-
-#define BZ_MAX_UNUSED 5000
-#define FILE_NAME_LEN 1034
-/*-- states for decompression. --*/
-
-#define BZ_X_IDLE 1
-#define BZ_X_OUTPUT 2
-
-#define BZ_X_MAGIC_1 10
-#define BZ_X_MAGIC_2 11
-#define BZ_X_MAGIC_3 12
-#define BZ_X_MAGIC_4 13
-#define BZ_X_BLKHDR_1 14
-#define BZ_X_BLKHDR_2 15
-#define BZ_X_BLKHDR_3 16
-#define BZ_X_BLKHDR_4 17
-#define BZ_X_BLKHDR_5 18
-#define BZ_X_BLKHDR_6 19
-#define BZ_X_BCRC_1 20
-#define BZ_X_BCRC_2 21
-#define BZ_X_BCRC_3 22
-#define BZ_X_BCRC_4 23
-#define BZ_X_RANDBIT 24
-#define BZ_X_ORIGPTR_1 25
-#define BZ_X_ORIGPTR_2 26
-#define BZ_X_ORIGPTR_3 27
-#define BZ_X_MAPPING_1 28
-#define BZ_X_MAPPING_2 29
-#define BZ_X_SELECTOR_1 30
-#define BZ_X_SELECTOR_2 31
-#define BZ_X_SELECTOR_3 32
-#define BZ_X_CODING_1 33
-#define BZ_X_CODING_2 34
-#define BZ_X_CODING_3 35
-#define BZ_X_MTF_1 36
-#define BZ_X_MTF_2 37
-#define BZ_X_MTF_3 38
-#define BZ_X_MTF_4 39
-#define BZ_X_MTF_5 40
-#define BZ_X_MTF_6 41
-#define BZ_X_ENDHDR_2 42
-#define BZ_X_ENDHDR_3 43
-#define BZ_X_ENDHDR_4 44
-#define BZ_X_ENDHDR_5 45
-#define BZ_X_ENDHDR_6 46
-#define BZ_X_CCRC_1 47
-#define BZ_X_CCRC_2 48
-#define BZ_X_CCRC_3 49
-#define BZ_X_CCRC_4 50
-
-#define BZ_MAX_CODE_LEN 23
-#define OM_TEST 3
-
-typedef struct {
- char *next_in;
- unsigned int avail_in;
-
- char *next_out;
- unsigned int avail_out;
-
- void *state;
-
-} bz_stream;
-
-#define BZ_MAX_UNUSED 5000
-typedef struct {
- bz_stream strm;
- int fd;
- unsigned char initialisedOk;
- char buf[BZ_MAX_UNUSED];
- int lastErr;
- int bufN;
-} bzFile;
-
-/*-- Structure holding all the decompression-side stuff. --*/
-typedef struct {
- /* pointer back to the struct bz_stream */
- bz_stream* strm;
-
- /* state indicator for this stream */
- int state;
-
- /* for doing the final run-length decoding */
- unsigned char state_out_ch;
- int state_out_len;
- unsigned char blockRandomised;
- int rNToGo;
- int rTPos;
-
- /* the buffer for bit stream reading */
- unsigned int bsBuff;
- int bsLive;
-
- /* misc administratium */
- int blockSize100k;
- int currBlockNo;
-
- /* for undoing the Burrows-Wheeler transform */
- int origPtr;
- unsigned int tPos;
- int k0;
- int unzftab[256];
- int nblock_used;
- int cftab[257];
- int cftabCopy[257];
-
- /* for undoing the Burrows-Wheeler transform (FAST) */
- unsigned int *tt;
-
- /* stored and calculated CRCs */
- unsigned int storedBlockCRC;
- unsigned int storedCombinedCRC;
- unsigned int calculatedBlockCRC;
- unsigned int calculatedCombinedCRC;
-
- /* map of bytes used in block */
- int nInUse;
- unsigned char inUse[256];
- unsigned char inUse16[16];
- unsigned char seqToUnseq[256];
-
- /* for decoding the MTF values */
- unsigned char mtfa [MTFA_SIZE];
- unsigned char selector [2 + (900000 / BZ_G_SIZE)];
- unsigned char selectorMtf[2 + (900000 / BZ_G_SIZE)];
- unsigned char len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
- int mtfbase[256 / MTFL_SIZE];
-
- int limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
- int base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
- int perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
- int minLens[BZ_N_GROUPS];
-
- /* save area for scalars in the main decompress code */
- int save_i;
- int save_j;
- int save_t;
- int save_alphaSize;
- int save_nGroups;
- int save_nSelectors;
- int save_EOB;
- int save_groupNo;
- int save_groupPos;
- int save_nextSym;
- int save_nblockMAX;
- int save_nblock;
- int save_es;
- int save_N;
- int save_curr;
- int save_zt;
- int save_zn;
- int save_zvec;
- int save_zj;
- int save_gSel;
- int save_gMinlen;
- int *save_gLimit;
- int *save_gBase;
- int *save_gPerm;
-} DState;
-
-static int BZ2_rNums[512];
-static bzFile *bzf;
-static int bzerr = BZ_OK;
-
-static const unsigned int BZ2_crc32Table[256] = {
-
- /*-- Ugly, innit? --*/
-
- 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L,
- 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L,
- 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L,
- 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL,
- 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L,
- 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L,
- 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L,
- 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL,
- 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L,
- 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L,
- 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L,
- 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL,
- 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L,
- 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L,
- 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L,
- 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL,
- 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL,
- 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L,
- 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L,
- 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL,
- 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL,
- 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L,
- 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L,
- 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL,
- 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL,
- 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L,
- 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L,
- 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL,
- 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL,
- 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L,
- 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L,
- 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL,
- 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L,
- 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL,
- 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL,
- 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L,
- 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L,
- 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL,
- 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL,
- 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L,
- 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L,
- 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL,
- 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL,
- 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L,
- 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L,
- 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL,
- 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL,
- 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L,
- 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L,
- 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL,
- 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L,
- 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L,
- 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L,
- 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL,
- 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L,
- 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L,
- 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L,
- 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL,
- 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L,
- 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L,
- 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L,
- 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL,
- 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L,
- 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L
+/* vi: set sw=4 ts=4: */
+/* Small bzip2 deflate implementation, by Rob Landley (rob@landley.net).
+
+ Based on bzip2 decompression code by Julian R Seward (jseward@acm.org),
+ which also acknowledges contributions by Mike Burrows, David Wheeler,
+ Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten,
+ Robert Sedgewick, and Jon L. Bentley.
+
+ Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+*/
+
+/*
+ Size and speed optimizations by Manuel Novoa III (mjn3@codepoet.org).
+
+ More efficient reading of Huffman codes, a streamlined read_bunzip()
+ function, and various other tweaks. In (limited) tests, approximately
+ 20% faster than bzcat on x86 and about 10% faster on arm.
+
+ Note that about 2/3 of the time is spent in read_unzip() reversing
+ the Burrows-Wheeler transformation. Much of that time is delay
+ resulting from cache misses.
+
+ I would ask that anyone benefiting from this work, especially those
+ using it in commercial products, consider making a donation to my local
+ non-profit hospice organization (www.hospiceacadiana.com) in the name of
+ the woman I loved, Toni W. Hagan, who passed away Feb. 12, 2003.
+
+ Manuel
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+/* Constants for Huffman coding */
+#define MAX_GROUPS 6
+#define GROUP_SIZE 50 /* 64 would have been more efficient */
+#define MAX_HUFCODE_BITS 20 /* Longest Huffman code allowed */
+#define MAX_SYMBOLS 258 /* 256 literals + RUNA + RUNB */
+#define SYMBOL_RUNA 0
+#define SYMBOL_RUNB 1
+
+/* Status return values */
+#define RETVAL_OK 0
+#define RETVAL_LAST_BLOCK (-1)
+#define RETVAL_NOT_BZIP_DATA (-2)
+#define RETVAL_UNEXPECTED_INPUT_EOF (-3)
+#define RETVAL_SHORT_WRITE (-4)
+#define RETVAL_DATA_ERROR (-5)
+#define RETVAL_OUT_OF_MEMORY (-6)
+#define RETVAL_OBSOLETE_INPUT (-7)
+
+/* Other housekeeping constants */
+#define IOBUF_SIZE 4096
+
+/* This is what we know about each Huffman coding group */
+struct group_data {
+ /* We have an extra slot at the end of limit[] for a sentinel value. */
+ int limit[MAX_HUFCODE_BITS+1], base[MAX_HUFCODE_BITS], permute[MAX_SYMBOLS];
+ int minLen, maxLen;
};
-static void bz_rand_udp_mask(DState *s)
-{
- if (s->rNToGo == 0) {
- s->rNToGo = BZ2_rNums[s->rTPos];
- s->rTPos++;
- if (s->rTPos == 512) {
- s->rTPos = 0;
- }
- }
- s->rNToGo--;
-}
-
-static void BZ2_hbCreateDecodeTables(int *limit, int *base, int *perm, unsigned char *length, int minLen, int maxLen, int alphaSize )
-{
- int pp, i, j, vec;
-
- pp = 0;
- for (i = minLen; i <= maxLen; i++) {
- for (j = 0; j < alphaSize; j++) {
- if (length[j] == i) {
- perm[pp] = j;
- pp++;
- }
- }
- }
-
- for (i = 0; i < BZ_MAX_CODE_LEN; i++) {
- base[i] = 0;
- }
-
- for (i = 0; i < alphaSize; i++) {
- base[length[i]+1]++;
- }
-
- for (i = 1; i < BZ_MAX_CODE_LEN; i++) {
- base[i] += base[i-1];
- }
-
- for (i = 0; i < BZ_MAX_CODE_LEN; i++) {
- limit[i] = 0;
- }
- vec = 0;
+/* Structure holding all the housekeeping data, including IO buffers and
+ * memory that persists between calls to bunzip
+ * Found the most used member:
+ * cat this_file.c | sed -e 's/"/ /g' -e "s/'/ /g" | xargs -n1 \
+ * | grep 'bd->' | sed 's/^.*bd->/bd->/' | sort | $PAGER
+ * and moved it (inbufBitCount) to offset 0.
+ */
+struct bunzip_data {
+ /* I/O tracking data (file handles, buffers, positions, etc.) */
+ unsigned inbufBitCount, inbufBits;
+ int in_fd, out_fd, inbufCount, inbufPos /*, outbufPos*/;
+ unsigned char *inbuf /*,*outbuf*/;
+
+ /* State for interrupting output loop */
+ int writeCopies, writePos, writeRunCountdown, writeCount, writeCurrent;
+
+ /* The CRC values stored in the block header and calculated from the data */
+ uint32_t headerCRC, totalCRC, writeCRC;
+
+ /* Intermediate buffer and its size (in bytes) */
+ unsigned *dbuf, dbufSize;
+
+ /* For I/O error handling */
+ jmp_buf jmpbuf;
+
+ /* Big things go last (register-relative addressing can be larger for big offsets) */
+ uint32_t crc32Table[256];
+ unsigned char selectors[32768]; /* nSelectors=15 bits */
+ struct group_data groups[MAX_GROUPS]; /* Huffman coding tables */
+};
+/* typedef struct bunzip_data bunzip_data; -- done in .h file */
- for (i = minLen; i <= maxLen; i++) {
- vec += (base[i+1] - base[i]);
- limit[i] = vec-1;
- vec <<= 1;
- }
- for (i = minLen + 1; i <= maxLen; i++) {
- base[i] = ((limit[i-1] + 1) << 1) - base[i];
- }
-}
+/* Return the next nnn bits of input. All reads from the compressed input
+ are done through this function. All reads are big endian */
-static int get_bits(DState *s, int *vvv, char nnn)
+static unsigned get_bits(bunzip_data *bd, int bits_wanted)
{
- while (1) {
- if (s->bsLive >= nnn) {
- *vvv = (s->bsBuff >> (s->bsLive-nnn)) & ((1 << nnn)-1);
- s->bsLive -= nnn;
- break;
+ unsigned bits = 0;
+
+ /* If we need to get more data from the byte buffer, do so. (Loop getting
+ one byte at a time to enforce endianness and avoid unaligned access.) */
+ while ((int)(bd->inbufBitCount) < bits_wanted) {
+
+ /* If we need to read more data from file into byte buffer, do so */
+ if (bd->inbufPos == bd->inbufCount) {
+ /* if "no input fd" case: in_fd == -1, read fails, we jump */
+ bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE);
+ if (bd->inbufCount <= 0)
+ longjmp(bd->jmpbuf, RETVAL_UNEXPECTED_INPUT_EOF);
+ bd->inbufPos = 0;
}
- if (s->strm->avail_in == 0) {
- return(FALSE);
+
+ /* Avoid 32-bit overflow (dump bit buffer to top of output) */
+ if (bd->inbufBitCount >= 24) {
+ bits = bd->inbufBits & ((1 << bd->inbufBitCount) - 1);
+ bits_wanted -= bd->inbufBitCount;
+ bits <<= bits_wanted;
+ bd->inbufBitCount = 0;
}
- s->bsBuff = (s->bsBuff << 8) | ((unsigned int) (*((unsigned char*)(s->strm->next_in))));
- s->bsLive += 8;
- s->strm->next_in++;
- s->strm->avail_in--;
+
+ /* Grab next 8 bits of input from buffer. */
+ bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++];
+ bd->inbufBitCount += 8;
}
- return(TRUE);
-}
-static int bz_get_fast(DState *s)
-{
- int cccc;
- s->tPos = s->tt[s->tPos];
- cccc = (unsigned char)(s->tPos & 0xff);
- s->tPos >>= 8;
- return(cccc);
+ /* Calculate result */
+ bd->inbufBitCount -= bits_wanted;
+ bits |= (bd->inbufBits >> bd->inbufBitCount) & ((1 << bits_wanted) - 1);
+
+ return bits;
}
-/*---------------------------------------------------*/
-static inline int BZ2_decompress(DState *s)
+/* Unpacks the next block and sets up for the inverse burrows-wheeler step. */
+static int get_next_block(bunzip_data *bd)
{
- int uc = 0;
- int retVal;
- int minLen, maxLen;
-
- /* stuff that needs to be saved/restored */
- int i;
- int j;
- int t;
- int alphaSize;
- int nGroups;
- int nSelectors;
- int EOB;
- int groupNo;
- int groupPos;
- int nextSym;
- int nblockMAX;
- int nblock;
- int es;
- int N;
- int curr;
- int zt;
- int zn;
- int zvec;
- int zj;
- int gSel;
- int gMinlen;
- int *gLimit;
- int *gBase;
- int *gPerm;
- int switch_val;
-
- int get_mtf_val_init(void)
- {
- if (groupPos == 0) {
- groupNo++;
- if (groupNo >= nSelectors) {
- retVal = BZ_DATA_ERROR;
- return(FALSE);
- }
- groupPos = BZ_G_SIZE;
- gSel = s->selector[groupNo];
- gMinlen = s->minLens[gSel];
- gLimit = &(s->limit[gSel][0]);
- gPerm = &(s->perm[gSel][0]);
- gBase = &(s->base[gSel][0]);
+ struct group_data *hufGroup;
+ int dbufCount, nextSym, dbufSize, groupCount, *base, *limit, selector,
+ i, j, k, t, runPos, symCount, symTotal, nSelectors, byteCount[256];
+ unsigned char uc, symToByte[256], mtfSymbol[256], *selectors;
+ unsigned *dbuf, origPtr;
+
+ dbuf = bd->dbuf;
+ dbufSize = bd->dbufSize;
+ selectors = bd->selectors;
+
+ /* Reset longjmp I/O error handling */
+ i = setjmp(bd->jmpbuf);
+ if (i) return i;
+
+ /* Read in header signature and CRC, then validate signature.
+ (last block signature means CRC is for whole file, return now) */
+ i = get_bits(bd, 24);
+ j = get_bits(bd, 24);
+ bd->headerCRC = get_bits(bd, 32);
+ if ((i == 0x177245) && (j == 0x385090)) return RETVAL_LAST_BLOCK;
+ if ((i != 0x314159) || (j != 0x265359)) return RETVAL_NOT_BZIP_DATA;
+
+ /* We can add support for blockRandomised if anybody complains. There was
+ some code for this in busybox 1.0.0-pre3, but nobody ever noticed that
+ it didn't actually work. */
+ if (get_bits(bd, 1)) return RETVAL_OBSOLETE_INPUT;
+ origPtr = get_bits(bd, 24);
+ if ((int)origPtr > dbufSize) return RETVAL_DATA_ERROR;
+
+ /* mapping table: if some byte values are never used (encoding things
+ like ascii text), the compression code removes the gaps to have fewer
+ symbols to deal with, and writes a sparse bitfield indicating which
+ values were present. We make a translation table to convert the symbols
+ back to the corresponding bytes. */
+ t = get_bits(bd, 16);
+ symTotal = 0;
+ for (i = 0; i < 16; i++) {
+ if (t & (1 << (15-i))) {
+ k = get_bits(bd, 16);
+ for (j = 0; j < 16; j++)
+ if (k & (1 << (15-j)))
+ symToByte[symTotal++] = (16*i) + j;
}
- groupPos--;
- zn = gMinlen;
- return(TRUE);
}
- if (s->state == BZ_X_MAGIC_1) {
- /*initialise the save area*/
- s->save_i = 0;
- s->save_j = 0;
- s->save_t = 0;
- s->save_alphaSize = 0;
- s->save_nGroups = 0;
- s->save_nSelectors = 0;
- s->save_EOB = 0;
- s->save_groupNo = 0;
- s->save_groupPos = 0;
- s->save_nextSym = 0;
- s->save_nblockMAX = 0;
- s->save_nblock = 0;
- s->save_es = 0;
- s->save_N = 0;
- s->save_curr = 0;
- s->save_zt = 0;
- s->save_zn = 0;
- s->save_zvec = 0;
- s->save_zj = 0;
- s->save_gSel = 0;
- s->save_gMinlen = 0;
- s->save_gLimit = NULL;
- s->save_gBase = NULL;
- s->save_gPerm = NULL;
+ /* How many different Huffman coding groups does this block use? */
+ groupCount = get_bits(bd, 3);
+ if (groupCount < 2 || groupCount > MAX_GROUPS)
+ return RETVAL_DATA_ERROR;
+
+ /* nSelectors: Every GROUP_SIZE many symbols we select a new Huffman coding
+ group. Read in the group selector list, which is stored as MTF encoded
+ bit runs. (MTF=Move To Front, as each value is used it's moved to the
+ start of the list.) */
+ nSelectors = get_bits(bd, 15);
+ if (!nSelectors) return RETVAL_DATA_ERROR;
+ for (i = 0; i < groupCount; i++) mtfSymbol[i] = i;
+ for (i = 0; i < nSelectors; i++) {
+
+ /* Get next value */
+ for (j = 0; get_bits(bd, 1); j++)
+ if (j >= groupCount) return RETVAL_DATA_ERROR;
+
+ /* Decode MTF to get the next selector */
+ uc = mtfSymbol[j];
+ for (;j;j--) mtfSymbol[j] = mtfSymbol[j-1];
+ mtfSymbol[0] = selectors[i] = uc;
}
- /*restore from the save area*/
- i = s->save_i;
- j = s->save_j;
- t = s->save_t;
- alphaSize = s->save_alphaSize;
- nGroups = s->save_nGroups;
- nSelectors = s->save_nSelectors;
- EOB = s->save_EOB;
- groupNo = s->save_groupNo;
- groupPos = s->save_groupPos;
- nextSym = s->save_nextSym;
- nblockMAX = s->save_nblockMAX;
- nblock = s->save_nblock;
- es = s->save_es;
- N = s->save_N;
- curr = s->save_curr;
- zt = s->save_zt;
- zn = s->save_zn;
- zvec = s->save_zvec;
- zj = s->save_zj;
- gSel = s->save_gSel;
- gMinlen = s->save_gMinlen;
- gLimit = s->save_gLimit;
- gBase = s->save_gBase;
- gPerm = s->save_gPerm;
-
- retVal = BZ_OK;
- switch_val = s->state;
- switch (switch_val) {
- case BZ_X_MAGIC_1:
- s->state = BZ_X_MAGIC_1;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc != 'B') {
- retVal = BZ_DATA_ERROR_MAGIC;
- goto save_state_and_return;
- }
-
- case BZ_X_MAGIC_2:
- s->state = BZ_X_MAGIC_2;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc != 'Z') {
- retVal = BZ_DATA_ERROR_MAGIC;
- goto save_state_and_return;
- }
-
- case BZ_X_MAGIC_3:
- s->state = BZ_X_MAGIC_3;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc != 'h') {
- retVal = BZ_DATA_ERROR_MAGIC;
- goto save_state_and_return;
- }
-
- case BZ_X_MAGIC_4:
- s->state = BZ_X_MAGIC_4;
- if (! get_bits(s, &s->blockSize100k, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if ((s->blockSize100k < '1') || (s->blockSize100k > '9')) {
- retVal = BZ_DATA_ERROR_MAGIC;
- goto save_state_and_return;
- }
- s->blockSize100k -= '0';
-
- s->tt = xmalloc(s->blockSize100k * 100000 * sizeof(int));
-
- case BZ_X_BLKHDR_1:
- s->state = BZ_X_BLKHDR_1;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
-
- if (uc == 0x17) {
- goto endhdr_2;
- }
- if (uc != 0x31) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
-
- case BZ_X_BLKHDR_2:
- s->state = BZ_X_BLKHDR_2;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc != 0x41) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
-
- case BZ_X_BLKHDR_3:
- s->state = BZ_X_BLKHDR_3;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc != 0x59) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
-
- case BZ_X_BLKHDR_4:
- s->state = BZ_X_BLKHDR_4;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc != 0x26) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
-
- case BZ_X_BLKHDR_5:
- s->state = BZ_X_BLKHDR_5;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc != 0x53) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
-
- case BZ_X_BLKHDR_6:
- s->state = BZ_X_BLKHDR_6;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc != 0x59) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
-
- s->currBlockNo++;
- s->storedBlockCRC = 0;
-
- case BZ_X_BCRC_1:
- s->state = BZ_X_BCRC_1;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- s->storedBlockCRC = (s->storedBlockCRC << 8) | ((unsigned int)uc);
-
- case BZ_X_BCRC_2:
- s->state = BZ_X_BCRC_2;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- s->storedBlockCRC = (s->storedBlockCRC << 8) | ((unsigned int)uc);
-
- case BZ_X_BCRC_3:
- s->state = BZ_X_BCRC_3;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- s->storedBlockCRC = (s->storedBlockCRC << 8) | ((unsigned int)uc);
-
- case BZ_X_BCRC_4:
- s->state = BZ_X_BCRC_4;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- s->storedBlockCRC = (s->storedBlockCRC << 8) | ((unsigned int)uc);
-
- case BZ_X_RANDBIT:
- s->state = BZ_X_RANDBIT;
- {
- int tmp = s->blockRandomised;
- const int ret = get_bits(s, &tmp, 1);
- s->blockRandomised = tmp;
- if (! ret) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- }
-
- s->origPtr = 0;
-
- case BZ_X_ORIGPTR_1:
- s->state = BZ_X_ORIGPTR_1;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- s->origPtr = (s->origPtr << 8) | ((int)uc);
-
- case BZ_X_ORIGPTR_2:
- s->state = BZ_X_ORIGPTR_2;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- s->origPtr = (s->origPtr << 8) | ((int)uc);
-
- case BZ_X_ORIGPTR_3:
- s->state = BZ_X_ORIGPTR_3;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- s->origPtr = (s->origPtr << 8) | ((int)uc);
-
- if (s->origPtr < 0) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
- if (s->origPtr > 10 + 100000*s->blockSize100k) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
-
- /*--- Receive the mapping table ---*/
- case BZ_X_MAPPING_1:
- for (i = 0; i < 16; i++) {
- s->state = BZ_X_MAPPING_1;
- if (! get_bits(s, &uc, 1)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc == 1) {
- s->inUse16[i] = TRUE;
- } else {
- s->inUse16[i] = FALSE;
- }
- }
-
- for (i = 0; i < 256; i++) {
- s->inUse[i] = FALSE;
- }
-
- for (i = 0; i < 16; i++) {
- if (s->inUse16[i]) {
- for (j = 0; j < 16; j++) {
- case BZ_X_MAPPING_2:
- s->state = BZ_X_MAPPING_2;
- if (! get_bits(s, &uc, 1)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc == 1) {
- s->inUse[i * 16 + j] = TRUE;
- }
- }
- }
- }
-
- s->nInUse = 0;
- for (i = 0; i < 256; i++) {
- if (s->inUse[i]) {
- s->seqToUnseq[s->nInUse] = i;
- s->nInUse++;
- }
- }
- if (s->nInUse == 0) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
- alphaSize = s->nInUse+2;
-
- /*--- Now the selectors ---*/
- case BZ_X_SELECTOR_1:
- s->state = BZ_X_SELECTOR_1;
- if (! get_bits(s, &nGroups, 3)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (nGroups < 2 || nGroups > 6) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
-
- case BZ_X_SELECTOR_2:
- s->state = BZ_X_SELECTOR_2;
- if (! get_bits(s, &nSelectors, 15)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (nSelectors < 1) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
-
-
-
- for (i = 0; i < nSelectors; i++) {
- j = 0;
- while (1) {
- case BZ_X_SELECTOR_3:
- s->state = BZ_X_SELECTOR_3;
- if (! get_bits(s, &uc, 1)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc == 0) {
- break;
- }
- j++;
- if (j >= nGroups) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
+ /* Read the Huffman coding tables for each group, which code for symTotal
+ literal symbols, plus two run symbols (RUNA, RUNB) */
+ symCount = symTotal + 2;
+ for (j = 0; j < groupCount; j++) {
+ unsigned char length[MAX_SYMBOLS];
+ /* 8 bits is ALMOST enough for temp[], see below */
+ unsigned temp[MAX_HUFCODE_BITS+1];
+ int minLen, maxLen, pp;
+
+ /* Read Huffman code lengths for each symbol. They're stored in
+ a way similar to mtf; record a starting value for the first symbol,
+ and an offset from the previous value for everys symbol after that.
+ (Subtracting 1 before the loop and then adding it back at the end is
+ an optimization that makes the test inside the loop simpler: symbol
+ length 0 becomes negative, so an unsigned inequality catches it.) */
+ t = get_bits(bd, 5) - 1;
+ for (i = 0; i < symCount; i++) {
+ for (;;) {
+ if ((unsigned)t > (MAX_HUFCODE_BITS-1))
+ return RETVAL_DATA_ERROR;
+
+ /* If first bit is 0, stop. Else second bit indicates whether
+ to increment or decrement the value. Optimization: grab 2
+ bits and unget the second if the first was 0. */
+ k = get_bits(bd, 2);
+ if (k < 2) {
+ bd->inbufBitCount++;
+ break;
}
- s->selectorMtf[i] = j;
- }
- /*--- Undo the MTF values for the selectors. ---*/
- {
- unsigned char pos[BZ_N_GROUPS], tmp, v;
- for (v = 0; v < nGroups; v++) {
- pos[v] = v;
- }
- for (i = 0; i < nSelectors; i++) {
- v = s->selectorMtf[i];
- tmp = pos[v];
- while (v > 0) {
- pos[v] = pos[v-1];
- v--;
- }
- pos[0] = tmp;
- s->selector[i] = tmp;
- }
+ /* Add one if second bit 1, else subtract 1. Avoids if/else */
+ t += (((k+1) & 2) - 1);
}
- /*--- Now the coding tables ---*/
- for (t = 0; t < nGroups; t++) {
- case BZ_X_CODING_1:
- s->state = BZ_X_CODING_1;
- if (! get_bits(s, &curr, 5)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- for (i = 0; i < alphaSize; i++) {
- while (TRUE) {
- if (curr < 1 || curr > 20) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
-
- case BZ_X_CODING_2:
- s->state = BZ_X_CODING_2;
- if (! get_bits(s, &uc, 1)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc == 0) {
- break;
- }
-
- case BZ_X_CODING_3:
- s->state = BZ_X_CODING_3;
- if (! get_bits(s, &uc, 1)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc == 0) {
- curr++;
- } else {
- curr--;
- }
- }
- s->len[t][i] = curr;
- }
+ /* Correct for the initial -1, to get the final symbol length */
+ length[i] = t + 1;
}
- /*--- Create the Huffman decoding tables ---*/
- for (t = 0; t < nGroups; t++) {
- minLen = 32;
- maxLen = 0;
- for (i = 0; i < alphaSize; i++) {
- if (s->len[t][i] > maxLen) {
- maxLen = s->len[t][i];
- }
- if (s->len[t][i] < minLen) {
- minLen = s->len[t][i];
- }
- }
-
- BZ2_hbCreateDecodeTables (
- &(s->limit[t][0]),
- &(s->base[t][0]),
- &(s->perm[t][0]),
- &(s->len[t][0]),
- minLen, maxLen, alphaSize
- );
-
-
- s->minLens[t] = minLen;
+ /* Find largest and smallest lengths in this group */
+ minLen = maxLen = length[0];
+ for (i = 1; i < symCount; i++) {
+ if (length[i] > maxLen) maxLen = length[i];
+ else if (length[i] < minLen) minLen = length[i];
}
- /*--- Now the MTF values ---*/
-
- EOB = s->nInUse+1;
- nblockMAX = 100000 * s->blockSize100k;
- groupNo = -1;
- groupPos = 0;
-
- for (i = 0; i <= 255; i++) {
- s->unzftab[i] = 0;
+ /* Calculate permute[], base[], and limit[] tables from length[].
+ *
+ * permute[] is the lookup table for converting Huffman coded symbols
+ * into decoded symbols. base[] is the amount to subtract from the
+ * value of a Huffman symbol of a given length when using permute[].
+ *
+ * limit[] indicates the largest numerical value a symbol with a given
+ * number of bits can have. This is how the Huffman codes can vary in
+ * length: each code with a value>limit[length] needs another bit.
+ */
+ hufGroup = bd->groups + j;
+ hufGroup->minLen = minLen;
+ hufGroup->maxLen = maxLen;
+
+ /* Note that minLen can't be smaller than 1, so we adjust the base
+ and limit array pointers so we're not always wasting the first
+ entry. We do this again when using them (during symbol decoding).*/
+ base = hufGroup->base - 1;
+ limit = hufGroup->limit - 1;
+
+ /* Calculate permute[]. Concurently, initialize temp[] and limit[]. */
+ pp = 0;
+ for (i = minLen; i <= maxLen; i++) {
+ temp[i] = limit[i] = 0;
+ for (t = 0; t < symCount; t++)
+ if (length[t] == i)
+ hufGroup->permute[pp++] = t;
}
- /*-- MTF init --*/
- {
- int ii, jj, kk;
- kk = MTFA_SIZE-1;
- for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
- for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
- s->mtfa[kk] = (unsigned char)(ii * MTFL_SIZE + jj);
- kk--;
- }
- s->mtfbase[ii] = kk + 1;
- }
- }
- /*-- end MTF init --*/
-
- nblock = 0;
- if (! get_mtf_val_init()) {
- goto save_state_and_return;
+ /* Count symbols coded for at each bit length */
+ /* NB: in pathological cases, temp[8] can end ip being 256.
+ * That's why uint8_t is too small for temp[]. */
+ for (i = 0; i < symCount; i++) temp[length[i]]++;
+
+ /* Calculate limit[] (the largest symbol-coding value at each bit
+ * length, which is (previous limit<<1)+symbols at this level), and
+ * base[] (number of symbols to ignore at each bit length, which is
+ * limit minus the cumulative count of symbols coded for already). */
+ pp = t = 0;
+ for (i = minLen; i < maxLen; i++) {
+ pp += temp[i];
+
+ /* We read the largest possible symbol size and then unget bits
+ after determining how many we need, and those extra bits could
+ be set to anything. (They're noise from future symbols.) At
+ each level we're really only interested in the first few bits,
+ so here we set all the trailing to-be-ignored bits to 1 so they
+ don't affect the value>limit[length] comparison. */
+ limit[i] = (pp << (maxLen - i)) - 1;
+ pp <<= 1;
+ t += temp[i];
+ base[i+1] = pp - t;
}
- case BZ_X_MTF_1:
- s->state = BZ_X_MTF_1;
- if (! get_bits(s, &zvec, zn)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- while (1) {
- if (zn > 20 /* the longest code */) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
- if (zvec <= gLimit[zn]) {
- break;
- }
- zn++;
-
- case BZ_X_MTF_2:
- s->state = BZ_X_MTF_2;
- if (! get_bits(s, &zj, 1)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- zvec = (zvec << 1) | zj;
- }
- if (zvec - gBase[zn] < 0 || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
- nextSym = gPerm[zvec - gBase[zn]];
-
- while (1) {
- if (nextSym == EOB) {
- break;
- }
-
- if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
- es = -1;
- N = 1;
- do {
- if (nextSym == BZ_RUNA) {
- es = es + (0+1) * N;
- } else {
- if (nextSym == BZ_RUNB) {
- es = es + (1+1) * N;
- }
- }
- N = N * 2;
- if (! get_mtf_val_init()) {
- goto save_state_and_return;
- }
- case BZ_X_MTF_3:
- s->state = BZ_X_MTF_3;
- if (! get_bits(s, &zvec, zn)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- while (1) {
- if (zn > 20 /* the longest code */) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
- if (zvec <= gLimit[zn]) {
- break;
- }
- zn++;
-
- case BZ_X_MTF_4:
- s->state = BZ_X_MTF_4;
- if (! get_bits(s, &zj, 1)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- zvec = (zvec << 1) | zj;
- }
- if (zvec - gBase[zn] < 0 || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
-
- }
- nextSym = gPerm[zvec - gBase[zn]];
- }
- while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
+ limit[maxLen+1] = INT_MAX; /* Sentinel value for reading next sym. */
+ limit[maxLen] = pp + temp[maxLen] - 1;
+ base[minLen] = 0;
+ }
- es++;
- uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
- s->unzftab[uc] += es;
+ /* We've finished reading and digesting the block header. Now read this
+ block's Huffman coded symbols from the file and undo the Huffman coding
+ and run length encoding, saving the result into dbuf[dbufCount++] = uc */
- while (es > 0) {
- if (nblock >= nblockMAX) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
- s->tt[nblock] = (unsigned int)uc;
- nblock++;
- es--;
- }
- continue;
- } else {
- if (nblock >= nblockMAX) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
- /*-- uc = MTF ( nextSym-1 ) --*/
- {
- int ii, jj, kk, pp, lno, off;
- unsigned int nn;
- nn = (unsigned int)(nextSym - 1);
-
- if (nn < MTFL_SIZE) {
- /* avoid general-case expense */
- pp = s->mtfbase[0];
- uc = s->mtfa[pp+nn];
- while (nn > 3) {
- int z = pp+nn;
- s->mtfa[(z) ] = s->mtfa[(z)-1];
- s->mtfa[(z)-1] = s->mtfa[(z)-2];
- s->mtfa[(z)-2] = s->mtfa[(z)-3];
- s->mtfa[(z)-3] = s->mtfa[(z)-4];
- nn -= 4;
- }
- while (nn > 0) {
- s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--;
- }
- s->mtfa[pp] = uc;
- } else {
- /* general case */
- lno = nn / MTFL_SIZE;
- off = nn % MTFL_SIZE;
- pp = s->mtfbase[lno] + off;
- uc = s->mtfa[pp];
- while (pp > s->mtfbase[lno]) {
- s->mtfa[pp] = s->mtfa[pp-1];
- pp--;
- }
- s->mtfbase[lno]++;
- while (lno > 0) {
- s->mtfbase[lno]--;
- s->mtfa[s->mtfbase[lno]] = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
- lno--;
- }
- s->mtfbase[0]--;
- s->mtfa[s->mtfbase[0]] = uc;
- if (s->mtfbase[0] == 0) {
- kk = MTFA_SIZE-1;
- for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
- for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
- s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
- kk--;
- }
- s->mtfbase[ii] = kk + 1;
- }
- }
- }
- }
- /*-- end uc = MTF ( nextSym-1 ) --*/
+ /* Initialize symbol occurrence counters and symbol Move To Front table */
+ memset(byteCount, 0, sizeof(byteCount)); /* smaller, maybe slower? */
+ for (i = 0; i < 256; i++) {
+ //byteCount[i] = 0;
+ mtfSymbol[i] = (unsigned char)i;
+ }
- s->unzftab[s->seqToUnseq[uc]]++;
- s->tt[nblock] = (unsigned int)(s->seqToUnseq[uc]);
- nblock++;
+ /* Loop through compressed symbols. */
+
+ runPos = dbufCount = selector = 0;
+ for (;;) {
+
+ /* Fetch next Huffman coding group from list. */
+ symCount = GROUP_SIZE - 1;
+ if (selector >= nSelectors) return RETVAL_DATA_ERROR;
+ hufGroup = bd->groups + selectors[selector++];
+ base = hufGroup->base - 1;
+ limit = hufGroup->limit - 1;
+ continue_this_group:
+
+ /* Read next Huffman-coded symbol. */
+
+ /* Note: It is far cheaper to read maxLen bits and back up than it is
+ to read minLen bits and then an additional bit at a time, testing
+ as we go. Because there is a trailing last block (with file CRC),
+ there is no danger of the overread causing an unexpected EOF for a
+ valid compressed file. As a further optimization, we do the read
+ inline (falling back to a call to get_bits if the buffer runs
+ dry). The following (up to got_huff_bits:) is equivalent to
+ j = get_bits(bd, hufGroup->maxLen);
+ */
+ while ((int)(bd->inbufBitCount) < hufGroup->maxLen) {
+ if (bd->inbufPos == bd->inbufCount) {
+ j = get_bits(bd, hufGroup->maxLen);
+ goto got_huff_bits;
+ }
+ bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++];
+ bd->inbufBitCount += 8;
+ };
+ bd->inbufBitCount -= hufGroup->maxLen;
+ j = (bd->inbufBits >> bd->inbufBitCount) & ((1 << hufGroup->maxLen) - 1);
+
+ got_huff_bits:
+
+ /* Figure how how many bits are in next symbol and unget extras */
+ i = hufGroup->minLen;
+ while (j > limit[i]) ++i;
+ bd->inbufBitCount += (hufGroup->maxLen - i);
+
+ /* Huffman decode value to get nextSym (with bounds checking) */
+ if (i > hufGroup->maxLen)
+ return RETVAL_DATA_ERROR;
+ j = (j >> (hufGroup->maxLen - i)) - base[i];
+ if ((unsigned)j >= MAX_SYMBOLS)
+ return RETVAL_DATA_ERROR;
+ nextSym = hufGroup->permute[j];
+
+ /* We have now decoded the symbol, which indicates either a new literal
+ byte, or a repeated run of the most recent literal byte. First,
+ check if nextSym indicates a repeated run, and if so loop collecting
+ how many times to repeat the last literal. */
+ if ((unsigned)nextSym <= SYMBOL_RUNB) { /* RUNA or RUNB */
+
+ /* If this is the start of a new run, zero out counter */
+ if (!runPos) {
+ runPos = 1;
+ t = 0;
+ }
+
+ /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at
+ each bit position, add 1 or 2 instead. For example,
+ 1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2.
+ You can make any bit pattern that way using 1 less symbol than
+ the basic or 0/1 method (except all bits 0, which would use no
+ symbols, but a run of length 0 doesn't mean anything in this
+ context). Thus space is saved. */
+ t += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */
+ if (runPos < dbufSize) runPos <<= 1;
+ goto end_of_huffman_loop;
+ }
- if (! get_mtf_val_init()) {
- goto save_state_and_return;
- }
- case BZ_X_MTF_5:
- s->state = BZ_X_MTF_5;
- if (! get_bits(s, &zvec, zn)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- while (1) {
- if (zn > 20 /* the longest code */) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
- if (zvec <= gLimit[zn]) {
- break;
- }
- zn++;
-
- case BZ_X_MTF_6:
- s->state = BZ_X_MTF_6;
- if (! get_bits(s, &zj, 1)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- zvec = (zvec << 1) | zj;
- }
- if (zvec - gBase[zn] < 0 || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
- nextSym = gPerm[zvec - gBase[zn]];
- continue;
+ /* When we hit the first non-run symbol after a run, we now know
+ how many times to repeat the last literal, so append that many
+ copies to our buffer of decoded symbols (dbuf) now. (The last
+ literal used is the one at the head of the mtfSymbol array.) */
+ if (runPos) {
+ runPos = 0;
+ if (dbufCount + t >= dbufSize) return RETVAL_DATA_ERROR;
+
+ uc = symToByte[mtfSymbol[0]];
+ byteCount[uc] += t;
+ while (t--) dbuf[dbufCount++] = uc;
}
- }
- /* Now we know what nblock is, we can do a better sanity
- check on s->origPtr.
- */
- if (s->origPtr < 0 || s->origPtr >= nblock) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
- s->state_out_len = 0;
- s->state_out_ch = 0;
- s->calculatedBlockCRC = 0xffffffffL;
- s->state = BZ_X_OUTPUT;
-
- /*-- Set up cftab to facilitate generation of T^(-1) --*/
- s->cftab[0] = 0;
- for (i = 1; i <= 256; i++) {
- s->cftab[i] = s->unzftab[i-1];
- }
- for (i = 1; i <= 256; i++) {
- s->cftab[i] += s->cftab[i-1];
+ /* Is this the terminating symbol? */
+ if (nextSym > symTotal) break;
+
+ /* At this point, nextSym indicates a new literal character. Subtract
+ one to get the position in the MTF array at which this literal is
+ currently to be found. (Note that the result can't be -1 or 0,
+ because 0 and 1 are RUNA and RUNB. But another instance of the
+ first symbol in the mtf array, position 0, would have been handled
+ as part of a run above. Therefore 1 unused mtf position minus
+ 2 non-literal nextSym values equals -1.) */
+ if (dbufCount >= dbufSize) return RETVAL_DATA_ERROR;
+ i = nextSym - 1;
+ uc = mtfSymbol[i];
+
+ /* Adjust the MTF array. Since we typically expect to move only a
+ * small number of symbols, and are bound by 256 in any case, using
+ * memmove here would typically be bigger and slower due to function
+ * call overhead and other assorted setup costs. */
+ do {
+ mtfSymbol[i] = mtfSymbol[i-1];
+ } while (--i);
+ mtfSymbol[0] = uc;
+ uc = symToByte[uc];
+
+ /* We have our literal byte. Save it into dbuf. */
+ byteCount[uc]++;
+ dbuf[dbufCount++] = (unsigned)uc;
+
+ /* Skip group initialization if we're not done with this group. Done
+ * this way to avoid compiler warning. */
+ end_of_huffman_loop:
+ if (symCount--) goto continue_this_group;
}
- /*-- compute the T^(-1) vector --*/
- for (i = 0; i < nblock; i++) {
- uc = (unsigned char)(s->tt[i] & 0xff);
- s->tt[s->cftab[uc]] |= (i << 8);
- s->cftab[uc]++;
+ /* At this point, we've read all the Huffman-coded symbols (and repeated
+ runs) for this block from the input stream, and decoded them into the
+ intermediate buffer. There are dbufCount many decoded bytes in dbuf[].
+ Now undo the Burrows-Wheeler transform on dbuf.
+ See http://dogma.net/markn/articles/bwt/bwt.htm
+ */
+
+ /* Turn byteCount into cumulative occurrence counts of 0 to n-1. */
+ j = 0;
+ for (i = 0; i < 256; i++) {
+ k = j + byteCount[i];
+ byteCount[i] = j;
+ j = k;
}
- s->tPos = s->tt[s->origPtr] >> 8;
- s->nblock_used = 0;
- if (s->blockRandomised) {
- s->rNToGo = 0;
- s->rTPos = 0;
- s->k0 = bz_get_fast(s);
-
- s->nblock_used++;
- bz_rand_udp_mask(s);
- s->k0 ^= ((s->rNToGo == 1) ? 1 : 0);
- } else {
- s->k0 = bz_get_fast(s);
- s->nblock_used++;
+ /* Figure out what order dbuf would be in if we sorted it. */
+ for (i = 0; i < dbufCount; i++) {
+ uc = (unsigned char)(dbuf[i] & 0xff);
+ dbuf[byteCount[uc]] |= (i << 8);
+ byteCount[uc]++;
}
- retVal = BZ_OK;
- goto save_state_and_return;
-
-endhdr_2:
- case BZ_X_ENDHDR_2:
- s->state = BZ_X_ENDHDR_2;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc != 0x72) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
-
- case BZ_X_ENDHDR_3:
- s->state = BZ_X_ENDHDR_3;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc != 0x45) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
-
- case BZ_X_ENDHDR_4:
- s->state = BZ_X_ENDHDR_4;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc != 0x38) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
-
- case BZ_X_ENDHDR_5:
- s->state = BZ_X_ENDHDR_5;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc != 0x50) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
-
- case BZ_X_ENDHDR_6:
- s->state = BZ_X_ENDHDR_6;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- if (uc != 0x90) {
- retVal = BZ_DATA_ERROR;
- goto save_state_and_return;
- }
- s->storedCombinedCRC = 0;
-
- case BZ_X_CCRC_1:
- s->state = BZ_X_CCRC_1;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((unsigned int)uc);
- case BZ_X_CCRC_2:
- s->state = BZ_X_CCRC_2;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((unsigned int)uc);
-
- case BZ_X_CCRC_3:
- s->state = BZ_X_CCRC_3;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((unsigned int)uc);
-
- case BZ_X_CCRC_4:
- s->state = BZ_X_CCRC_4;
- if (! get_bits(s, &uc, 8)) {
- retVal = BZ_OK;
- goto save_state_and_return;
- }
- s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((unsigned int)uc);
-
- s->state = BZ_X_IDLE;
- retVal = BZ_STREAM_END;
- goto save_state_and_return;
-
+ /* Decode first byte by hand to initialize "previous" byte. Note that it
+ doesn't get output, and if the first three characters are identical
+ it doesn't qualify as a run (hence writeRunCountdown=5). */
+ if (dbufCount) {
+ if ((int)origPtr >= dbufCount) return RETVAL_DATA_ERROR;
+ bd->writePos = dbuf[origPtr];
+ bd->writeCurrent = (unsigned char)(bd->writePos & 0xff);
+ bd->writePos >>= 8;
+ bd->writeRunCountdown = 5;
}
+ bd->writeCount = dbufCount;
-save_state_and_return:
- s->save_i = i;
- s->save_j = j;
- s->save_t = t;
- s->save_alphaSize = alphaSize;
- s->save_nGroups = nGroups;
- s->save_nSelectors = nSelectors;
- s->save_EOB = EOB;
- s->save_groupNo = groupNo;
- s->save_groupPos = groupPos;
- s->save_nextSym = nextSym;
- s->save_nblockMAX = nblockMAX;
- s->save_nblock = nblock;
- s->save_es = es;
- s->save_N = N;
- s->save_curr = curr;
- s->save_zt = zt;
- s->save_zn = zn;
- s->save_zvec = zvec;
- s->save_zj = zj;
- s->save_gSel = gSel;
- s->save_gMinlen = gMinlen;
- s->save_gLimit = gLimit;
- s->save_gBase = gBase;
- s->save_gPerm = gPerm;
-
- return retVal;
+ return RETVAL_OK;
}
-extern void BZ2_bzReadClose(void)
+/* Undo burrows-wheeler transform on intermediate buffer to produce output.
+ If start_bunzip was initialized with out_fd=-1, then up to len bytes of
+ data are written to outbuf. Return value is number of bytes written or
+ error (all errors are negative numbers). If out_fd!=-1, outbuf and len
+ are ignored, data is written to out_fd and return is RETVAL_OK or error.
+*/
+int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len)
{
- if (bzf->initialisedOk) {
- bz_stream *strm = &(bzf->strm);
- DState *s;
- if (strm == NULL) {
- return;
- }
- s = strm->state;
- if ((s == NULL) || (s->strm != strm)) {
- return;
- }
- free(s->tt);
- free(strm->state);
- strm->state = NULL;
- return;
- }
- free(bzf);
-}
+ const unsigned *dbuf;
+ int pos, current, previous, gotcount;
-static void unRLE_obuf_to_output_FAST(DState *s)
-{
- unsigned char k1;
-
- if (s->blockRandomised) {
- while (1) {
- /* try to finish existing run */
- while (1) {
- if (s->strm->avail_out == 0) {
- return;
- }
- if (s->state_out_len == 0) {
- break;
- }
- *((unsigned char *)(s->strm->next_out)) = s->state_out_ch;
- s->calculatedBlockCRC = (s->calculatedBlockCRC << 8) ^
- BZ2_crc32Table[(s->calculatedBlockCRC >> 24) ^
- ((unsigned char)s->state_out_ch)];
- s->state_out_len--;
- s->strm->next_out++;
- s->strm->avail_out--;
- }
-
- /* can a new run be started? */
- if (s->nblock_used == s->save_nblock+1) {
- return;
- }
- s->state_out_len = 1;
- s->state_out_ch = s->k0;
- k1 = bz_get_fast(s);
- bz_rand_udp_mask(s);
- k1 ^= ((s->rNToGo == 1) ? 1 : 0);
- s->nblock_used++;
- if (s->nblock_used == s->save_nblock+1) {
- continue;
- }
- if (k1 != s->k0) {
- s->k0 = k1;
- continue;
- }
+ /* If last read was short due to end of file, return last block now */
+ if (bd->writeCount < 0) return bd->writeCount;
- s->state_out_len = 2;
- k1 = bz_get_fast(s);
- bz_rand_udp_mask(s);
- k1 ^= ((s->rNToGo == 1) ? 1 : 0);
- s->nblock_used++;
- if (s->nblock_used == s->save_nblock+1) {
- continue;
- }
- if (k1 != s->k0) {
- s->k0 = k1;
- continue;
- }
- s->state_out_len = 3;
- k1 = bz_get_fast(s);
- bz_rand_udp_mask(s);
- k1 ^= ((s->rNToGo == 1) ? 1 : 0);
- s->nblock_used++;
- if (s->nblock_used == s->save_nblock+1) {
- continue;
- }
- if (k1 != s->k0) {
- s->k0 = k1;
- continue;
- }
+ gotcount = 0;
+ dbuf = bd->dbuf;
+ pos = bd->writePos;
+ current = bd->writeCurrent;
- k1 = bz_get_fast(s);
- bz_rand_udp_mask(s);
- k1 ^= ((s->rNToGo == 1) ? 1 : 0);
- s->nblock_used++;
- s->state_out_len = ((int)k1) + 4;
- s->k0 = bz_get_fast(s);
- bz_rand_udp_mask(s);
- s->k0 ^= ((s->rNToGo == 1) ? 1 : 0);
- s->nblock_used++;
- }
- } else {
- /* restore */
- unsigned int c_calculatedBlockCRC = s->calculatedBlockCRC;
- unsigned char c_state_out_ch = s->state_out_ch;
- int c_state_out_len = s->state_out_len;
- int c_nblock_used = s->nblock_used;
- int c_k0 = s->k0;
- unsigned int *c_tt = s->tt;
- unsigned int c_tPos = s->tPos;
- char *cs_next_out = s->strm->next_out;
- unsigned int cs_avail_out = s->strm->avail_out;
- /* end restore */
-
- int s_save_nblockPP = s->save_nblock+1;
-
- while (1) {
- /* try to finish existing run */
- if (c_state_out_len > 0) {
- while (TRUE) {
- if (cs_avail_out == 0) {
- goto return_notr;
- }
- if (c_state_out_len == 1) {
- break;
- }
- *((unsigned char *)(cs_next_out)) = c_state_out_ch;
- c_calculatedBlockCRC = (c_calculatedBlockCRC << 8) ^
- BZ2_crc32Table[(c_calculatedBlockCRC >> 24) ^
- ((unsigned char)c_state_out_ch)];
- c_state_out_len--;
- cs_next_out++;
- cs_avail_out--;
- }
-s_state_out_len_eq_one:
- {
- if (cs_avail_out == 0) {
- c_state_out_len = 1;
- goto return_notr;
- }
- *((unsigned char *)(cs_next_out)) = c_state_out_ch;
- c_calculatedBlockCRC = (c_calculatedBlockCRC << 8) ^
- BZ2_crc32Table[(c_calculatedBlockCRC >> 24) ^
- ((unsigned char)c_state_out_ch)];
- cs_next_out++;
- cs_avail_out--;
- }
- }
- /* can a new run be started? */
- if (c_nblock_used == s_save_nblockPP) {
- c_state_out_len = 0; goto return_notr;
- }
- c_state_out_ch = c_k0;
- c_tPos = c_tt[c_tPos];
- k1 = (unsigned char)(c_tPos & 0xff);
- c_tPos >>= 8;
+ /* We will always have pending decoded data to write into the output
+ buffer unless this is the very first call (in which case we haven't
+ Huffman-decoded a block into the intermediate buffer yet). */
+ if (bd->writeCopies) {
- c_nblock_used++;
+ /* Inside the loop, writeCopies means extra copies (beyond 1) */
+ --bd->writeCopies;
- if (k1 != c_k0) {
- c_k0 = k1;
- goto s_state_out_len_eq_one;
- }
+ /* Loop outputting bytes */
+ for (;;) {
- if (c_nblock_used == s_save_nblockPP) {
- goto s_state_out_len_eq_one;
+ /* If the output buffer is full, snapshot state and return */
+ if (gotcount >= len) {
+ bd->writePos = pos;
+ bd->writeCurrent = current;
+ bd->writeCopies++;
+ return len;
}
- c_state_out_len = 2;
- c_tPos = c_tt[c_tPos];
- k1 = (unsigned char)(c_tPos & 0xff);
- c_tPos >>= 8;
+ /* Write next byte into output buffer, updating CRC */
+ outbuf[gotcount++] = current;
+ bd->writeCRC = (bd->writeCRC << 8)
+ ^ bd->crc32Table[(bd->writeCRC >> 24) ^ current];
- c_nblock_used++;
- if (c_nblock_used == s_save_nblockPP) {
- continue;
- }
- if (k1 != c_k0) {
- c_k0 = k1;
+ /* Loop now if we're outputting multiple copies of this byte */
+ if (bd->writeCopies) {
+ --bd->writeCopies;
continue;
}
+ decode_next_byte:
+ if (!bd->writeCount--) break;
+ /* Follow sequence vector to undo Burrows-Wheeler transform */
+ previous = current;
+ pos = dbuf[pos];
+ current = pos & 0xff;
+ pos >>= 8;
+
+ /* After 3 consecutive copies of the same byte, the 4th
+ * is a repeat count. We count down from 4 instead
+ * of counting up because testing for non-zero is faster */
+ if (--bd->writeRunCountdown) {
+ if (current != previous)
+ bd->writeRunCountdown = 4;
+ } else {
- c_state_out_len = 3;
- c_tPos = c_tt[c_tPos];
- k1 = (unsigned char)(c_tPos & 0xff);
- c_tPos >>= 8;
+ /* We have a repeated run, this byte indicates the count */
+ bd->writeCopies = current;
+ current = previous;
+ bd->writeRunCountdown = 5;
- c_nblock_used++;
- if (c_nblock_used == s_save_nblockPP) {
- continue;
- }
- if (k1 != c_k0) {
- c_k0 = k1;
- continue;
- }
-
- c_tPos = c_tt[c_tPos];
- k1 = (unsigned char)(c_tPos & 0xff);
- c_tPos >>= 8;
+ /* Sometimes there are just 3 bytes (run length 0) */
+ if (!bd->writeCopies) goto decode_next_byte;
- c_nblock_used++;
- c_state_out_len = ((int)k1) + 4;
+ /* Subtract the 1 copy we'd output anyway to get extras */
+ --bd->writeCopies;
+ }
+ }
- c_tPos = c_tt[c_tPos];
- c_k0 = (unsigned char)(c_tPos & 0xff);
- c_tPos >>= 8;
+ /* Decompression of this block completed successfully */
+ bd->writeCRC = ~bd->writeCRC;
+ bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ bd->writeCRC;
- c_nblock_used++;
+ /* If this block had a CRC error, force file level CRC error. */
+ if (bd->writeCRC != bd->headerCRC) {
+ bd->totalCRC = bd->headerCRC + 1;
+ return RETVAL_LAST_BLOCK;
}
+ }
-return_notr:
-
- /* save */
- s->calculatedBlockCRC = c_calculatedBlockCRC;
- s->state_out_ch = c_state_out_ch;
- s->state_out_len = c_state_out_len;
- s->nblock_used = c_nblock_used;
- s->k0 = c_k0;
- s->tt = c_tt;
- s->tPos = c_tPos;
- s->strm->next_out = cs_next_out;
- s->strm->avail_out = cs_avail_out;
- /* end save */
+ /* Refill the intermediate buffer by Huffman-decoding next block of input */
+ /* (previous is just a convenient unused temp variable here) */
+ previous = get_next_block(bd);
+ if (previous) {
+ bd->writeCount = previous;
+ return (previous != RETVAL_LAST_BLOCK) ? previous : gotcount;
}
+ bd->writeCRC = ~0;
+ pos = bd->writePos;
+ current = bd->writeCurrent;
+ goto decode_next_byte;
}
-static inline
-int BZ2_bzDecompress(bz_stream *strm)
-{
- DState* s;
- s = strm->state;
- while (1) {
- if (s->state == BZ_X_IDLE) {
- return BZ_SEQUENCE_ERROR;
- }
- if (s->state == BZ_X_OUTPUT) {
- unRLE_obuf_to_output_FAST(s);
- if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
- s->calculatedBlockCRC = ~(s->calculatedBlockCRC);
- if (s->calculatedBlockCRC != s->storedBlockCRC) {
- return BZ_DATA_ERROR;
- }
- s->calculatedCombinedCRC = (s->calculatedCombinedCRC << 1) | (s->calculatedCombinedCRC >> 31);
- s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
- s->state = BZ_X_BLKHDR_1;
- } else {
- return BZ_OK;
- }
- }
- if (s->state >= BZ_X_MAGIC_1) {
- int r = BZ2_decompress(s);
- if (r == BZ_STREAM_END) {
- if (s->calculatedCombinedCRC != s->storedCombinedCRC) {
- return BZ_DATA_ERROR;
- }
- return r;
- }
- if (s->state != BZ_X_OUTPUT) {
- return r;
- }
- }
- }
+/* Allocate the structure, read file header. If in_fd==-1, inbuf must contain
+ a complete bunzip file (len bytes long). If in_fd!=-1, inbuf and len are
+ ignored, and data is read from file handle into temporary buffer. */
- return(0); /*NOTREACHED*/
+/* Because bunzip2 is used for help text unpacking, and because bb_show_usage()
+ should work for NOFORK applets too, we must be extremely careful to not leak
+ any allocations! */
+int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd, const unsigned char *inbuf,
+ int len)
+{
+ bunzip_data *bd;
+ unsigned i;
+ enum {
+ BZh0 = ('B' << 24) + ('Z' << 16) + ('h' << 8) + '0',
+ h0 = ('h' << 8) + '0',
+ };
+
+ /* Figure out how much data to allocate */
+ i = sizeof(bunzip_data);
+ if (in_fd != -1) i += IOBUF_SIZE;
+
+ /* Allocate bunzip_data. Most fields initialize to zero. */
+ bd = *bdp = xzalloc(i);
+
+ /* Setup input buffer */
+ bd->in_fd = in_fd;
+ if (-1 == in_fd) {
+ /* in this case, bd->inbuf is read-only */
+ bd->inbuf = (void*)inbuf; /* cast away const-ness */
+ bd->inbufCount = len;
+ } else
+ bd->inbuf = (unsigned char *)(bd + 1);
+
+ /* Init the CRC32 table (big endian) */
+ crc32_filltable(bd->crc32Table, 1);
+
+ /* Setup for I/O error handling via longjmp */
+ i = setjmp(bd->jmpbuf);
+ if (i) return i;
+
+ /* Ensure that file starts with "BZh['1'-'9']." */
+ /* Update: now caller verifies 1st two bytes, makes .gz/.bz2
+ * integration easier */
+ /* was: */
+ /* i = get_bits(bd, 32); */
+ /* if ((unsigned)(i - BZh0 - 1) >= 9) return RETVAL_NOT_BZIP_DATA; */
+ i = get_bits(bd, 16);
+ if ((unsigned)(i - h0 - 1) >= 9) return RETVAL_NOT_BZIP_DATA;
+
+ /* Fourth byte (ascii '1'-'9') indicates block size in units of 100k of
+ uncompressed data. Allocate intermediate buffer for block. */
+ /* bd->dbufSize = 100000 * (i - BZh0); */
+ bd->dbufSize = 100000 * (i - h0);
+
+ /* Cannot use xmalloc - may leak bd in NOFORK case! */
+ bd->dbuf = malloc_or_warn(bd->dbufSize * sizeof(int));
+ if (!bd->dbuf) {
+ free(bd);
+ xfunc_die();
+ }
+ return RETVAL_OK;
}
-extern ssize_t read_bz2(int fd, void *buf, size_t count)
+void FAST_FUNC dealloc_bunzip(bunzip_data *bd)
{
- int n, ret;
+ free(bd->dbuf);
+ free(bd);
+}
- bzerr = BZ_OK;
- if (count == 0) {
- return(0);
- }
- bzf->strm.avail_out = count;
- bzf->strm.next_out = buf;
- while (1) {
- if (bzf->strm.avail_in == 0) {
- n = bb_xread(bzf->fd, bzf->buf, BZ_MAX_UNUSED);
- if (n == 0) {
+/* Decompress src_fd to dst_fd. Stops at end of bzip data, not end of file. */
+USE_DESKTOP(long long) int FAST_FUNC
+unpack_bz2_stream(int src_fd, int dst_fd)
+{
+ USE_DESKTOP(long long total_written = 0;)
+ char *outbuf;
+ bunzip_data *bd;
+ int i;
+
+ outbuf = xmalloc(IOBUF_SIZE);
+ i = start_bunzip(&bd, src_fd, NULL, 0);
+ if (!i) {
+ for (;;) {
+ i = read_bunzip(bd, outbuf, IOBUF_SIZE);
+ if (i <= 0) break;
+ if (i != full_write(dst_fd, outbuf, i)) {
+ i = RETVAL_SHORT_WRITE;
break;
}
- bzf->bufN = n;
- bzf->strm.avail_in = bzf->bufN;
- bzf->strm.next_in = bzf->buf;
+ USE_DESKTOP(total_written += i;)
}
+ }
- ret = BZ2_bzDecompress(&(bzf->strm));
-
- if ((ret != BZ_OK) && (ret != BZ_STREAM_END)) {
- bb_error_msg_and_die("Error decompressing");
- }
+ /* Check CRC and release memory */
- if (ret == BZ_STREAM_END) {
- bzerr = BZ_STREAM_END;
- return(count - bzf->strm.avail_out);
- }
- if (bzf->strm.avail_out == 0) {
- bzerr = BZ_OK;
- return(count);
+ if (i == RETVAL_LAST_BLOCK) {
+ if (bd->headerCRC != bd->totalCRC) {
+ bb_error_msg("CRC error");
+ } else {
+ i = RETVAL_OK;
}
+ } else if (i == RETVAL_SHORT_WRITE) {
+ bb_error_msg("short write");
+ } else {
+ bb_error_msg("bunzip error %d", i);
}
- return(0);
+ dealloc_bunzip(bd);
+ free(outbuf);
+
+ return i ? i : USE_DESKTOP(total_written) + 0;
}
-extern void BZ2_bzReadOpen(int fd, void *unused, int nUnused)
+USE_DESKTOP(long long) int FAST_FUNC
+unpack_bz2_stream_prime(int src_fd, int dst_fd)
{
- DState *s;
-
- bzf = xmalloc(sizeof(bzFile));
- bzf->initialisedOk = FALSE;
- bzf->fd = fd;
- bzf->bufN = 0;
-
- s = xmalloc(sizeof(DState));
- s->strm = &bzf->strm;
- s->state = BZ_X_MAGIC_1;
- s->bsLive = 0;
- s->bsBuff = 0;
- s->calculatedCombinedCRC = 0;
- s->tt = NULL;
- s->currBlockNo = 0;
- bzf->strm.state = s;
-
- while (nUnused > 0) {
- bzf->buf[bzf->bufN] = *((unsigned char *)(unused));
- bzf->bufN++;
- unused = ((void *)( 1 + ((unsigned char *)(unused)) ));
- nUnused--;
+ unsigned char magic[2];
+ xread(src_fd, magic, 2);
+ if (magic[0] != 'B' || magic[1] != 'Z') {
+ bb_error_msg_and_die("invalid magic");
}
- bzf->strm.avail_in = bzf->bufN;
- bzf->strm.next_in = bzf->buf;
+ return unpack_bz2_stream(src_fd, dst_fd);
+}
- bzf->initialisedOk = TRUE;
+#ifdef TESTING
- return;
-}
+static char *const bunzip_errors[] = {
+ NULL, "Bad file checksum", "Not bzip data",
+ "Unexpected input EOF", "Unexpected output EOF", "Data error",
+ "Out of memory", "Obsolete (pre 0.9.5) bzip format not supported"
+};
-extern unsigned char uncompressStream(int src_fd, int dst_fd)
+/* Dumb little test thing, decompress stdin to stdout */
+int main(int argc, char **argv)
{
- unsigned char unused[BZ_MAX_UNUSED];
- unsigned char *unusedTmp;
- unsigned char obuf[5000];
- int nread;
- int nUnused;
- int streamNo;
int i;
-
- nUnused = 0;
- streamNo = 0;
-
- while(1) {
- BZ2_bzReadOpen(src_fd, unused, nUnused);
- streamNo++;
-
- while (bzerr == BZ_OK) {
- nread = read_bz2(src_fd, obuf, 5000);
- if (bzerr == BZ_DATA_ERROR_MAGIC) {
- bb_error_msg_and_die("invalid magic");
- }
- if (((bzerr == BZ_OK) || (bzerr == BZ_STREAM_END)) && (nread > 0)) {
- if (write(dst_fd, obuf, nread) != nread) {
- BZ2_bzReadClose();
- bb_perror_msg_and_die("Couldnt write to file");
- }
- }
- }
- nUnused = bzf->strm.avail_in;
- unusedTmp = bzf->strm.next_in;
-
- for (i = 0; i < nUnused; i++) {
- unused[i] = unusedTmp[i];
- }
- BZ2_bzReadClose();
- if (nUnused == 0) {
- break;
- }
- }
-
- close(src_fd);
- if (dst_fd != fileno(stdout)) {
- close(dst_fd);
- }
- return TRUE;
+ char c;
+
+ int i = unpack_bz2_stream_prime(0, 1);
+ if (i < 0)
+ fprintf(stderr, "%s\n", bunzip_errors[-i]);
+ else if (read(STDIN_FILENO, &c, 1))
+ fprintf(stderr, "Trailing garbage ignored\n");
+ return -i;
}
-
+#endif
diff --git a/release/src/router/busybox/archival/libunarchive/decompress_uncompress.c b/release/src/router/busybox/archival/libunarchive/decompress_uncompress.c
new file mode 100644
index 00000000..fe1491e7
--- /dev/null
+++ b/release/src/router/busybox/archival/libunarchive/decompress_uncompress.c
@@ -0,0 +1,307 @@
+/* vi: set sw=4 ts=4: */
+/* uncompress for busybox -- (c) 2002 Robert Griebl
+ *
+ * based on the original compress42.c source
+ * (see disclaimer below)
+ */
+
+/* (N)compress42.c - File compression ala IEEE Computer, Mar 1992.
+ *
+ * Authors:
+ * Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
+ * Jim McKie (decvax!mcvax!jim)
+ * Steve Davies (decvax!vax135!petsd!peora!srd)
+ * Ken Turkowski (decvax!decwrl!turtlevax!ken)
+ * James A. Woods (decvax!ihnp4!ames!jaw)
+ * Joe Orost (decvax!vax135!petsd!joe)
+ * Dave Mack (csu@alembic.acs.com)
+ * Peter Jannesen, Network Communication Systems
+ * (peter@ncs.nl)
+ *
+ * marc@suse.de : a small security fix for a buffer overflow
+ *
+ * [... History snipped ...]
+ *
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+
+/* Default input buffer size */
+#define IBUFSIZ 2048
+
+/* Default output buffer size */
+#define OBUFSIZ 2048
+
+/* Defines for third byte of header */
+#define BIT_MASK 0x1f /* Mask for 'number of compresssion bits' */
+ /* Masks 0x20 and 0x40 are free. */
+ /* I think 0x20 should mean that there is */
+ /* a fourth header byte (for expansion). */
+#define BLOCK_MODE 0x80 /* Block compression if table is full and */
+ /* compression rate is dropping flush tables */
+ /* the next two codes should not be changed lightly, as they must not */
+ /* lie within the contiguous general code space. */
+#define FIRST 257 /* first free entry */
+#define CLEAR 256 /* table clear output code */
+
+#define INIT_BITS 9 /* initial number of bits/code */
+
+
+/* machine variants which require cc -Dmachine: pdp11, z8000, DOS */
+#define HBITS 17 /* 50% occupancy */
+#define HSIZE (1<<HBITS)
+#define HMASK (HSIZE-1) /* unused */
+#define HPRIME 9941 /* unused */
+#define BITS 16
+#define BITS_STR "16"
+#undef MAXSEG_64K /* unused */
+#define MAXCODE(n) (1L << (n))
+
+#define htabof(i) htab[i]
+#define codetabof(i) codetab[i]
+#define tab_prefixof(i) codetabof(i)
+#define tab_suffixof(i) ((unsigned char *)(htab))[i]
+#define de_stack ((unsigned char *)&(htab[HSIZE-1]))
+#define clear_tab_prefixof() memset(codetab, 0, 256)
+
+/*
+ * Decompress stdin to stdout. This routine adapts to the codes in the
+ * file building the "string" table on-the-fly; requiring no table to
+ * be stored in the compressed file.
+ */
+
+USE_DESKTOP(long long) int FAST_FUNC
+unpack_Z_stream(int fd_in, int fd_out)
+{
+ USE_DESKTOP(long long total_written = 0;)
+ USE_DESKTOP(long long) int retval = -1;
+ unsigned char *stackp;
+ long code;
+ int finchar;
+ long oldcode;
+ long incode;
+ int inbits;
+ int posbits;
+ int outpos;
+ int insize;
+ int bitmask;
+ long free_ent;
+ long maxcode;
+ long maxmaxcode;
+ int n_bits;
+ int rsize = 0;
+ unsigned char *inbuf; /* were eating insane amounts of stack - */
+ unsigned char *outbuf; /* bad for some embedded targets */
+ unsigned char *htab;
+ unsigned short *codetab;
+
+ /* Hmm, these were statics - why?! */
+ /* user settable max # bits/code */
+ int maxbits; /* = BITS; */
+ /* block compress mode -C compatible with 2.0 */
+ int block_mode; /* = BLOCK_MODE; */
+
+ inbuf = xzalloc(IBUFSIZ + 64);
+ outbuf = xzalloc(OBUFSIZ + 2048);
+ htab = xzalloc(HSIZE); /* wsn't zeroed out before, maybe can xmalloc? */
+ codetab = xzalloc(HSIZE * sizeof(codetab[0]));
+
+ insize = 0;
+
+ /* xread isn't good here, we have to return - caller may want
+ * to do some cleanup (e.g. delete incomplete unpacked file etc) */
+ if (full_read(fd_in, inbuf, 1) != 1) {
+ bb_error_msg("short read");
+ goto err;
+ }
+
+ maxbits = inbuf[0] & BIT_MASK;
+ block_mode = inbuf[0] & BLOCK_MODE;
+ maxmaxcode = MAXCODE(maxbits);
+
+ if (maxbits > BITS) {
+ bb_error_msg("compressed with %d bits, can only handle "
+ BITS_STR" bits", maxbits);
+ goto err;
+ }
+
+ n_bits = INIT_BITS;
+ maxcode = MAXCODE(INIT_BITS) - 1;
+ bitmask = (1 << INIT_BITS) - 1;
+ oldcode = -1;
+ finchar = 0;
+ outpos = 0;
+ posbits = 0 << 3;
+
+ free_ent = ((block_mode) ? FIRST : 256);
+
+ /* As above, initialize the first 256 entries in the table. */
+ /*clear_tab_prefixof(); - done by xzalloc */
+
+ for (code = 255; code >= 0; --code) {
+ tab_suffixof(code) = (unsigned char) code;
+ }
+
+ do {
+ resetbuf:
+ {
+ int i;
+ int e;
+ int o;
+
+ o = posbits >> 3;
+ e = insize - o;
+
+ for (i = 0; i < e; ++i)
+ inbuf[i] = inbuf[i + o];
+
+ insize = e;
+ posbits = 0;
+ }
+
+ if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) {
+ rsize = safe_read(fd_in, inbuf + insize, IBUFSIZ);
+//error check??
+ insize += rsize;
+ }
+
+ inbits = ((rsize > 0) ? (insize - insize % n_bits) << 3 :
+ (insize << 3) - (n_bits - 1));
+
+ while (inbits > posbits) {
+ if (free_ent > maxcode) {
+ posbits =
+ ((posbits - 1) +
+ ((n_bits << 3) -
+ (posbits - 1 + (n_bits << 3)) % (n_bits << 3)));
+ ++n_bits;
+ if (n_bits == maxbits) {
+ maxcode = maxmaxcode;
+ } else {
+ maxcode = MAXCODE(n_bits) - 1;
+ }
+ bitmask = (1 << n_bits) - 1;
+ goto resetbuf;
+ }
+ {
+ unsigned char *p = &inbuf[posbits >> 3];
+
+ code = ((((long) (p[0])) | ((long) (p[1]) << 8) |
+ ((long) (p[2]) << 16)) >> (posbits & 0x7)) & bitmask;
+ }
+ posbits += n_bits;
+
+
+ if (oldcode == -1) {
+ oldcode = code;
+ finchar = (int) oldcode;
+ outbuf[outpos++] = (unsigned char) finchar;
+ continue;
+ }
+
+ if (code == CLEAR && block_mode) {
+ clear_tab_prefixof();
+ free_ent = FIRST - 1;
+ posbits =
+ ((posbits - 1) +
+ ((n_bits << 3) -
+ (posbits - 1 + (n_bits << 3)) % (n_bits << 3)));
+ n_bits = INIT_BITS;
+ maxcode = MAXCODE(INIT_BITS) - 1;
+ bitmask = (1 << INIT_BITS) - 1;
+ goto resetbuf;
+ }
+
+ incode = code;
+ stackp = de_stack;
+
+ /* Special case for KwKwK string. */
+ if (code >= free_ent) {
+ if (code > free_ent) {
+ unsigned char *p;
+
+ posbits -= n_bits;
+ p = &inbuf[posbits >> 3];
+
+ bb_error_msg
+ ("insize:%d posbits:%d inbuf:%02X %02X %02X %02X %02X (%d)",
+ insize, posbits, p[-1], p[0], p[1], p[2], p[3],
+ (posbits & 07));
+ bb_error_msg("uncompress: corrupt input");
+ goto err;
+ }
+
+ *--stackp = (unsigned char) finchar;
+ code = oldcode;
+ }
+
+ /* Generate output characters in reverse order */
+ while ((long) code >= (long) 256) {
+ *--stackp = tab_suffixof(code);
+ code = tab_prefixof(code);
+ }
+
+ finchar = tab_suffixof(code);
+ *--stackp = (unsigned char) finchar;
+
+ /* And put them out in forward order */
+ {
+ int i;
+
+ i = de_stack - stackp;
+ if (outpos + i >= OBUFSIZ) {
+ do {
+ if (i > OBUFSIZ - outpos) {
+ i = OBUFSIZ - outpos;
+ }
+
+ if (i > 0) {
+ memcpy(outbuf + outpos, stackp, i);
+ outpos += i;
+ }
+
+ if (outpos >= OBUFSIZ) {
+ full_write(fd_out, outbuf, outpos);
+//error check??
+ USE_DESKTOP(total_written += outpos;)
+ outpos = 0;
+ }
+ stackp += i;
+ i = de_stack - stackp;
+ } while (i > 0);
+ } else {
+ memcpy(outbuf + outpos, stackp, i);
+ outpos += i;
+ }
+ }
+
+ /* Generate the new entry. */
+ code = free_ent;
+ if (code < maxmaxcode) {
+ tab_prefixof(code) = (unsigned short) oldcode;
+ tab_suffixof(code) = (unsigned char) finchar;
+ free_ent = code + 1;
+ }
+
+ /* Remember previous code. */
+ oldcode = incode;
+ }
+
+ } while (rsize > 0);
+
+ if (outpos > 0) {
+ full_write(fd_out, outbuf, outpos);
+//error check??
+ USE_DESKTOP(total_written += outpos;)
+ }
+
+ retval = USE_DESKTOP(total_written) + 0;
+ err:
+ free(inbuf);
+ free(outbuf);
+ free(htab);
+ free(codetab);
+ return retval;
+}
diff --git a/release/src/router/busybox/archival/libunarchive/decompress_unlzma.c b/release/src/router/busybox/archival/libunarchive/decompress_unlzma.c
new file mode 100644
index 00000000..2cfcd9b7
--- /dev/null
+++ b/release/src/router/busybox/archival/libunarchive/decompress_unlzma.c
@@ -0,0 +1,503 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Small lzma deflate implementation.
+ * Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
+ *
+ * Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/)
+ * Copyright (C) 1999-2005 Igor Pavlov
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+#if ENABLE_FEATURE_LZMA_FAST
+# define speed_inline ALWAYS_INLINE
+#else
+# define speed_inline
+#endif
+
+
+typedef struct {
+ int fd;
+ uint8_t *ptr;
+
+/* Was keeping rc on stack in unlzma and separately allocating buffer,
+ * but with "buffer 'attached to' allocated rc" code is smaller: */
+ /* uint8_t *buffer; */
+#define RC_BUFFER ((uint8_t*)(rc+1))
+
+ uint8_t *buffer_end;
+
+/* Had provisions for variable buffer, but we don't need it here */
+ /* int buffer_size; */
+#define RC_BUFFER_SIZE 0x10000
+
+ uint32_t code;
+ uint32_t range;
+ uint32_t bound;
+} rc_t;
+
+#define RC_TOP_BITS 24
+#define RC_MOVE_BITS 5
+#define RC_MODEL_TOTAL_BITS 11
+
+
+/* Called twice: once at startup and once in rc_normalize() */
+static void rc_read(rc_t *rc)
+{
+ int buffer_size = safe_read(rc->fd, RC_BUFFER, RC_BUFFER_SIZE);
+ if (buffer_size <= 0)
+ bb_error_msg_and_die("unexpected EOF");
+ rc->ptr = RC_BUFFER;
+ rc->buffer_end = RC_BUFFER + buffer_size;
+}
+
+/* Called once */
+static rc_t* rc_init(int fd) /*, int buffer_size) */
+{
+ int i;
+ rc_t *rc;
+
+ rc = xmalloc(sizeof(*rc) + RC_BUFFER_SIZE);
+
+ rc->fd = fd;
+ /* rc->buffer_size = buffer_size; */
+ rc->buffer_end = RC_BUFFER + RC_BUFFER_SIZE;
+ rc->ptr = rc->buffer_end;
+
+ rc->code = 0;
+ rc->range = 0xFFFFFFFF;
+ for (i = 0; i < 5; i++) {
+ if (rc->ptr >= rc->buffer_end)
+ rc_read(rc);
+ rc->code = (rc->code << 8) | *rc->ptr++;
+ }
+ return rc;
+}
+
+/* Called once */
+static ALWAYS_INLINE void rc_free(rc_t *rc)
+{
+ free(rc);
+}
+
+/* Called twice, but one callsite is in speed_inline'd rc_is_bit_0_helper() */
+static void rc_do_normalize(rc_t *rc)
+{
+ if (rc->ptr >= rc->buffer_end)
+ rc_read(rc);
+ rc->range <<= 8;
+ rc->code = (rc->code << 8) | *rc->ptr++;
+}
+static ALWAYS_INLINE void rc_normalize(rc_t *rc)
+{
+ if (rc->range < (1 << RC_TOP_BITS)) {
+ rc_do_normalize(rc);
+ }
+}
+
+/* rc_is_bit_0 is called 9 times */
+/* Why rc_is_bit_0_helper exists?
+ * Because we want to always expose (rc->code < rc->bound) to optimizer.
+ * Thus rc_is_bit_0 is always inlined, and rc_is_bit_0_helper is inlined
+ * only if we compile for speed.
+ */
+static speed_inline uint32_t rc_is_bit_0_helper(rc_t *rc, uint16_t *p)
+{
+ rc_normalize(rc);
+ rc->bound = *p * (rc->range >> RC_MODEL_TOTAL_BITS);
+ return rc->bound;
+}
+static ALWAYS_INLINE int rc_is_bit_0(rc_t *rc, uint16_t *p)
+{
+ uint32_t t = rc_is_bit_0_helper(rc, p);
+ return rc->code < t;
+}
+
+/* Called ~10 times, but very small, thus inlined */
+static speed_inline void rc_update_bit_0(rc_t *rc, uint16_t *p)
+{
+ rc->range = rc->bound;
+ *p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS;
+}
+static speed_inline void rc_update_bit_1(rc_t *rc, uint16_t *p)
+{
+ rc->range -= rc->bound;
+ rc->code -= rc->bound;
+ *p -= *p >> RC_MOVE_BITS;
+}
+
+/* Called 4 times in unlzma loop */
+static int rc_get_bit(rc_t *rc, uint16_t *p, int *symbol)
+{
+ if (rc_is_bit_0(rc, p)) {
+ rc_update_bit_0(rc, p);
+ *symbol *= 2;
+ return 0;
+ } else {
+ rc_update_bit_1(rc, p);
+ *symbol = *symbol * 2 + 1;
+ return 1;
+ }
+}
+
+/* Called once */
+static ALWAYS_INLINE int rc_direct_bit(rc_t *rc)
+{
+ rc_normalize(rc);
+ rc->range >>= 1;
+ if (rc->code >= rc->range) {
+ rc->code -= rc->range;
+ return 1;
+ }
+ return 0;
+}
+
+/* Called twice */
+static speed_inline void
+rc_bit_tree_decode(rc_t *rc, uint16_t *p, int num_levels, int *symbol)
+{
+ int i = num_levels;
+
+ *symbol = 1;
+ while (i--)
+ rc_get_bit(rc, p + *symbol, symbol);
+ *symbol -= 1 << num_levels;
+}
+
+
+typedef struct {
+ uint8_t pos;
+ uint32_t dict_size;
+ uint64_t dst_size;
+} __attribute__ ((packed)) lzma_header_t;
+
+
+/* #defines will force compiler to compute/optimize each one with each usage.
+ * Have heart and use enum instead. */
+enum {
+ LZMA_BASE_SIZE = 1846,
+ LZMA_LIT_SIZE = 768,
+
+ LZMA_NUM_POS_BITS_MAX = 4,
+
+ LZMA_LEN_NUM_LOW_BITS = 3,
+ LZMA_LEN_NUM_MID_BITS = 3,
+ LZMA_LEN_NUM_HIGH_BITS = 8,
+
+ LZMA_LEN_CHOICE = 0,
+ LZMA_LEN_CHOICE_2 = (LZMA_LEN_CHOICE + 1),
+ LZMA_LEN_LOW = (LZMA_LEN_CHOICE_2 + 1),
+ LZMA_LEN_MID = (LZMA_LEN_LOW \
+ + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_LOW_BITS))),
+ LZMA_LEN_HIGH = (LZMA_LEN_MID \
+ + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_MID_BITS))),
+ LZMA_NUM_LEN_PROBS = (LZMA_LEN_HIGH + (1 << LZMA_LEN_NUM_HIGH_BITS)),
+
+ LZMA_NUM_STATES = 12,
+ LZMA_NUM_LIT_STATES = 7,
+
+ LZMA_START_POS_MODEL_INDEX = 4,
+ LZMA_END_POS_MODEL_INDEX = 14,
+ LZMA_NUM_FULL_DISTANCES = (1 << (LZMA_END_POS_MODEL_INDEX >> 1)),
+
+ LZMA_NUM_POS_SLOT_BITS = 6,
+ LZMA_NUM_LEN_TO_POS_STATES = 4,
+
+ LZMA_NUM_ALIGN_BITS = 4,
+
+ LZMA_MATCH_MIN_LEN = 2,
+
+ LZMA_IS_MATCH = 0,
+ LZMA_IS_REP = (LZMA_IS_MATCH + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)),
+ LZMA_IS_REP_G0 = (LZMA_IS_REP + LZMA_NUM_STATES),
+ LZMA_IS_REP_G1 = (LZMA_IS_REP_G0 + LZMA_NUM_STATES),
+ LZMA_IS_REP_G2 = (LZMA_IS_REP_G1 + LZMA_NUM_STATES),
+ LZMA_IS_REP_0_LONG = (LZMA_IS_REP_G2 + LZMA_NUM_STATES),
+ LZMA_POS_SLOT = (LZMA_IS_REP_0_LONG \
+ + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)),
+ LZMA_SPEC_POS = (LZMA_POS_SLOT \
+ + (LZMA_NUM_LEN_TO_POS_STATES << LZMA_NUM_POS_SLOT_BITS)),
+ LZMA_ALIGN = (LZMA_SPEC_POS \
+ + LZMA_NUM_FULL_DISTANCES - LZMA_END_POS_MODEL_INDEX),
+ LZMA_LEN_CODER = (LZMA_ALIGN + (1 << LZMA_NUM_ALIGN_BITS)),
+ LZMA_REP_LEN_CODER = (LZMA_LEN_CODER + LZMA_NUM_LEN_PROBS),
+ LZMA_LITERAL = (LZMA_REP_LEN_CODER + LZMA_NUM_LEN_PROBS),
+};
+
+
+USE_DESKTOP(long long) int FAST_FUNC
+unpack_lzma_stream(int src_fd, int dst_fd)
+{
+ USE_DESKTOP(long long total_written = 0;)
+ lzma_header_t header;
+ int lc, pb, lp;
+ uint32_t pos_state_mask;
+ uint32_t literal_pos_mask;
+ uint32_t pos;
+ uint16_t *p;
+ uint16_t *prob;
+ uint16_t *prob_lit;
+ int num_bits;
+ int num_probs;
+ rc_t *rc;
+ int i, mi;
+ uint8_t *buffer;
+ uint8_t previous_byte = 0;
+ size_t buffer_pos = 0, global_pos = 0;
+ int len = 0;
+ int state = 0;
+ uint32_t rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+
+ xread(src_fd, &header, sizeof(header));
+
+ if (header.pos >= (9 * 5 * 5))
+ bb_error_msg_and_die("bad header");
+ mi = header.pos / 9;
+ lc = header.pos % 9;
+ pb = mi / 5;
+ lp = mi % 5;
+ pos_state_mask = (1 << pb) - 1;
+ literal_pos_mask = (1 << lp) - 1;
+
+ header.dict_size = SWAP_LE32(header.dict_size);
+ header.dst_size = SWAP_LE64(header.dst_size);
+
+ if (header.dict_size == 0)
+ header.dict_size = 1;
+
+ buffer = xmalloc(MIN(header.dst_size, header.dict_size));
+
+ num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp));
+ p = xmalloc(num_probs * sizeof(*p));
+ num_probs = LZMA_LITERAL + (LZMA_LIT_SIZE << (lc + lp));
+ for (i = 0; i < num_probs; i++)
+ p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1;
+
+ rc = rc_init(src_fd); /*, RC_BUFFER_SIZE); */
+
+ while (global_pos + buffer_pos < header.dst_size) {
+ int pos_state = (buffer_pos + global_pos) & pos_state_mask;
+
+ prob = p + LZMA_IS_MATCH + (state << LZMA_NUM_POS_BITS_MAX) + pos_state;
+ if (rc_is_bit_0(rc, prob)) {
+ mi = 1;
+ rc_update_bit_0(rc, prob);
+ prob = (p + LZMA_LITERAL
+ + (LZMA_LIT_SIZE * ((((buffer_pos + global_pos) & literal_pos_mask) << lc)
+ + (previous_byte >> (8 - lc))
+ )
+ )
+ );
+
+ if (state >= LZMA_NUM_LIT_STATES) {
+ int match_byte;
+
+ pos = buffer_pos - rep0;
+ while (pos >= header.dict_size)
+ pos += header.dict_size;
+ match_byte = buffer[pos];
+ do {
+ int bit;
+
+ match_byte <<= 1;
+ bit = match_byte & 0x100;
+ prob_lit = prob + 0x100 + bit + mi;
+ bit ^= (rc_get_bit(rc, prob_lit, &mi) << 8); /* 0x100 or 0 */
+ if (bit)
+ break;
+ } while (mi < 0x100);
+ }
+ while (mi < 0x100) {
+ prob_lit = prob + mi;
+ rc_get_bit(rc, prob_lit, &mi);
+ }
+
+ state -= 3;
+ if (state < 4-3)
+ state = 0;
+ if (state >= 10-3)
+ state -= 6-3;
+
+ previous_byte = (uint8_t) mi;
+#if ENABLE_FEATURE_LZMA_FAST
+ one_byte1:
+ buffer[buffer_pos++] = previous_byte;
+ if (buffer_pos == header.dict_size) {
+ buffer_pos = 0;
+ global_pos += header.dict_size;
+ if (full_write(dst_fd, buffer, header.dict_size) != (ssize_t)header.dict_size)
+ goto bad;
+ USE_DESKTOP(total_written += header.dict_size;)
+ }
+#else
+ len = 1;
+ goto one_byte2;
+#endif
+ } else {
+ int offset;
+ uint16_t *prob_len;
+
+ rc_update_bit_1(rc, prob);
+ prob = p + LZMA_IS_REP + state;
+ if (rc_is_bit_0(rc, prob)) {
+ rc_update_bit_0(rc, prob);
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ state = state < LZMA_NUM_LIT_STATES ? 0 : 3;
+ prob = p + LZMA_LEN_CODER;
+ } else {
+ rc_update_bit_1(rc, prob);
+ prob = p + LZMA_IS_REP_G0 + state;
+ if (rc_is_bit_0(rc, prob)) {
+ rc_update_bit_0(rc, prob);
+ prob = (p + LZMA_IS_REP_0_LONG
+ + (state << LZMA_NUM_POS_BITS_MAX)
+ + pos_state
+ );
+ if (rc_is_bit_0(rc, prob)) {
+ rc_update_bit_0(rc, prob);
+
+ state = state < LZMA_NUM_LIT_STATES ? 9 : 11;
+#if ENABLE_FEATURE_LZMA_FAST
+ pos = buffer_pos - rep0;
+ while (pos >= header.dict_size)
+ pos += header.dict_size;
+ previous_byte = buffer[pos];
+ goto one_byte1;
+#else
+ len = 1;
+ goto string;
+#endif
+ } else {
+ rc_update_bit_1(rc, prob);
+ }
+ } else {
+ uint32_t distance;
+
+ rc_update_bit_1(rc, prob);
+ prob = p + LZMA_IS_REP_G1 + state;
+ if (rc_is_bit_0(rc, prob)) {
+ rc_update_bit_0(rc, prob);
+ distance = rep1;
+ } else {
+ rc_update_bit_1(rc, prob);
+ prob = p + LZMA_IS_REP_G2 + state;
+ if (rc_is_bit_0(rc, prob)) {
+ rc_update_bit_0(rc, prob);
+ distance = rep2;
+ } else {
+ rc_update_bit_1(rc, prob);
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < LZMA_NUM_LIT_STATES ? 8 : 11;
+ prob = p + LZMA_REP_LEN_CODER;
+ }
+
+ prob_len = prob + LZMA_LEN_CHOICE;
+ if (rc_is_bit_0(rc, prob_len)) {
+ rc_update_bit_0(rc, prob_len);
+ prob_len = (prob + LZMA_LEN_LOW
+ + (pos_state << LZMA_LEN_NUM_LOW_BITS));
+ offset = 0;
+ num_bits = LZMA_LEN_NUM_LOW_BITS;
+ } else {
+ rc_update_bit_1(rc, prob_len);
+ prob_len = prob + LZMA_LEN_CHOICE_2;
+ if (rc_is_bit_0(rc, prob_len)) {
+ rc_update_bit_0(rc, prob_len);
+ prob_len = (prob + LZMA_LEN_MID
+ + (pos_state << LZMA_LEN_NUM_MID_BITS));
+ offset = 1 << LZMA_LEN_NUM_LOW_BITS;
+ num_bits = LZMA_LEN_NUM_MID_BITS;
+ } else {
+ rc_update_bit_1(rc, prob_len);
+ prob_len = prob + LZMA_LEN_HIGH;
+ offset = ((1 << LZMA_LEN_NUM_LOW_BITS)
+ + (1 << LZMA_LEN_NUM_MID_BITS));
+ num_bits = LZMA_LEN_NUM_HIGH_BITS;
+ }
+ }
+ rc_bit_tree_decode(rc, prob_len, num_bits, &len);
+ len += offset;
+
+ if (state < 4) {
+ int pos_slot;
+
+ state += LZMA_NUM_LIT_STATES;
+ prob = p + LZMA_POS_SLOT +
+ ((len < LZMA_NUM_LEN_TO_POS_STATES ? len :
+ LZMA_NUM_LEN_TO_POS_STATES - 1)
+ << LZMA_NUM_POS_SLOT_BITS);
+ rc_bit_tree_decode(rc, prob, LZMA_NUM_POS_SLOT_BITS,
+ &pos_slot);
+ if (pos_slot >= LZMA_START_POS_MODEL_INDEX) {
+ num_bits = (pos_slot >> 1) - 1;
+ rep0 = 2 | (pos_slot & 1);
+ if (pos_slot < LZMA_END_POS_MODEL_INDEX) {
+ rep0 <<= num_bits;
+ prob = p + LZMA_SPEC_POS + rep0 - pos_slot - 1;
+ } else {
+ num_bits -= LZMA_NUM_ALIGN_BITS;
+ while (num_bits--)
+ rep0 = (rep0 << 1) | rc_direct_bit(rc);
+ prob = p + LZMA_ALIGN;
+ rep0 <<= LZMA_NUM_ALIGN_BITS;
+ num_bits = LZMA_NUM_ALIGN_BITS;
+ }
+ i = 1;
+ mi = 1;
+ while (num_bits--) {
+ if (rc_get_bit(rc, prob + mi, &mi))
+ rep0 |= i;
+ i <<= 1;
+ }
+ } else
+ rep0 = pos_slot;
+ if (++rep0 == 0)
+ break;
+ }
+
+ len += LZMA_MATCH_MIN_LEN;
+ SKIP_FEATURE_LZMA_FAST(string:)
+ do {
+ pos = buffer_pos - rep0;
+ while (pos >= header.dict_size)
+ pos += header.dict_size;
+ previous_byte = buffer[pos];
+ SKIP_FEATURE_LZMA_FAST(one_byte2:)
+ buffer[buffer_pos++] = previous_byte;
+ if (buffer_pos == header.dict_size) {
+ buffer_pos = 0;
+ global_pos += header.dict_size;
+ if (full_write(dst_fd, buffer, header.dict_size) != (ssize_t)header.dict_size)
+ goto bad;
+ USE_DESKTOP(total_written += header.dict_size;)
+ }
+ len--;
+ } while (len != 0 && buffer_pos < header.dst_size);
+ }
+ }
+
+ {
+ SKIP_DESKTOP(int total_written = 0; /* success */)
+ USE_DESKTOP(total_written += buffer_pos;)
+ if (full_write(dst_fd, buffer, buffer_pos) != (ssize_t)buffer_pos) {
+ bad:
+ total_written = -1; /* failure */
+ }
+ rc_free(rc);
+ free(p);
+ free(buffer);
+ return total_written;
+ }
+}
diff --git a/release/src/router/busybox/archival/libunarchive/decompress_unzip.c b/release/src/router/busybox/archival/libunarchive/decompress_unzip.c
new file mode 100644
index 00000000..86969251
--- /dev/null
+++ b/release/src/router/busybox/archival/libunarchive/decompress_unzip.c
@@ -0,0 +1,1252 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * gunzip implementation for busybox
+ *
+ * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
+ *
+ * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
+ * based on gzip sources
+ *
+ * Adjusted further by Erik Andersen <andersen@codepoet.org> to support
+ * files as well as stdin/stdout, and to generally behave itself wrt
+ * command line handling.
+ *
+ * General cleanup to better adhere to the style guide and make use of standard
+ * busybox functions by Glenn McGrath
+ *
+ * read_gz interface + associated hacking by Laurence Anderson
+ *
+ * Fixed huft_build() so decoding end-of-block code does not grab more bits
+ * than necessary (this is required by unzip applet), added inflate_cleanup()
+ * to free leaked bytebuffer memory (used in unzip.c), and some minor style
+ * guide cleanups by Ed Clark
+ *
+ * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * The unzip code was written and put in the public domain by Mark Adler.
+ * Portions of the lzw code are derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * See the file algorithm.doc for the compression algorithms and file formats.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <setjmp.h>
+#include "libbb.h"
+#include "unarchive.h"
+
+typedef struct huft_t {
+ unsigned char e; /* number of extra bits or operation */
+ unsigned char b; /* number of bits in this code or subcode */
+ union {
+ unsigned short n; /* literal, length base, or distance base */
+ struct huft_t *t; /* pointer to next level of table */
+ } v;
+} huft_t;
+
+enum {
+ /* gunzip_window size--must be a power of two, and
+ * at least 32K for zip's deflate method */
+ GUNZIP_WSIZE = 0x8000,
+ /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+ BMAX = 16, /* maximum bit length of any code (16 for explode) */
+ N_MAX = 288, /* maximum number of codes in any set */
+};
+
+
+/* This is somewhat complex-looking arrangement, but it allows
+ * to place decompressor state either in bss or in
+ * malloc'ed space simply by changing #defines below.
+ * Sizes on i386:
+ * text data bss dec hex
+ * 5256 0 108 5364 14f4 - bss
+ * 4915 0 0 4915 1333 - malloc
+ */
+#define STATE_IN_BSS 0
+#define STATE_IN_MALLOC 1
+
+
+typedef struct state_t {
+ off_t gunzip_bytes_out; /* number of output bytes */
+ uint32_t gunzip_crc;
+
+ int gunzip_src_fd;
+ unsigned gunzip_outbuf_count; /* bytes in output buffer */
+
+ unsigned char *gunzip_window;
+
+ uint32_t *gunzip_crc_table;
+
+ /* bitbuffer */
+ unsigned gunzip_bb; /* bit buffer */
+ unsigned char gunzip_bk; /* bits in bit buffer */
+
+ /* input (compressed) data */
+ unsigned char *bytebuffer; /* buffer itself */
+ off_t to_read; /* compressed bytes to read (unzip only, -1 for gunzip) */
+// unsigned bytebuffer_max; /* buffer size */
+ unsigned bytebuffer_offset; /* buffer position */
+ unsigned bytebuffer_size; /* how much data is there (size <= max) */
+
+ /* private data of inflate_codes() */
+ unsigned inflate_codes_ml; /* masks for bl and bd bits */
+ unsigned inflate_codes_md; /* masks for bl and bd bits */
+ unsigned inflate_codes_bb; /* bit buffer */
+ unsigned inflate_codes_k; /* number of bits in bit buffer */
+ unsigned inflate_codes_w; /* current gunzip_window position */
+ huft_t *inflate_codes_tl;
+ huft_t *inflate_codes_td;
+ unsigned inflate_codes_bl;
+ unsigned inflate_codes_bd;
+ unsigned inflate_codes_nn; /* length and index for copy */
+ unsigned inflate_codes_dd;
+
+ smallint resume_copy;
+
+ /* private data of inflate_get_next_window() */
+ smallint method; /* method == -1 for stored, -2 for codes */
+ smallint need_another_block;
+ smallint end_reached;
+
+ /* private data of inflate_stored() */
+ unsigned inflate_stored_n;
+ unsigned inflate_stored_b;
+ unsigned inflate_stored_k;
+ unsigned inflate_stored_w;
+
+ const char *error_msg;
+ jmp_buf error_jmp;
+} state_t;
+#define gunzip_bytes_out (S()gunzip_bytes_out )
+#define gunzip_crc (S()gunzip_crc )
+#define gunzip_src_fd (S()gunzip_src_fd )
+#define gunzip_outbuf_count (S()gunzip_outbuf_count)
+#define gunzip_window (S()gunzip_window )
+#define gunzip_crc_table (S()gunzip_crc_table )
+#define gunzip_bb (S()gunzip_bb )
+#define gunzip_bk (S()gunzip_bk )
+#define to_read (S()to_read )
+// #define bytebuffer_max (S()bytebuffer_max )
+// Both gunzip and unzip can use constant buffer size now (16k):
+#define bytebuffer_max 0x4000
+#define bytebuffer (S()bytebuffer )
+#define bytebuffer_offset (S()bytebuffer_offset )
+#define bytebuffer_size (S()bytebuffer_size )
+#define inflate_codes_ml (S()inflate_codes_ml )
+#define inflate_codes_md (S()inflate_codes_md )
+#define inflate_codes_bb (S()inflate_codes_bb )
+#define inflate_codes_k (S()inflate_codes_k )
+#define inflate_codes_w (S()inflate_codes_w )
+#define inflate_codes_tl (S()inflate_codes_tl )
+#define inflate_codes_td (S()inflate_codes_td )
+#define inflate_codes_bl (S()inflate_codes_bl )
+#define inflate_codes_bd (S()inflate_codes_bd )
+#define inflate_codes_nn (S()inflate_codes_nn )
+#define inflate_codes_dd (S()inflate_codes_dd )
+#define resume_copy (S()resume_copy )
+#define method (S()method )
+#define need_another_block (S()need_another_block )
+#define end_reached (S()end_reached )
+#define inflate_stored_n (S()inflate_stored_n )
+#define inflate_stored_b (S()inflate_stored_b )
+#define inflate_stored_k (S()inflate_stored_k )
+#define inflate_stored_w (S()inflate_stored_w )
+#define error_msg (S()error_msg )
+#define error_jmp (S()error_jmp )
+
+/* This is a generic part */
+#if STATE_IN_BSS /* Use global data segment */
+#define DECLARE_STATE /*nothing*/
+#define ALLOC_STATE /*nothing*/
+#define DEALLOC_STATE ((void)0)
+#define S() state.
+#define PASS_STATE /*nothing*/
+#define PASS_STATE_ONLY /*nothing*/
+#define STATE_PARAM /*nothing*/
+#define STATE_PARAM_ONLY void
+static state_t state;
+#endif
+
+#if STATE_IN_MALLOC /* Use malloc space */
+#define DECLARE_STATE state_t *state
+#define ALLOC_STATE (state = xzalloc(sizeof(*state)))
+#define DEALLOC_STATE free(state)
+#define S() state->
+#define PASS_STATE state,
+#define PASS_STATE_ONLY state
+#define STATE_PARAM state_t *state,
+#define STATE_PARAM_ONLY state_t *state
+#endif
+
+
+static const uint16_t mask_bits[] ALIGN2 = {
+ 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+/* Copy lengths for literal codes 257..285 */
+static const uint16_t cplens[] ALIGN2 = {
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
+ 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
+};
+
+/* note: see note #13 above about the 258 in this list. */
+/* Extra bits for literal codes 257..285 */
+static const uint8_t cplext[] ALIGN1 = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5,
+ 5, 5, 5, 0, 99, 99
+}; /* 99 == invalid */
+
+/* Copy offsets for distance codes 0..29 */
+static const uint16_t cpdist[] ALIGN2 = {
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513,
+ 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577
+};
+
+/* Extra bits for distance codes */
+static const uint8_t cpdext[] ALIGN1 = {
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
+ 11, 11, 12, 12, 13, 13
+};
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+/* Order of the bit length code lengths */
+static const uint8_t border[] ALIGN1 = {
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+};
+
+
+/*
+ * Free the malloc'ed tables built by huft_build(), which makes a linked
+ * list of the tables it made, with the links in a dummy first entry of
+ * each table.
+ * t: table to free
+ */
+static void huft_free(huft_t *p)
+{
+ huft_t *q;
+
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ while (p) {
+ q = (--p)->v.t;
+ free(p);
+ p = q;
+ }
+}
+
+static void huft_free_all(STATE_PARAM_ONLY)
+{
+ huft_free(inflate_codes_tl);
+ huft_free(inflate_codes_td);
+ inflate_codes_tl = NULL;
+ inflate_codes_td = NULL;
+}
+
+static void abort_unzip(STATE_PARAM_ONLY) NORETURN;
+static void abort_unzip(STATE_PARAM_ONLY)
+{
+ huft_free_all(PASS_STATE_ONLY);
+ longjmp(error_jmp, 1);
+}
+
+static unsigned fill_bitbuffer(STATE_PARAM unsigned bitbuffer, unsigned *current, const unsigned required)
+{
+ while (*current < required) {
+ if (bytebuffer_offset >= bytebuffer_size) {
+ unsigned sz = bytebuffer_max - 4;
+ if (to_read >= 0 && to_read < sz) /* unzip only */
+ sz = to_read;
+ /* Leave the first 4 bytes empty so we can always unwind the bitbuffer
+ * to the front of the bytebuffer */
+ bytebuffer_size = safe_read(gunzip_src_fd, &bytebuffer[4], sz);
+ if ((int)bytebuffer_size < 1) {
+ error_msg = "unexpected end of file";
+ abort_unzip(PASS_STATE_ONLY);
+ }
+ if (to_read >= 0) /* unzip only */
+ to_read -= bytebuffer_size;
+ bytebuffer_size += 4;
+ bytebuffer_offset = 4;
+ }
+ bitbuffer |= ((unsigned) bytebuffer[bytebuffer_offset]) << *current;
+ bytebuffer_offset++;
+ *current += 8;
+ }
+ return bitbuffer;
+}
+
+
+/* Given a list of code lengths and a maximum table size, make a set of
+ * tables to decode that set of codes. Return zero on success, one if
+ * the given code set is incomplete (the tables are still built in this
+ * case), two if the input is invalid (all zero length codes or an
+ * oversubscribed set of lengths) - in this case stores NULL in *t.
+ *
+ * b: code lengths in bits (all assumed <= BMAX)
+ * n: number of codes (assumed <= N_MAX)
+ * s: number of simple-valued codes (0..s-1)
+ * d: list of base values for non-simple codes
+ * e: list of extra bits for non-simple codes
+ * t: result: starting table
+ * m: maximum lookup bits, returns actual
+ */
+static int huft_build(const unsigned *b, const unsigned n,
+ const unsigned s, const unsigned short *d,
+ const unsigned char *e, huft_t **t, unsigned *m)
+{
+ unsigned a; /* counter for codes of length k */
+ unsigned c[BMAX + 1]; /* bit length count table */
+ unsigned eob_len; /* length of end-of-block code (value 256) */
+ unsigned f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int htl; /* table level */
+ unsigned i; /* counter, current code */
+ unsigned j; /* counter */
+ int k; /* number of bits in current code */
+ unsigned *p; /* pointer into c[], b[], or v[] */
+ huft_t *q; /* points to current table */
+ huft_t r; /* table entry for structure assignment */
+ huft_t *u[BMAX]; /* table stack */
+ unsigned v[N_MAX]; /* values in order of bit length */
+ int ws[BMAX + 1]; /* bits decoded stack */
+ int w; /* bits decoded */
+ unsigned x[BMAX + 1]; /* bit offsets, then code stack */
+ unsigned *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ unsigned z; /* number of entries in current table */
+
+ /* Length of EOB code, if any */
+ eob_len = n > 256 ? b[256] : BMAX;
+
+ *t = NULL;
+
+ /* Generate counts for each bit length */
+ memset(c, 0, sizeof(c));
+ p = (unsigned *) b; /* cast allows us to reuse p for pointing to b */
+ i = n;
+ do {
+ c[*p]++; /* assume all entries <= BMAX */
+ p++; /* can't combine with above line (Solaris bug) */
+ } while (--i);
+ if (c[0] == n) { /* null input - all zero length codes */
+ *m = 0;
+ return 2;
+ }
+
+ /* Find minimum and maximum length, bound *m by those */
+ for (j = 1; (c[j] == 0) && (j <= BMAX); j++)
+ continue;
+ k = j; /* minimum code length */
+ for (i = BMAX; (c[i] == 0) && i; i--)
+ continue;
+ g = i; /* maximum code length */
+ *m = (*m < j) ? j : ((*m > i) ? i : *m);
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1) {
+ y -= c[j];
+ if (y < 0)
+ return 2; /* bad input: more codes than bits */
+ }
+ y -= c[i];
+ if (y < 0)
+ return 2;
+ c[i] += y;
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1;
+ xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ j += *p++;
+ *xp++ = j;
+ }
+
+ /* Make a table of values in order of bit lengths */
+ p = (unsigned *) b;
+ i = 0;
+ do {
+ j = *p++;
+ if (j != 0) {
+ v[x[j]++] = i;
+ }
+ } while (++i < n);
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ htl = -1; /* no tables yet--level -1 */
+ w = ws[0] = 0; /* bits decoded */
+ u[0] = NULL; /* just to keep compilers happy */
+ q = NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++) {
+ a = c[k];
+ while (a--) {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > ws[htl + 1]) {
+ w = ws[++htl];
+
+ /* compute minimum size table less than or equal to *m bits */
+ z = g - w;
+ z = z > *m ? *m : z; /* upper limit on table size */
+ j = k - w;
+ f = 1 << j;
+ if (f > a + 1) { /* try a k-w bit table */
+ /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ while (++j < z) { /* try smaller tables up to z bits */
+ f <<= 1;
+ if (f <= *++xp) {
+ break; /* enough codes to use up j bits */
+ }
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ j = (w + j > eob_len && w < eob_len) ? eob_len - w : j; /* make EOB code end at table */
+ z = 1 << j; /* table entries for j-bit table */
+ ws[htl+1] = w + j; /* set bits decoded in stack */
+
+ /* allocate and link in new table */
+ q = xzalloc((z + 1) * sizeof(huft_t));
+ *t = q + 1; /* link to list for huft_free() */
+ t = &(q->v.t);
+ u[htl] = ++q; /* table starts after link */
+
+ /* connect to last table, if there is one */
+ if (htl) {
+ x[htl] = i; /* save pattern for backing up */
+ r.b = (unsigned char) (w - ws[htl - 1]); /* bits to dump before this table */
+ r.e = (unsigned char) (16 + j); /* bits in this table */
+ r.v.t = q; /* pointer to this table */
+ j = (i & ((1 << w) - 1)) >> ws[htl - 1];
+ u[htl - 1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.b = (unsigned char) (k - w);
+ if (p >= v + n) {
+ r.e = 99; /* out of values--invalid code */
+ } else if (*p < s) {
+ r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is EOB code */
+ r.v.n = (unsigned short) (*p++); /* simple code is just the value */
+ } else {
+ r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */
+ r.v.n = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f) {
+ q[j] = r;
+ }
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1) {
+ i ^= j;
+ }
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[htl]) {
+ w = ws[--htl];
+ }
+ }
+ }
+
+ /* return actual size of base table */
+ *m = ws[1];
+
+ /* Return 1 if we were given an incomplete table */
+ return y != 0 && g != 1;
+}
+
+
+/*
+ * inflate (decompress) the codes in a deflated (compressed) block.
+ * Return an error code or zero if it all goes ok.
+ *
+ * tl, td: literal/length and distance decoder tables
+ * bl, bd: number of bits decoded by tl[] and td[]
+ */
+/* called once from inflate_block */
+
+/* map formerly local static variables to globals */
+#define ml inflate_codes_ml
+#define md inflate_codes_md
+#define bb inflate_codes_bb
+#define k inflate_codes_k
+#define w inflate_codes_w
+#define tl inflate_codes_tl
+#define td inflate_codes_td
+#define bl inflate_codes_bl
+#define bd inflate_codes_bd
+#define nn inflate_codes_nn
+#define dd inflate_codes_dd
+static void inflate_codes_setup(STATE_PARAM unsigned my_bl, unsigned my_bd)
+{
+ bl = my_bl;
+ bd = my_bd;
+ /* make local copies of globals */
+ bb = gunzip_bb; /* initialize bit buffer */
+ k = gunzip_bk;
+ w = gunzip_outbuf_count; /* initialize gunzip_window position */
+ /* inflate the coded data */
+ ml = mask_bits[bl]; /* precompute masks for speed */
+ md = mask_bits[bd];
+}
+/* called once from inflate_get_next_window */
+static int inflate_codes(STATE_PARAM_ONLY)
+{
+ unsigned e; /* table entry flag/number of extra bits */
+ huft_t *t; /* pointer to table entry */
+
+ if (resume_copy)
+ goto do_copy;
+
+ while (1) { /* do until end of block */
+ bb = fill_bitbuffer(PASS_STATE bb, &k, bl);
+ t = tl + ((unsigned) bb & ml);
+ e = t->e;
+ if (e > 16)
+ do {
+ if (e == 99)
+ abort_unzip(PASS_STATE_ONLY);;
+ bb >>= t->b;
+ k -= t->b;
+ e -= 16;
+ bb = fill_bitbuffer(PASS_STATE bb, &k, e);
+ t = t->v.t + ((unsigned) bb & mask_bits[e]);
+ e = t->e;
+ } while (e > 16);
+ bb >>= t->b;
+ k -= t->b;
+ if (e == 16) { /* then it's a literal */
+ gunzip_window[w++] = (unsigned char) t->v.n;
+ if (w == GUNZIP_WSIZE) {
+ gunzip_outbuf_count = w;
+ //flush_gunzip_window();
+ w = 0;
+ return 1; // We have a block to read
+ }
+ } else { /* it's an EOB or a length */
+ /* exit if end of block */
+ if (e == 15) {
+ break;
+ }
+
+ /* get length of block to copy */
+ bb = fill_bitbuffer(PASS_STATE bb, &k, e);
+ nn = t->v.n + ((unsigned) bb & mask_bits[e]);
+ bb >>= e;
+ k -= e;
+
+ /* decode distance of block to copy */
+ bb = fill_bitbuffer(PASS_STATE bb, &k, bd);
+ t = td + ((unsigned) bb & md);
+ e = t->e;
+ if (e > 16)
+ do {
+ if (e == 99)
+ abort_unzip(PASS_STATE_ONLY);
+ bb >>= t->b;
+ k -= t->b;
+ e -= 16;
+ bb = fill_bitbuffer(PASS_STATE bb, &k, e);
+ t = t->v.t + ((unsigned) bb & mask_bits[e]);
+ e = t->e;
+ } while (e > 16);
+ bb >>= t->b;
+ k -= t->b;
+ bb = fill_bitbuffer(PASS_STATE bb, &k, e);
+ dd = w - t->v.n - ((unsigned) bb & mask_bits[e]);
+ bb >>= e;
+ k -= e;
+
+ /* do the copy */
+ do_copy:
+ do {
+ /* Was: nn -= (e = (e = GUNZIP_WSIZE - ((dd &= GUNZIP_WSIZE - 1) > w ? dd : w)) > nn ? nn : e); */
+ /* Who wrote THAT?? rewritten as: */
+ dd &= GUNZIP_WSIZE - 1;
+ e = GUNZIP_WSIZE - (dd > w ? dd : w);
+ if (e > nn) e = nn;
+ nn -= e;
+
+ /* copy to new buffer to prevent possible overwrite */
+ if (w - dd >= e) { /* (this test assumes unsigned comparison) */
+ memcpy(gunzip_window + w, gunzip_window + dd, e);
+ w += e;
+ dd += e;
+ } else {
+ /* do it slow to avoid memcpy() overlap */
+ /* !NOMEMCPY */
+ do {
+ gunzip_window[w++] = gunzip_window[dd++];
+ } while (--e);
+ }
+ if (w == GUNZIP_WSIZE) {
+ gunzip_outbuf_count = w;
+ resume_copy = (nn != 0);
+ //flush_gunzip_window();
+ w = 0;
+ return 1;
+ }
+ } while (nn);
+ resume_copy = 0;
+ }
+ }
+
+ /* restore the globals from the locals */
+ gunzip_outbuf_count = w; /* restore global gunzip_window pointer */
+ gunzip_bb = bb; /* restore global bit buffer */
+ gunzip_bk = k;
+
+ /* normally just after call to inflate_codes, but save code by putting it here */
+ /* free the decoding tables (tl and td), return */
+ huft_free_all(PASS_STATE_ONLY);
+
+ /* done */
+ return 0;
+}
+#undef ml
+#undef md
+#undef bb
+#undef k
+#undef w
+#undef tl
+#undef td
+#undef bl
+#undef bd
+#undef nn
+#undef dd
+
+
+/* called once from inflate_block */
+static void inflate_stored_setup(STATE_PARAM int my_n, int my_b, int my_k)
+{
+ inflate_stored_n = my_n;
+ inflate_stored_b = my_b;
+ inflate_stored_k = my_k;
+ /* initialize gunzip_window position */
+ inflate_stored_w = gunzip_outbuf_count;
+}
+/* called once from inflate_get_next_window */
+static int inflate_stored(STATE_PARAM_ONLY)
+{
+ /* read and output the compressed data */
+ while (inflate_stored_n--) {
+ inflate_stored_b = fill_bitbuffer(PASS_STATE inflate_stored_b, &inflate_stored_k, 8);
+ gunzip_window[inflate_stored_w++] = (unsigned char) inflate_stored_b;
+ if (inflate_stored_w == GUNZIP_WSIZE) {
+ gunzip_outbuf_count = inflate_stored_w;
+ //flush_gunzip_window();
+ inflate_stored_w = 0;
+ inflate_stored_b >>= 8;
+ inflate_stored_k -= 8;
+ return 1; /* We have a block */
+ }
+ inflate_stored_b >>= 8;
+ inflate_stored_k -= 8;
+ }
+
+ /* restore the globals from the locals */
+ gunzip_outbuf_count = inflate_stored_w; /* restore global gunzip_window pointer */
+ gunzip_bb = inflate_stored_b; /* restore global bit buffer */
+ gunzip_bk = inflate_stored_k;
+ return 0; /* Finished */
+}
+
+
+/*
+ * decompress an inflated block
+ * e: last block flag
+ *
+ * GLOBAL VARIABLES: bb, kk,
+ */
+/* Return values: -1 = inflate_stored, -2 = inflate_codes */
+/* One callsite in inflate_get_next_window */
+static int inflate_block(STATE_PARAM smallint *e)
+{
+ unsigned ll[286 + 30]; /* literal/length and distance code lengths */
+ unsigned t; /* block type */
+ unsigned b; /* bit buffer */
+ unsigned k; /* number of bits in bit buffer */
+
+ /* make local bit buffer */
+
+ b = gunzip_bb;
+ k = gunzip_bk;
+
+ /* read in last block bit */
+ b = fill_bitbuffer(PASS_STATE b, &k, 1);
+ *e = b & 1;
+ b >>= 1;
+ k -= 1;
+
+ /* read in block type */
+ b = fill_bitbuffer(PASS_STATE b, &k, 2);
+ t = (unsigned) b & 3;
+ b >>= 2;
+ k -= 2;
+
+ /* restore the global bit buffer */
+ gunzip_bb = b;
+ gunzip_bk = k;
+
+ /* Do we see block type 1 often? Yes!
+ * TODO: fix performance problem (see below) */
+ //bb_error_msg("blktype %d", t);
+
+ /* inflate that block type */
+ switch (t) {
+ case 0: /* Inflate stored */
+ {
+ unsigned n; /* number of bytes in block */
+ unsigned b_stored; /* bit buffer */
+ unsigned k_stored; /* number of bits in bit buffer */
+
+ /* make local copies of globals */
+ b_stored = gunzip_bb; /* initialize bit buffer */
+ k_stored = gunzip_bk;
+
+ /* go to byte boundary */
+ n = k_stored & 7;
+ b_stored >>= n;
+ k_stored -= n;
+
+ /* get the length and its complement */
+ b_stored = fill_bitbuffer(PASS_STATE b_stored, &k_stored, 16);
+ n = ((unsigned) b_stored & 0xffff);
+ b_stored >>= 16;
+ k_stored -= 16;
+
+ b_stored = fill_bitbuffer(PASS_STATE b_stored, &k_stored, 16);
+ if (n != (unsigned) ((~b_stored) & 0xffff)) {
+ abort_unzip(PASS_STATE_ONLY); /* error in compressed data */
+ }
+ b_stored >>= 16;
+ k_stored -= 16;
+
+ inflate_stored_setup(PASS_STATE n, b_stored, k_stored);
+
+ return -1;
+ }
+ case 1:
+ /* Inflate fixed
+ * decompress an inflated type 1 (fixed Huffman codes) block. We should
+ * either replace this with a custom decoder, or at least precompute the
+ * Huffman tables. TODO */
+ {
+ int i; /* temporary variable */
+ unsigned bl; /* lookup bits for tl */
+ unsigned bd; /* lookup bits for td */
+ /* gcc 4.2.1 is too dumb to reuse stackspace. Moved up... */
+ //unsigned ll[288]; /* length list for huft_build */
+
+ /* set up literal table */
+ for (i = 0; i < 144; i++)
+ ll[i] = 8;
+ for (; i < 256; i++)
+ ll[i] = 9;
+ for (; i < 280; i++)
+ ll[i] = 7;
+ for (; i < 288; i++) /* make a complete, but wrong code set */
+ ll[i] = 8;
+ bl = 7;
+ huft_build(ll, 288, 257, cplens, cplext, &inflate_codes_tl, &bl);
+ /* huft_build() never return nonzero - we use known data */
+
+ /* set up distance table */
+ for (i = 0; i < 30; i++) /* make an incomplete code set */
+ ll[i] = 5;
+ bd = 5;
+ huft_build(ll, 30, 0, cpdist, cpdext, &inflate_codes_td, &bd);
+
+ /* set up data for inflate_codes() */
+ inflate_codes_setup(PASS_STATE bl, bd);
+
+ /* huft_free code moved into inflate_codes */
+
+ return -2;
+ }
+ case 2: /* Inflate dynamic */
+ {
+ enum { dbits = 6 }; /* bits in base distance lookup table */
+ enum { lbits = 9 }; /* bits in base literal/length lookup table */
+
+ huft_t *td; /* distance code table */
+ unsigned i; /* temporary variables */
+ unsigned j;
+ unsigned l; /* last length */
+ unsigned m; /* mask for bit lengths table */
+ unsigned n; /* number of lengths to get */
+ unsigned bl; /* lookup bits for tl */
+ unsigned bd; /* lookup bits for td */
+ unsigned nb; /* number of bit length codes */
+ unsigned nl; /* number of literal/length codes */
+ unsigned nd; /* number of distance codes */
+
+ //unsigned ll[286 + 30];/* literal/length and distance code lengths */
+ unsigned b_dynamic; /* bit buffer */
+ unsigned k_dynamic; /* number of bits in bit buffer */
+
+ /* make local bit buffer */
+ b_dynamic = gunzip_bb;
+ k_dynamic = gunzip_bk;
+
+ /* read in table lengths */
+ b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 5);
+ nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */
+
+ b_dynamic >>= 5;
+ k_dynamic -= 5;
+ b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 5);
+ nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */
+
+ b_dynamic >>= 5;
+ k_dynamic -= 5;
+ b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 4);
+ nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */
+
+ b_dynamic >>= 4;
+ k_dynamic -= 4;
+ if (nl > 286 || nd > 30)
+ abort_unzip(PASS_STATE_ONLY); /* bad lengths */
+
+ /* read in bit-length-code lengths */
+ for (j = 0; j < nb; j++) {
+ b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 3);
+ ll[border[j]] = (unsigned) b_dynamic & 7;
+ b_dynamic >>= 3;
+ k_dynamic -= 3;
+ }
+ for (; j < 19; j++)
+ ll[border[j]] = 0;
+
+ /* build decoding table for trees - single level, 7 bit lookup */
+ bl = 7;
+ i = huft_build(ll, 19, 19, NULL, NULL, &inflate_codes_tl, &bl);
+ if (i != 0) {
+ abort_unzip(PASS_STATE_ONLY); //return i; /* incomplete code set */
+ }
+
+ /* read in literal and distance code lengths */
+ n = nl + nd;
+ m = mask_bits[bl];
+ i = l = 0;
+ while ((unsigned) i < n) {
+ b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, (unsigned)bl);
+ td = inflate_codes_tl + ((unsigned) b_dynamic & m);
+ j = td->b;
+ b_dynamic >>= j;
+ k_dynamic -= j;
+ j = td->v.n;
+ if (j < 16) { /* length of code in bits (0..15) */
+ ll[i++] = l = j; /* save last length in l */
+ } else if (j == 16) { /* repeat last length 3 to 6 times */
+ b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 2);
+ j = 3 + ((unsigned) b_dynamic & 3);
+ b_dynamic >>= 2;
+ k_dynamic -= 2;
+ if ((unsigned) i + j > n) {
+ abort_unzip(PASS_STATE_ONLY); //return 1;
+ }
+ while (j--) {
+ ll[i++] = l;
+ }
+ } else if (j == 17) { /* 3 to 10 zero length codes */
+ b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 3);
+ j = 3 + ((unsigned) b_dynamic & 7);
+ b_dynamic >>= 3;
+ k_dynamic -= 3;
+ if ((unsigned) i + j > n) {
+ abort_unzip(PASS_STATE_ONLY); //return 1;
+ }
+ while (j--) {
+ ll[i++] = 0;
+ }
+ l = 0;
+ } else { /* j == 18: 11 to 138 zero length codes */
+ b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 7);
+ j = 11 + ((unsigned) b_dynamic & 0x7f);
+ b_dynamic >>= 7;
+ k_dynamic -= 7;
+ if ((unsigned) i + j > n) {
+ abort_unzip(PASS_STATE_ONLY); //return 1;
+ }
+ while (j--) {
+ ll[i++] = 0;
+ }
+ l = 0;
+ }
+ }
+
+ /* free decoding table for trees */
+ huft_free(inflate_codes_tl);
+
+ /* restore the global bit buffer */
+ gunzip_bb = b_dynamic;
+ gunzip_bk = k_dynamic;
+
+ /* build the decoding tables for literal/length and distance codes */
+ bl = lbits;
+
+ i = huft_build(ll, nl, 257, cplens, cplext, &inflate_codes_tl, &bl);
+ if (i != 0)
+ abort_unzip(PASS_STATE_ONLY);
+ bd = dbits;
+ i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &inflate_codes_td, &bd);
+ if (i != 0)
+ abort_unzip(PASS_STATE_ONLY);
+
+ /* set up data for inflate_codes() */
+ inflate_codes_setup(PASS_STATE bl, bd);
+
+ /* huft_free code moved into inflate_codes */
+
+ return -2;
+ }
+ default:
+ abort_unzip(PASS_STATE_ONLY);
+ }
+}
+
+/* Two callsites, both in inflate_get_next_window */
+static void calculate_gunzip_crc(STATE_PARAM_ONLY)
+{
+ unsigned n;
+ for (n = 0; n < gunzip_outbuf_count; n++) {
+ gunzip_crc = gunzip_crc_table[((int) gunzip_crc ^ (gunzip_window[n])) & 0xff] ^ (gunzip_crc >> 8);
+ }
+ gunzip_bytes_out += gunzip_outbuf_count;
+}
+
+/* One callsite in inflate_unzip_internal */
+static int inflate_get_next_window(STATE_PARAM_ONLY)
+{
+ gunzip_outbuf_count = 0;
+
+ while (1) {
+ int ret;
+
+ if (need_another_block) {
+ if (end_reached) {
+ calculate_gunzip_crc(PASS_STATE_ONLY);
+ end_reached = 0;
+ /* NB: need_another_block is still set */
+ return 0; /* Last block */
+ }
+ method = inflate_block(PASS_STATE &end_reached);
+ need_another_block = 0;
+ }
+
+ switch (method) {
+ case -1:
+ ret = inflate_stored(PASS_STATE_ONLY);
+ break;
+ case -2:
+ ret = inflate_codes(PASS_STATE_ONLY);
+ break;
+ default: /* cannot happen */
+ abort_unzip(PASS_STATE_ONLY);
+ }
+
+ if (ret == 1) {
+ calculate_gunzip_crc(PASS_STATE_ONLY);
+ return 1; /* more data left */
+ }
+ need_another_block = 1; /* end of that block */
+ }
+ /* Doesnt get here */
+}
+
+
+/* Called from unpack_gz_stream() and inflate_unzip() */
+static USE_DESKTOP(long long) int
+inflate_unzip_internal(STATE_PARAM int in, int out)
+{
+ USE_DESKTOP(long long) int n = 0;
+ ssize_t nwrote;
+
+ /* Allocate all global buffers (for DYN_ALLOC option) */
+ gunzip_window = xmalloc(GUNZIP_WSIZE);
+ gunzip_outbuf_count = 0;
+ gunzip_bytes_out = 0;
+ gunzip_src_fd = in;
+
+ /* (re) initialize state */
+ method = -1;
+ need_another_block = 1;
+ resume_copy = 0;
+ gunzip_bk = 0;
+ gunzip_bb = 0;
+
+ /* Create the crc table */
+ gunzip_crc_table = crc32_filltable(NULL, 0);
+ gunzip_crc = ~0;
+
+ error_msg = "corrupted data";
+ if (setjmp(error_jmp)) {
+ /* Error from deep inside zip machinery */
+ n = -1;
+ goto ret;
+ }
+
+ while (1) {
+ int r = inflate_get_next_window(PASS_STATE_ONLY);
+ nwrote = full_write(out, gunzip_window, gunzip_outbuf_count);
+ if (nwrote != (ssize_t)gunzip_outbuf_count) {
+ bb_perror_msg("write");
+ n = -1;
+ goto ret;
+ }
+ USE_DESKTOP(n += nwrote;)
+ if (r == 0) break;
+ }
+
+ /* Store unused bytes in a global buffer so calling applets can access it */
+ if (gunzip_bk >= 8) {
+ /* Undo too much lookahead. The next read will be byte aligned
+ * so we can discard unused bits in the last meaningful byte. */
+ bytebuffer_offset--;
+ bytebuffer[bytebuffer_offset] = gunzip_bb & 0xff;
+ gunzip_bb >>= 8;
+ gunzip_bk -= 8;
+ }
+ ret:
+ /* Cleanup */
+ free(gunzip_window);
+ free(gunzip_crc_table);
+ return n;
+}
+
+
+/* External entry points */
+
+/* For unzip */
+
+USE_DESKTOP(long long) int FAST_FUNC
+inflate_unzip(inflate_unzip_result *res, off_t compr_size, int in, int out)
+{
+ USE_DESKTOP(long long) int n;
+ DECLARE_STATE;
+
+ ALLOC_STATE;
+
+ to_read = compr_size;
+// bytebuffer_max = 0x8000;
+ bytebuffer_offset = 4;
+ bytebuffer = xmalloc(bytebuffer_max);
+ n = inflate_unzip_internal(PASS_STATE in, out);
+ free(bytebuffer);
+
+ res->crc = gunzip_crc;
+ res->bytes_out = gunzip_bytes_out;
+ DEALLOC_STATE;
+ return n;
+}
+
+
+/* For gunzip */
+
+/* helpers first */
+
+/* Top up the input buffer with at least n bytes. */
+static int top_up(STATE_PARAM unsigned n)
+{
+ int count = bytebuffer_size - bytebuffer_offset;
+
+ if (count < (int)n) {
+ memmove(bytebuffer, &bytebuffer[bytebuffer_offset], count);
+ bytebuffer_offset = 0;
+ bytebuffer_size = full_read(gunzip_src_fd, &bytebuffer[count], bytebuffer_max - count);
+ if ((int)bytebuffer_size < 0) {
+ bb_error_msg("read error");
+ return 0;
+ }
+ bytebuffer_size += count;
+ if (bytebuffer_size < n)
+ return 0;
+ }
+ return 1;
+}
+
+static uint16_t buffer_read_le_u16(STATE_PARAM_ONLY)
+{
+ uint16_t res;
+#if BB_LITTLE_ENDIAN
+ move_from_unaligned16(res, &bytebuffer[bytebuffer_offset]);
+#else
+ res = bytebuffer[bytebuffer_offset];
+ res |= bytebuffer[bytebuffer_offset + 1] << 8;
+#endif
+ bytebuffer_offset += 2;
+ return res;
+}
+
+static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY)
+{
+ uint32_t res;
+#if BB_LITTLE_ENDIAN
+ move_from_unaligned32(res, &bytebuffer[bytebuffer_offset]);
+#else
+ res = bytebuffer[bytebuffer_offset];
+ res |= bytebuffer[bytebuffer_offset + 1] << 8;
+ res |= bytebuffer[bytebuffer_offset + 2] << 16;
+ res |= bytebuffer[bytebuffer_offset + 3] << 24;
+#endif
+ bytebuffer_offset += 4;
+ return res;
+}
+
+static int check_header_gzip(STATE_PARAM unpack_info_t *info)
+{
+ union {
+ unsigned char raw[8];
+ struct {
+ uint8_t gz_method;
+ uint8_t flags;
+ uint32_t mtime;
+ uint8_t xtra_flags_UNUSED;
+ uint8_t os_flags_UNUSED;
+ } __attribute__((packed)) formatted;
+ } header;
+ struct BUG_header {
+ char BUG_header[sizeof(header) == 8 ? 1 : -1];
+ };
+
+ /*
+ * Rewind bytebuffer. We use the beginning because the header has 8
+ * bytes, leaving enough for unwinding afterwards.
+ */
+ bytebuffer_size -= bytebuffer_offset;
+ memmove(bytebuffer, &bytebuffer[bytebuffer_offset], bytebuffer_size);
+ bytebuffer_offset = 0;
+
+ if (!top_up(PASS_STATE 8))
+ return 0;
+ memcpy(header.raw, &bytebuffer[bytebuffer_offset], 8);
+ bytebuffer_offset += 8;
+
+ /* Check the compression method */
+ if (header.formatted.gz_method != 8) {
+ return 0;
+ }
+
+ if (header.formatted.flags & 0x04) {
+ /* bit 2 set: extra field present */
+ unsigned extra_short;
+
+ if (!top_up(PASS_STATE 2))
+ return 0;
+ extra_short = buffer_read_le_u16(PASS_STATE_ONLY);
+ if (!top_up(PASS_STATE extra_short))
+ return 0;
+ /* Ignore extra field */
+ bytebuffer_offset += extra_short;
+ }
+
+ /* Discard original name and file comment if any */
+ /* bit 3 set: original file name present */
+ /* bit 4 set: file comment present */
+ if (header.formatted.flags & 0x18) {
+ while (1) {
+ do {
+ if (!top_up(PASS_STATE 1))
+ return 0;
+ } while (bytebuffer[bytebuffer_offset++] != 0);
+ if ((header.formatted.flags & 0x18) != 0x18)
+ break;
+ header.formatted.flags &= ~0x18;
+ }
+ }
+
+ if (info)
+ info->mtime = SWAP_LE32(header.formatted.mtime);
+
+ /* Read the header checksum */
+ if (header.formatted.flags & 0x02) {
+ if (!top_up(PASS_STATE 2))
+ return 0;
+ bytebuffer_offset += 2;
+ }
+ return 1;
+}
+
+USE_DESKTOP(long long) int FAST_FUNC
+unpack_gz_stream_with_info(int in, int out, unpack_info_t *info)
+{
+ uint32_t v32;
+ USE_DESKTOP(long long) int n;
+ DECLARE_STATE;
+
+ n = 0;
+
+ ALLOC_STATE;
+ to_read = -1;
+// bytebuffer_max = 0x8000;
+ bytebuffer = xmalloc(bytebuffer_max);
+ gunzip_src_fd = in;
+
+ again:
+ if (!check_header_gzip(PASS_STATE info)) {
+ bb_error_msg("corrupted data");
+ n = -1;
+ goto ret;
+ }
+ n += inflate_unzip_internal(PASS_STATE in, out);
+ if (n < 0)
+ goto ret;
+
+ if (!top_up(PASS_STATE 8)) {
+ bb_error_msg("corrupted data");
+ n = -1;
+ goto ret;
+ }
+
+ /* Validate decompression - crc */
+ v32 = buffer_read_le_u32(PASS_STATE_ONLY);
+ if ((~gunzip_crc) != v32) {
+ bb_error_msg("crc error");
+ n = -1;
+ goto ret;
+ }
+
+ /* Validate decompression - size */
+ v32 = buffer_read_le_u32(PASS_STATE_ONLY);
+ if ((uint32_t)gunzip_bytes_out != v32) {
+ bb_error_msg("incorrect length");
+ n = -1;
+ }
+
+ if (!top_up(PASS_STATE 2))
+ goto ret; /* EOF */
+
+ if (bytebuffer[bytebuffer_offset] == 0x1f
+ && bytebuffer[bytebuffer_offset + 1] == 0x8b
+ ) {
+ bytebuffer_offset += 2;
+ goto again;
+ }
+ /* GNU gzip says: */
+ /*bb_error_msg("decompression OK, trailing garbage ignored");*/
+
+ ret:
+ free(bytebuffer);
+ DEALLOC_STATE;
+ return n;
+}
+
+USE_DESKTOP(long long) int FAST_FUNC
+unpack_gz_stream(int in, int out)
+{
+ return unpack_gz_stream_with_info(in, out, NULL);
+}
diff --git a/release/src/router/busybox/archival/libunarchive/filter_accept_all.c b/release/src/router/busybox/archival/libunarchive/filter_accept_all.c
index baf9e4b7..21f9c5c9 100644
--- a/release/src/router/busybox/archival/libunarchive/filter_accept_all.c
+++ b/release/src/router/busybox/archival/libunarchive/filter_accept_all.c
@@ -1,32 +1,17 @@
+/* vi: set sw=4 ts=4: */
/*
- * Copyright (C) 2002 by Glenn McGrath
+ * Copyright (C) 2002 by Glenn McGrath
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <fnmatch.h>
-#include <stdlib.h>
-
+#include "libbb.h"
#include "unarchive.h"
/* Accept any non-null name, its not really a filter at all */
-extern char filter_accept_all(archive_handle_t *archive_handle)
+char FAST_FUNC filter_accept_all(archive_handle_t *archive_handle)
{
- if (archive_handle->file_header->name) {
- return(EXIT_SUCCESS);
- } else {
- return(EXIT_FAILURE);
- }
+ if (archive_handle->file_header->name)
+ return EXIT_SUCCESS;
+ return EXIT_FAILURE;
}
diff --git a/release/src/router/busybox/archival/libunarchive/filter_accept_list.c b/release/src/router/busybox/archival/libunarchive/filter_accept_list.c
index e1c4827b..afa0b4cb 100644
--- a/release/src/router/busybox/archival/libunarchive/filter_accept_list.c
+++ b/release/src/router/busybox/archival/libunarchive/filter_accept_list.c
@@ -1,34 +1,19 @@
+/* vi: set sw=4 ts=4: */
/*
- * Copyright (C) 2002 by Glenn McGrath
+ * Copyright (C) 2002 by Glenn McGrath
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <fnmatch.h>
-#include <stdlib.h>
-
+#include "libbb.h"
#include "unarchive.h"
/*
* Accept names that are in the accept list, ignoring reject list.
*/
-extern char filter_accept_list(archive_handle_t *archive_handle)
+char FAST_FUNC filter_accept_list(archive_handle_t *archive_handle)
{
- if (find_list_entry(archive_handle->accept, archive_handle->file_header->name)) {
- return(EXIT_SUCCESS);
- } else {
- return(EXIT_FAILURE);
- }
+ if (find_list_entry(archive_handle->accept, archive_handle->file_header->name))
+ return EXIT_SUCCESS;
+ return EXIT_FAILURE;
}
diff --git a/release/src/router/busybox/archival/libunarchive/filter_accept_list_reassign.c b/release/src/router/busybox/archival/libunarchive/filter_accept_list_reassign.c
index d9bee79d..f1de4e80 100644
--- a/release/src/router/busybox/archival/libunarchive/filter_accept_list_reassign.c
+++ b/release/src/router/busybox/archival/libunarchive/filter_accept_list_reassign.c
@@ -1,58 +1,51 @@
+/* vi: set sw=4 ts=4: */
/*
* Copyright (C) 2002 by Glenn McGrath
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
#include "libbb.h"
#include "unarchive.h"
+/* Built and used only if ENABLE_DPKG || ENABLE_DPKG_DEB */
+
/*
- * Reassign the subarchive metadata parser based on the filename extension
- * e.g. if its a .tar.gz modify archive_handle->sub_archive to process a .tar.gz
- * or if its a .tar.bz2 make archive_handle->sub_archive handle that
+ * Reassign the subarchive metadata parser based on the filename extension
+ * e.g. if its a .tar.gz modify archive_handle->sub_archive to process a .tar.gz
+ * or if its a .tar.bz2 make archive_handle->sub_archive handle that
*/
-extern char filter_accept_list_reassign(archive_handle_t *archive_handle)
+char FAST_FUNC filter_accept_list_reassign(archive_handle_t *archive_handle)
{
/* Check the file entry is in the accept list */
if (find_list_entry(archive_handle->accept, archive_handle->file_header->name)) {
const char *name_ptr;
- /* Extract the last 2 extensions */
+ /* Find extension */
name_ptr = strrchr(archive_handle->file_header->name, '.');
+ if (!name_ptr)
+ return EXIT_FAILURE;
+ name_ptr++;
/* Modify the subarchive handler based on the extension */
-#ifdef CONFIG_FEATURE_DEB_TAR_GZ
- if (strcmp(name_ptr, ".gz") == 0) {
- archive_handle->sub_archive->read = read;
+ if (ENABLE_FEATURE_SEAMLESS_GZ
+ && strcmp(name_ptr, "gz") == 0
+ ) {
archive_handle->action_data_subarchive = get_header_tar_gz;
- return(EXIT_SUCCESS);
+ return EXIT_SUCCESS;
+ }
+ if (ENABLE_FEATURE_SEAMLESS_BZ2
+ && strcmp(name_ptr, "bz2") == 0
+ ) {
+ archive_handle->action_data_subarchive = get_header_tar_bz2;
+ return EXIT_SUCCESS;
}
-#endif
-#ifdef CONFIG_FEATURE_DEB_TAR_BZ2
- if (strcmp(name_ptr, ".bz2") == 0) {
- archive_handle->sub_archive->read = read_bz2;
- BZ2_bzReadOpen(archive_handle->src_fd, NULL, 0);
- archive_handle->action_data_subarchive = get_header_tar;
- return(EXIT_SUCCESS);
+ if (ENABLE_FEATURE_SEAMLESS_LZMA
+ && strcmp(name_ptr, "lzma") == 0
+ ) {
+ archive_handle->action_data_subarchive = get_header_tar_lzma;
+ return EXIT_SUCCESS;
}
-#endif
}
- return(EXIT_FAILURE);
+ return EXIT_FAILURE;
}
diff --git a/release/src/router/busybox/archival/libunarchive/filter_accept_reject_list.c b/release/src/router/busybox/archival/libunarchive/filter_accept_reject_list.c
index 657f7a0b..aa601e13 100644
--- a/release/src/router/busybox/archival/libunarchive/filter_accept_reject_list.c
+++ b/release/src/router/busybox/archival/libunarchive/filter_accept_reject_list.c
@@ -1,45 +1,36 @@
+/* vi: set sw=4 ts=4: */
/*
- * Copyright (C) 2002 by Glenn McGrath
+ * Copyright (C) 2002 by Glenn McGrath
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <fnmatch.h>
-#include <stdlib.h>
-
+#include "libbb.h"
#include "unarchive.h"
/*
* Accept names that are in the accept list and not in the reject list
*/
-extern char filter_accept_reject_list(archive_handle_t *archive_handle)
+char FAST_FUNC filter_accept_reject_list(archive_handle_t *archive_handle)
{
- const char *key = archive_handle->file_header->name;
- const llist_t *accept_entry = find_list_entry(archive_handle->accept, key);
- const llist_t *reject_entry = find_list_entry(archive_handle->reject, key);
+ const char *key;
+ const llist_t *reject_entry;
+ const llist_t *accept_entry;
+
+ key = archive_handle->file_header->name;
/* If the key is in a reject list fail */
+ reject_entry = find_list_entry2(archive_handle->reject, key);
if (reject_entry) {
- return(EXIT_FAILURE);
+ return EXIT_FAILURE;
}
+ accept_entry = find_list_entry2(archive_handle->accept, key);
/* Fail if an accept list was specified and the key wasnt in there */
- if (archive_handle->accept && (accept_entry == NULL)) {
- return(EXIT_FAILURE);
+ if ((accept_entry == NULL) && archive_handle->accept) {
+ return EXIT_FAILURE;
}
/* Accepted */
- return(EXIT_SUCCESS);
+ return EXIT_SUCCESS;
}
diff --git a/release/src/router/busybox/archival/libunarchive/find_list_entry.c b/release/src/router/busybox/archival/libunarchive/find_list_entry.c
index 7ed9e332..bc7bc647 100644
--- a/release/src/router/busybox/archival/libunarchive/find_list_entry.c
+++ b/release/src/router/busybox/archival/libunarchive/find_list_entry.c
@@ -1,30 +1,54 @@
+/* vi: set sw=4 ts=4: */
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * Copyright (C) 2002 by Glenn McGrath
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
#include <fnmatch.h>
-#include <stdlib.h>
+#include "libbb.h"
#include "unarchive.h"
-extern const llist_t *find_list_entry(const llist_t *list, const char *filename)
+/* Find a string in a shell pattern list */
+const llist_t* FAST_FUNC find_list_entry(const llist_t *list, const char *filename)
{
while (list) {
if (fnmatch(list->data, filename, 0) == 0) {
- return(list);
+ return list;
+ }
+ list = list->link;
+ }
+ return NULL;
+}
+
+/* Same, but compares only path components present in pattern
+ * (extra trailing path components in filename are assumed to match)
+ */
+const llist_t* FAST_FUNC find_list_entry2(const llist_t *list, const char *filename)
+{
+ char buf[PATH_MAX];
+ int pattern_slash_cnt;
+ const char *c;
+ char *d;
+
+ while (list) {
+ c = list->data;
+ pattern_slash_cnt = 0;
+ while (*c)
+ if (*c++ == '/') pattern_slash_cnt++;
+ c = filename;
+ d = buf;
+ /* paranoia is better than buffer overflows */
+ while (*c && d != buf + sizeof(buf)-1) {
+ if (*c == '/' && --pattern_slash_cnt < 0)
+ break;
+ *d++ = *c++;
+ }
+ *d = '\0';
+ if (fnmatch(list->data, buf, 0) == 0) {
+ return list;
}
list = list->link;
}
- return(NULL);
+ return NULL;
}
diff --git a/release/src/router/busybox/archival/libunarchive/get_header_ar.c b/release/src/router/busybox/archival/libunarchive/get_header_ar.c
index 6c576a8d..d476a9d2 100644
--- a/release/src/router/busybox/archival/libunarchive/get_header_ar.c
+++ b/release/src/router/busybox/archival/libunarchive/get_header_ar.c
@@ -1,122 +1,127 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+/* vi: set sw=4 ts=4: */
+/* Copyright 2001 Glenn McGrath.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "unarchive.h"
#include "libbb.h"
+#include "unarchive.h"
-extern char get_header_ar(archive_handle_t *archive_handle)
+char FAST_FUNC get_header_ar(archive_handle_t *archive_handle)
{
+ int err;
file_header_t *typed = archive_handle->file_header;
union {
char raw[60];
- struct {
- char name[16];
- char date[12];
- char uid[6];
- char gid[6];
- char mode[8];
- char size[10];
- char magic[2];
- } formated;
+ struct {
+ char name[16];
+ char date[12];
+ char uid[6];
+ char gid[6];
+ char mode[8];
+ char size[10];
+ char magic[2];
+ } formatted;
} ar;
-#ifdef CONFIG_FEATURE_AR_LONG_FILENAMES
+#if ENABLE_FEATURE_AR_LONG_FILENAMES
static char *ar_long_names;
- static unsigned int ar_long_name_size;
+ static unsigned ar_long_name_size;
#endif
- /* dont use bb_xread as we want to handle the error ourself */
+ /* dont use xread as we want to handle the error ourself */
if (read(archive_handle->src_fd, ar.raw, 60) != 60) {
/* End Of File */
- return(EXIT_FAILURE);
- }
+ return EXIT_FAILURE;
+ }
- /* Some ar entries have a trailing '\n' after the previous data entry */
+ /* ar header starts on an even byte (2 byte aligned)
+ * '\n' is used for padding
+ */
if (ar.raw[0] == '\n') {
/* fix up the header, we started reading 1 byte too early */
memmove(ar.raw, &ar.raw[1], 59);
- ar.raw[59] = bb_xread_char(archive_handle->src_fd);
+ ar.raw[59] = xread_char(archive_handle->src_fd);
archive_handle->offset++;
}
archive_handle->offset += 60;
-
+
/* align the headers based on the header magic */
- if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) {
- bb_error_msg_and_die("Invalid ar header");
- }
+ if (ar.formatted.magic[0] != '`' || ar.formatted.magic[1] != '\n')
+ bb_error_msg_and_die("invalid ar header");
- typed->mode = strtol(ar.formated.mode, NULL, 8);
- typed->mtime = atoi(ar.formated.date);
- typed->uid = atoi(ar.formated.uid);
- typed->gid = atoi(ar.formated.gid);
- typed->size = atoi(ar.formated.size);
+ /* FIXME: more thorough routine would be in order here */
+ /* (we have something like that in tar) */
+ /* but for now we are lax. This code works because */
+ /* on misformatted numbers bb_strtou returns all-ones */
+ typed->mode = err = bb_strtou(ar.formatted.mode, NULL, 8);
+ if (err == -1) bb_error_msg_and_die("invalid ar header");
+ typed->mtime = err = bb_strtou(ar.formatted.date, NULL, 10);
+ if (err == -1) bb_error_msg_and_die("invalid ar header");
+ typed->uid = err = bb_strtou(ar.formatted.uid, NULL, 10);
+ if (err == -1) bb_error_msg_and_die("invalid ar header");
+ typed->gid = err = bb_strtou(ar.formatted.gid, NULL, 10);
+ if (err == -1) bb_error_msg_and_die("invalid ar header");
+ typed->size = err = bb_strtou(ar.formatted.size, NULL, 10);
+ if (err == -1) bb_error_msg_and_die("invalid ar header");
/* long filenames have '/' as the first character */
- if (ar.formated.name[0] == '/') {
-#ifdef CONFIG_FEATURE_AR_LONG_FILENAMES
- if (ar.formated.name[1] == '/') {
+ if (ar.formatted.name[0] == '/') {
+#if ENABLE_FEATURE_AR_LONG_FILENAMES
+ unsigned long_offset;
+
+ if (ar.formatted.name[1] == '/') {
/* If the second char is a '/' then this entries data section
* stores long filename for multiple entries, they are stored
* in static variable long_names for use in future entries */
ar_long_name_size = typed->size;
ar_long_names = xmalloc(ar_long_name_size);
- bb_xread_all(archive_handle->src_fd, ar_long_names, ar_long_name_size);
+ xread(archive_handle->src_fd, ar_long_names, ar_long_name_size);
archive_handle->offset += ar_long_name_size;
/* This ar entries data section only contained filenames for other records
* they are stored in the static ar_long_names for future reference */
- return (get_header_ar(archive_handle)); /* Return next header */
- } else if (ar.formated.name[1] == ' ') {
+ return get_header_ar(archive_handle); /* Return next header */
+ }
+
+ if (ar.formatted.name[1] == ' ') {
/* This is the index of symbols in the file for compilers */
data_skip(archive_handle);
- return (get_header_ar(archive_handle)); /* Return next header */
- } else {
- /* The number after the '/' indicates the offset in the ar data section
- (saved in variable long_name) that conatains the real filename */
- const unsigned int long_offset = atoi(&ar.formated.name[1]);
- if (long_offset >= ar_long_name_size) {
- bb_error_msg_and_die("Cant resolve long filename");
- }
- typed->name = bb_xstrdup(ar_long_names + long_offset);
+ archive_handle->offset += typed->size;
+ return get_header_ar(archive_handle); /* Return next header */
+ }
+
+ /* The number after the '/' indicates the offset in the ar data section
+ * (saved in variable long_name) that conatains the real filename */
+ long_offset = atoi(&ar.formatted.name[1]);
+ if (long_offset >= ar_long_name_size) {
+ bb_error_msg_and_die("can't resolve long filename");
}
+ typed->name = xstrdup(ar_long_names + long_offset);
#else
bb_error_msg_and_die("long filenames not supported");
#endif
} else {
/* short filenames */
- typed->name = bb_xstrndup(ar.formated.name, 16);
+ typed->name = xstrndup(ar.formatted.name, 16);
}
typed->name[strcspn(typed->name, " /")] = '\0';
if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
archive_handle->action_header(typed);
+#if ENABLE_DPKG || ENABLE_DPKG_DEB
if (archive_handle->sub_archive) {
- while (archive_handle->action_data_subarchive(archive_handle->sub_archive) == EXIT_SUCCESS);
- } else {
+ while (archive_handle->action_data_subarchive(archive_handle->sub_archive) == EXIT_SUCCESS)
+ continue;
+ } else
+#endif
archive_handle->action_data(archive_handle);
- }
} else {
- data_skip(archive_handle);
+ data_skip(archive_handle);
}
- archive_handle->offset += typed->size + 1;
+ archive_handle->offset += typed->size;
+ /* Set the file pointer to the correct spot, we may have been reading a compressed file */
+ lseek(archive_handle->src_fd, archive_handle->offset, SEEK_SET);
- return(EXIT_SUCCESS);
+ return EXIT_SUCCESS;
}
-
diff --git a/release/src/router/busybox/archival/libunarchive/get_header_cpio.c b/release/src/router/busybox/archival/libunarchive/get_header_cpio.c
index 975e2a4b..302f1223 100644
--- a/release/src/router/busybox/archival/libunarchive/get_header_cpio.c
+++ b/release/src/router/busybox/archival/libunarchive/get_header_cpio.c
@@ -1,189 +1,182 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+/* vi: set sw=4 ts=4: */
+/* Copyright 2002 Laurence Anderson
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "unarchive.h"
#include "libbb.h"
+#include "unarchive.h"
-typedef struct hardlinks_s {
- file_header_t *entry;
- int inode;
- struct hardlinks_s *next;
+typedef struct hardlinks_t {
+ struct hardlinks_t *next;
+ int inode; /* TODO: must match maj/min too! */
+ int mode ;
+ int mtime; /* These three are useful only in corner case */
+ int uid ; /* of hardlinks with zero size body */
+ int gid ;
+ char name[1];
} hardlinks_t;
-extern char get_header_cpio(archive_handle_t *archive_handle)
+char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle)
{
- static hardlinks_t *saved_hardlinks = NULL;
- static unsigned short pending_hardlinks = 0;
file_header_t *file_header = archive_handle->file_header;
char cpio_header[110];
int namesize;
- char dummy[16];
- int major, minor, nlink, inode;
- char extract_flag;
-
- if (pending_hardlinks) { /* Deal with any pending hardlinks */
- hardlinks_t *tmp;
- hardlinks_t *oldtmp;
-
- tmp = saved_hardlinks;
- oldtmp = NULL;
-
- while (tmp) {
- bb_error_msg_and_die("need to fix this\n");
- if (tmp->entry->link_name) { /* Found a hardlink ready to be extracted */
- file_header = tmp->entry;
- if (oldtmp) {
- oldtmp->next = tmp->next; /* Remove item from linked list */
- } else {
- saved_hardlinks = tmp->next;
- }
- free(tmp);
- continue;
- }
- oldtmp = tmp;
- tmp = tmp->next;
- }
- pending_hardlinks = 0; /* No more pending hardlinks, read next file entry */
- }
+ int major, minor, nlink, mode, inode;
+ unsigned size, uid, gid, mtime;
+
+#define hardlinks_to_create (*(hardlinks_t **)(&archive_handle->ah_priv[0]))
+#define created_hardlinks (*(hardlinks_t **)(&archive_handle->ah_priv[1]))
+#define block_count (archive_handle->ah_priv[2])
+// if (!archive_handle->ah_priv_inited) {
+// archive_handle->ah_priv_inited = 1;
+// hardlinks_to_create = NULL;
+// created_hardlinks = NULL;
+// }
/* There can be padding before archive header */
data_align(archive_handle, 4);
- if (archive_xread_all_eof(archive_handle, cpio_header, 110) == 0) {
- return(EXIT_FAILURE);
+ size = full_read(archive_handle->src_fd, cpio_header, 110);
+ if (size == 0) {
+ goto create_hardlinks;
}
- archive_handle->offset += 110;
-
- if (strncmp(&cpio_header[0], "07070", 5) != 0) {
- printf("cpio header is %x-%x-%x-%x-%x\n",
- cpio_header[0],
- cpio_header[1],
- cpio_header[2],
- cpio_header[3],
- cpio_header[4]);
- bb_error_msg_and_die("Unsupported cpio format");
- }
-
- if ((cpio_header[5] != '1') && (cpio_header[5] != '2')) {
- bb_error_msg_and_die("Unsupported cpio format, use newc or crc");
+ if (size != 110) {
+ bb_error_msg_and_die("short read");
}
+ archive_handle->offset += 110;
- {
- unsigned long tmpsize;
- sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c",
- dummy, &inode, (unsigned int*)&file_header->mode,
- (unsigned int*)&file_header->uid, (unsigned int*)&file_header->gid,
- &nlink, &file_header->mtime, &tmpsize,
- dummy, &major, &minor, &namesize, dummy);
- file_header->size = tmpsize;
+ if (strncmp(&cpio_header[0], "07070", 5) != 0
+ || (cpio_header[5] != '1' && cpio_header[5] != '2')
+ ) {
+ bb_error_msg_and_die("unsupported cpio format, use newc or crc");
}
- file_header->name = (char *) xmalloc(namesize + 1);
- archive_xread_all(archive_handle, file_header->name, namesize); /* Read in filename */
- file_header->name[namesize] = '\0';
+ if (sscanf(cpio_header + 6,
+ "%8x" "%8x" "%8x" "%8x"
+ "%8x" "%8x" "%8x" /*maj,min:*/ "%*16c"
+ /*rmaj,rmin:*/"%8x" "%8x" "%8x" /*chksum: "%*8c"*/,
+ &inode, &mode, &uid, &gid,
+ &nlink, &mtime, &size,
+ &major, &minor, &namesize) != 10)
+ bb_error_msg_and_die("damaged cpio file");
+ file_header->mode = mode;
+ file_header->uid = uid;
+ file_header->gid = gid;
+ file_header->mtime = mtime;
+ file_header->size = size;
+
+ namesize &= 0x1fff; /* paranoia: limit names to 8k chars */
+ file_header->name = xzalloc(namesize + 1);
+ /* Read in filename */
+ xread(archive_handle->src_fd, file_header->name, namesize);
archive_handle->offset += namesize;
/* Update offset amount and skip padding before file contents */
data_align(archive_handle, 4);
if (strcmp(file_header->name, "TRAILER!!!") == 0) {
- printf("%d blocks\n", (int) (archive_handle->offset % 512 ? (archive_handle->offset / 512) + 1 : archive_handle->offset / 512)); /* Always round up */
- if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */
- hardlinks_t *tmp = saved_hardlinks;
- hardlinks_t *oldtmp = NULL;
- while (tmp) {
- bb_error_msg("%s not created: cannot resolve hardlink", tmp->entry->name);
- oldtmp = tmp;
- tmp = tmp->next;
- free (oldtmp->entry->name);
- free (oldtmp->entry);
- free (oldtmp);
- }
- saved_hardlinks = NULL;
- pending_hardlinks = 0;
- }
- return(EXIT_FAILURE);
+ /* Always round up. ">> 9" divides by 512 */
+ block_count = (void*)(ptrdiff_t) ((archive_handle->offset + 511) >> 9);
+ goto create_hardlinks;
}
+ file_header->link_target = NULL;
if (S_ISLNK(file_header->mode)) {
- file_header->link_name = (char *) xmalloc(file_header->size + 1);
- archive_xread_all(archive_handle, file_header->link_name, file_header->size);
- file_header->link_name[file_header->size] = '\0';
+ file_header->size &= 0x1fff; /* paranoia: limit names to 8k chars */
+ file_header->link_target = xzalloc(file_header->size + 1);
+ xread(archive_handle->src_fd, file_header->link_target, file_header->size);
archive_handle->offset += file_header->size;
file_header->size = 0; /* Stop possible seeks in future */
}
- if (nlink > 1 && !S_ISDIR(file_header->mode)) {
- if (file_header->size == 0) { /* Put file on a linked list for later */
- hardlinks_t *new = xmalloc(sizeof(hardlinks_t));
- new->next = saved_hardlinks;
- new->inode = inode;
- new->entry = file_header;
- saved_hardlinks = new;
- return(EXIT_SUCCESS); // Skip this one
- } else { /* Found the file with data in */
- hardlinks_t *tmp = saved_hardlinks;
- pending_hardlinks = 1;
- while (tmp) {
- if (tmp->inode == inode) {
- tmp->entry->link_name = bb_xstrdup(file_header->name);
- nlink--;
- }
- tmp = tmp->next;
- }
- if (nlink > 1) {
- bb_error_msg("error resolving hardlink: did you create the archive with GNU cpio 2.0-2.2?");
- }
- }
- }
- file_header->device = (major << 8) | minor;
- extract_flag = FALSE;
- if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
- struct stat statbuf;
-
- extract_flag = TRUE;
-
- /* Check if the file already exists */
- if (lstat (file_header->name, &statbuf) == 0) {
- if ((archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) || (statbuf.st_mtime < file_header->mtime)) {
- /* Remove file if flag set or its older than the file to be extracted */
- if (unlink(file_header->name) == -1) {
- bb_perror_msg_and_die("Couldnt remove old file");
- }
- } else {
- if (! archive_handle->flags & ARCHIVE_EXTRACT_QUIET) {
- bb_error_msg("%s not created: newer or same age file exists", file_header->name);
- }
- extract_flag = FALSE;
- }
+// TODO: data_extract_all can't deal with hardlinks to non-files...
+// when fixed, change S_ISREG to !S_ISDIR here
+
+ if (nlink > 1 && S_ISREG(file_header->mode)) {
+ hardlinks_t *new = xmalloc(sizeof(*new) + namesize);
+ new->inode = inode;
+ new->mode = mode ;
+ new->mtime = mtime;
+ new->uid = uid ;
+ new->gid = gid ;
+ strcpy(new->name, file_header->name);
+ /* Put file on a linked list for later */
+ if (size == 0) {
+ new->next = hardlinks_to_create;
+ hardlinks_to_create = new;
+ return EXIT_SUCCESS; /* Skip this one */
+ /* TODO: this breaks cpio -t (it does not show hardlinks) */
}
- archive_handle->action_header(file_header);
+ new->next = created_hardlinks;
+ created_hardlinks = new;
}
+ file_header->device = makedev(major, minor);
- archive_handle->action_header(file_header);
- if (extract_flag) {
+ if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
archive_handle->action_data(archive_handle);
+ archive_handle->action_header(file_header);
} else {
data_skip(archive_handle);
}
+
archive_handle->offset += file_header->size;
- return (EXIT_SUCCESS);
-}
+ free(file_header->link_target);
+ free(file_header->name);
+ file_header->link_target = NULL;
+ file_header->name = NULL;
+
+ return EXIT_SUCCESS;
+
+ create_hardlinks:
+ free(file_header->link_target);
+ free(file_header->name);
+
+ while (hardlinks_to_create) {
+ hardlinks_t *cur;
+ hardlinks_t *make_me = hardlinks_to_create;
+
+ hardlinks_to_create = make_me->next;
+
+ memset(file_header, 0, sizeof(*file_header));
+ file_header->mtime = make_me->mtime;
+ file_header->name = make_me->name;
+ file_header->mode = make_me->mode;
+ file_header->uid = make_me->uid;
+ file_header->gid = make_me->gid;
+ /*file_header->size = 0;*/
+ /*file_header->link_target = NULL;*/
+
+ /* Try to find a file we are hardlinked to */
+ cur = created_hardlinks;
+ while (cur) {
+ /* TODO: must match maj/min too! */
+ if (cur->inode == make_me->inode) {
+ file_header->link_target = cur->name;
+ /* link_target != NULL, size = 0: "I am a hardlink" */
+ if (archive_handle->filter(archive_handle) == EXIT_SUCCESS)
+ archive_handle->action_data(archive_handle);
+ free(make_me);
+ goto next_link;
+ }
+ cur = cur->next;
+ }
+ /* Oops... no file with such inode was created... do it now
+ * (happens when hardlinked files are empty (zero length)) */
+ if (archive_handle->filter(archive_handle) == EXIT_SUCCESS)
+ archive_handle->action_data(archive_handle);
+ /* Move to the list of created hardlinked files */
+ make_me->next = created_hardlinks;
+ created_hardlinks = make_me;
+ next_link: ;
+ }
+
+ while (created_hardlinks) {
+ hardlinks_t *p = created_hardlinks;
+ created_hardlinks = p->next;
+ free(p);
+ }
+
+ return EXIT_FAILURE; /* "No more files to process" */
+}
diff --git a/release/src/router/busybox/archival/libunarchive/get_header_tar.c b/release/src/router/busybox/archival/libunarchive/get_header_tar.c
index 33cb75df..443052f7 100644
--- a/release/src/router/busybox/archival/libunarchive/get_header_tar.c
+++ b/release/src/router/busybox/archival/libunarchive/get_header_tar.c
@@ -1,188 +1,449 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+/* vi: set sw=4 ts=4: */
+/* Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
+ * FIXME:
+ * In privileged mode if uname and gname map to a uid and gid then use the
+ * mapped value instead of the uid/gid values in tar header
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * References:
+ * GNU tar and star man pages,
+ * Opengroup's ustar interchange format,
+ * http://www.opengroup.org/onlinepubs/007904975/utilities/pax.html
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "unarchive.h"
#include "libbb.h"
+#include "unarchive.h"
+
+/*
+ * GNU tar uses "base-256 encoding" for very large numbers (>8 billion).
+ * Encoding is binary, with highest bit always set as a marker
+ * and sign in next-highest bit:
+ * 80 00 .. 00 - zero
+ * bf ff .. ff - largest positive number
+ * ff ff .. ff - minus 1
+ * c0 00 .. 00 - smallest negative number
+ *
+ * We expect it only in size field, where negative numbers don't make sense.
+ */
+static off_t getBase256_len12(const char *str)
+{
+ off_t value;
+ int len;
+
+ /* if (*str & 0x40) error; - caller prevents this */
-#ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS
-static char *longname = NULL;
-static char *linkname = NULL;
+ if (sizeof(off_t) >= 12) {
+ /* Probably 128-bit (16 byte) off_t. Can be optimized. */
+ len = 12;
+ value = *str++ & 0x3f;
+ while (--len)
+ value = (value << 8) + (unsigned char) *str++;
+ return value;
+ }
+
+#ifdef CHECK_FOR_OVERFLOW
+ /* Can be optimized to eat 32-bit chunks */
+ char c = *str++ & 0x3f;
+ len = 12;
+ while (1) {
+ if (c)
+ bb_error_msg_and_die("overflow in base-256 encoded file size");
+ if (--len == sizeof(off_t))
+ break;
+ c = *str++;
+ }
+#else
+ str += (12 - sizeof(off_t));
#endif
-extern char get_header_tar(archive_handle_t *archive_handle)
+/* Now str points to sizeof(off_t) least significant bytes.
+ *
+ * Example of tar file with 8914993153 (0x213600001) byte file.
+ * Field starts at offset 7c:
+ * 00070 30 30 30 00 30 30 30 30 30 30 30 00 80 00 00 00 |000.0000000.....|
+ * 00080 00 00 00 02 13 60 00 01 31 31 31 32 30 33 33 36 |.....`..11120336|
+ *
+ * str is at offset 80 or 84 now (64-bit or 32-bit off_t).
+ * We (ab)use the fact that value happens to be aligned,
+ * and fetch it in one go:
+ */
+ if (sizeof(off_t) == 8) {
+ value = *(off_t*)str;
+ value = SWAP_BE64(value);
+ } else if (sizeof(off_t) == 4) {
+ value = *(off_t*)str;
+ value = SWAP_BE32(value);
+ } else {
+ value = 0;
+ len = sizeof(off_t);
+ while (--len)
+ value = (value << 8) + (unsigned char) *str++;
+ }
+ return value;
+}
+
+/* NB: _DESTROYS_ str[len] character! */
+static unsigned long long getOctal(char *str, int len)
+{
+ unsigned long long v;
+ /* NB: leading spaces are allowed. Using strtoull to handle that.
+ * The downside is that we accept e.g. "-123" too :)
+ */
+ str[len] = '\0';
+ v = strtoull(str, &str, 8);
+ if (*str && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY || *str != ' '))
+ bb_error_msg_and_die("corrupted octal value in tar header");
+ return v;
+}
+#define GET_OCTAL(a) getOctal((a), sizeof(a))
+
+void BUG_tar_header_size(void);
+char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
{
file_header_t *file_header = archive_handle->file_header;
- union {
- unsigned char raw[512];
- struct {
- char name[100]; /* 0-99 */
- char mode[8]; /* 100-107 */
- char uid[8]; /* 108-115 */
- char gid[8]; /* 116-123 */
- char size[12]; /* 124-135 */
- char mtime[12]; /* 136-147 */
- char chksum[8]; /* 148-155 */
- char typeflag; /* 156-156 */
- char linkname[100]; /* 157-256 */
- char magic[6]; /* 257-262 */
- char version[2]; /* 263-264 */
- char uname[32]; /* 265-296 */
- char gname[32]; /* 297-328 */
- char devmajor[8]; /* 329-336 */
- char devminor[8]; /* 337-344 */
- char prefix[155]; /* 345-499 */
- char padding[12]; /* 500-512 */
- } formated;
+ struct {
+ /* ustar header, Posix 1003.1 */
+ char name[100]; /* 0-99 */
+ char mode[8]; /* 100-107 */
+ char uid[8]; /* 108-115 */
+ char gid[8]; /* 116-123 */
+ char size[12]; /* 124-135 */
+ char mtime[12]; /* 136-147 */
+ char chksum[8]; /* 148-155 */
+ char typeflag; /* 156-156 */
+ char linkname[100]; /* 157-256 */
+ /* POSIX: "ustar" NUL "00" */
+ /* GNU tar: "ustar " NUL */
+ /* Normally it's defined as magic[6] followed by
+ * version[2], but we put them together to simplify code
+ */
+ char magic[8]; /* 257-264 */
+ char uname[32]; /* 265-296 */
+ char gname[32]; /* 297-328 */
+ char devmajor[8]; /* 329-336 */
+ char devminor[8]; /* 337-344 */
+ char prefix[155]; /* 345-499 */
+ char padding[12]; /* 500-512 */
} tar;
- long sum = 0;
- long i;
- char *tmp;
+ char *cp;
+ int i, sum_u, sum;
+#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
+ int sum_s;
+#endif
+ int parse_names;
+
+ /* Our "private data" */
+#define p_end (*(smallint *)(&archive_handle->ah_priv[0]))
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+#define p_longname (*(char* *)(&archive_handle->ah_priv[1]))
+#define p_linkname (*(char* *)(&archive_handle->ah_priv[2]))
+#else
+#define p_longname 0
+#define p_linkname 0
+#endif
+// if (!archive_handle->ah_priv_inited) {
+// archive_handle->ah_priv_inited = 1;
+// p_end = 0;
+// USE_FEATURE_TAR_GNU_EXTENSIONS(p_longname = NULL;)
+// USE_FEATURE_TAR_GNU_EXTENSIONS(p_linkname = NULL;)
+// }
+
+ if (sizeof(tar) != 512)
+ BUG_tar_header_size();
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+ again:
+#endif
/* Align header */
data_align(archive_handle, 512);
- if (archive_xread(archive_handle, tar.raw, 512) != 512) {
- /* Assume end of file */
- return(EXIT_FAILURE);
+ again_after_align:
+
+#if ENABLE_DESKTOP || ENABLE_FEATURE_TAR_AUTODETECT
+ /* to prevent misdetection of bz2 sig */
+ *(uint32_t*)(&tar) = 0;
+ i = full_read(archive_handle->src_fd, &tar, 512);
+ /* If GNU tar sees EOF in above read, it says:
+ * "tar: A lone zero block at N", where N = kilobyte
+ * where EOF was met (not EOF block, actual EOF!),
+ * and exits with EXIT_SUCCESS.
+ * We will mimic exit(EXIT_SUCCESS), although we will not mimic
+ * the message and we don't check whether we indeed
+ * saw zero block directly before this. */
+ if (i == 0) {
+ xfunc_error_retval = 0;
+ short_read:
+ bb_error_msg_and_die("short read");
}
- archive_handle->offset += 512;
+ if (i != 512) {
+ USE_FEATURE_TAR_AUTODETECT(goto autodetect;)
+ goto short_read;
+ }
+
+#else
+ i = 512;
+ xread(archive_handle->src_fd, &tar, i);
+#endif
+ archive_handle->offset += i;
/* If there is no filename its an empty header */
- if (tar.formated.name[0] == 0) {
- return(EXIT_SUCCESS);
+ if (tar.name[0] == 0 && tar.prefix[0] == 0) {
+ if (p_end) {
+ /* Second consecutive empty header - end of archive.
+ * Read until the end to empty the pipe from gz or bz2
+ */
+ while (full_read(archive_handle->src_fd, &tar, 512) == 512)
+ continue;
+ return EXIT_FAILURE;
+ }
+ p_end = 1;
+ return EXIT_SUCCESS;
}
+ p_end = 0;
- /* Check header has valid magic, "ustar" is for the proper tar
- * 0's are for the old tar format
- */
- if (strncmp(tar.formated.magic, "ustar", 5) != 0) {
-#ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY
- if (strncmp(tar.formated.magic, "\0\0\0\0\0", 5) != 0)
+ /* Check header has valid magic, "ustar" is for the proper tar,
+ * five NULs are for the old tar format */
+ if (strncmp(tar.magic, "ustar", 5) != 0
+ && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
+ || memcmp(tar.magic, "\0\0\0\0", 5) != 0)
+ ) {
+#if ENABLE_FEATURE_TAR_AUTODETECT
+ char FAST_FUNC (*get_header_ptr)(archive_handle_t *);
+
+ autodetect:
+ /* tar gz/bz autodetect: check for gz/bz2 magic.
+ * If we see the magic, and it is the very first block,
+ * we can switch to get_header_tar_gz/bz2/lzma().
+ * Needs seekable fd. I wish recv(MSG_PEEK) works
+ * on any fd... */
+#if ENABLE_FEATURE_SEAMLESS_GZ
+ if (tar.name[0] == 0x1f && tar.name[1] == (char)0x8b) { /* gzip */
+ get_header_ptr = get_header_tar_gz;
+ } else
#endif
- bb_error_msg_and_die("Invalid tar magic");
+#if ENABLE_FEATURE_SEAMLESS_BZ2
+ if (tar.name[0] == 'B' && tar.name[1] == 'Z'
+ && tar.name[2] == 'h' && isdigit(tar.name[3])
+ ) { /* bzip2 */
+ get_header_ptr = get_header_tar_bz2;
+ } else
+#endif
+ goto err;
+ /* Two different causes for lseek() != 0:
+ * unseekable fd (would like to support that too, but...),
+ * or not first block (false positive, it's not .gz/.bz2!) */
+ if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0)
+ goto err;
+ while (get_header_ptr(archive_handle) == EXIT_SUCCESS)
+ continue;
+ return EXIT_FAILURE;
+ err:
+#endif /* FEATURE_TAR_AUTODETECT */
+ bb_error_msg_and_die("invalid tar magic");
}
- /* Do checksum on headers */
- for (i = 0; i < 148 ; i++) {
- sum += tar.raw[i];
+
+ /* Do checksum on headers.
+ * POSIX says that checksum is done on unsigned bytes, but
+ * Sun and HP-UX gets it wrong... more details in
+ * GNU tar source. */
+#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
+ sum_s = ' ' * sizeof(tar.chksum);
+#endif
+ sum_u = ' ' * sizeof(tar.chksum);
+ for (i = 0; i < 148; i++) {
+ sum_u += ((unsigned char*)&tar)[i];
+#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
+ sum_s += ((signed char*)&tar)[i];
+#endif
}
- sum += ' ' * 8;
- for (i = 156; i < 512 ; i++) {
- sum += tar.raw[i];
+ for (i = 156; i < 512; i++) {
+ sum_u += ((unsigned char*)&tar)[i];
+#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
+ sum_s += ((signed char*)&tar)[i];
+#endif
}
- if (sum != strtol(tar.formated.chksum, NULL, 8)) {
- bb_error_msg("Invalid tar header checksum");
- return(EXIT_FAILURE);
+#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
+ sum = strtoul(tar.chksum, &cp, 8);
+ if ((*cp && *cp != ' ')
+ || (sum_u != sum USE_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum))
+ ) {
+ bb_error_msg_and_die("invalid tar header checksum");
}
+#else
+ /* This field does not need special treatment (getOctal) */
+ sum = xstrtoul(tar.chksum, 8);
+ if (sum_u != sum USE_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) {
+ bb_error_msg_and_die("invalid tar header checksum");
+ }
+#endif
-#ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS
- if (longname) {
- file_header->name = longname;
- longname = NULL;
+ /* 0 is reserved for high perf file, treat as normal file */
+ if (!tar.typeflag) tar.typeflag = '0';
+ parse_names = (tar.typeflag >= '0' && tar.typeflag <= '7');
+
+ /* getOctal trashes subsequent field, therefore we call it
+ * on fields in reverse order */
+ if (tar.devmajor[0]) {
+ char t = tar.prefix[0];
+ /* we trash prefix[0] here, but we DO need it later! */
+ unsigned minor = GET_OCTAL(tar.devminor);
+ unsigned major = GET_OCTAL(tar.devmajor);
+ file_header->device = makedev(major, minor);
+ tar.prefix[0] = t;
+ }
+ file_header->link_target = NULL;
+ if (!p_linkname && parse_names && tar.linkname[0]) {
+ file_header->link_target = xstrndup(tar.linkname, sizeof(tar.linkname));
+ /* FIXME: what if we have non-link object with link_target? */
+ /* Will link_target be free()ed? */
}
- else if (linkname) {
- file_header->name = linkname;
- linkname = NULL;
- } else
+#if ENABLE_FEATURE_TAR_UNAME_GNAME
+ file_header->uname = tar.uname[0] ? xstrndup(tar.uname, sizeof(tar.uname)) : NULL;
+ file_header->gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL;
#endif
- if (tar.formated.prefix[0] == 0) {
- file_header->name = strdup(tar.formated.name);
- } else {
- file_header->name = concat_path_file(tar.formated.prefix, tar.formated.name);
- }
- tmp = last_char_is(archive_handle->file_header->name, '/');
- if (tmp) {
- *tmp = '\0';
- }
-
- file_header->mode = strtol(tar.formated.mode, NULL, 8);
- file_header->uid = strtol(tar.formated.uid, NULL, 8);
- file_header->gid = strtol(tar.formated.gid, NULL, 8);
- file_header->size = strtol(tar.formated.size, NULL, 8);
- file_header->mtime = strtol(tar.formated.mtime, NULL, 8);
- file_header->link_name = (tar.formated.linkname[0] != '\0') ?
- bb_xstrdup(tar.formated.linkname) : NULL;
- file_header->device = (dev_t) ((strtol(tar.formated.devmajor, NULL, 8) << 8) +
- strtol(tar.formated.devminor, NULL, 8));
-
-#if defined CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY || defined CONFIG_FEATURE_TAR_GNU_EXTENSIONS
- /* Fix mode, used by the old format */
- switch (tar.formated.typeflag) {
-# ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY
- case 0:
+ file_header->mtime = GET_OCTAL(tar.mtime);
+ /* Size field: handle GNU tar's "base256 encoding" */
+ file_header->size = (*tar.size & 0xc0) == 0x80 /* positive base256? */
+ ? getBase256_len12(tar.size)
+ : GET_OCTAL(tar.size);
+ file_header->gid = GET_OCTAL(tar.gid);
+ file_header->uid = GET_OCTAL(tar.uid);
+ /* Set bits 0-11 of the files mode */
+ file_header->mode = 07777 & GET_OCTAL(tar.mode);
+
+ file_header->name = NULL;
+ if (!p_longname && parse_names) {
+ /* we trash mode[0] here, it's ok */
+ //tar.name[sizeof(tar.name)] = '\0'; - gcc 4.3.0 would complain
+ tar.mode[0] = '\0';
+ if (tar.prefix[0]) {
+ /* and padding[0] */
+ //tar.prefix[sizeof(tar.prefix)] = '\0'; - gcc 4.3.0 would complain
+ tar.padding[0] = '\0';
+ file_header->name = concat_path_file(tar.prefix, tar.name);
+ } else
+ file_header->name = xstrdup(tar.name);
+ }
+
+ /* Set bits 12-15 of the files mode */
+ /* (typeflag was not trashed because chksum does not use getOctal) */
+ switch (tar.typeflag) {
+ /* busybox identifies hard links as being regular files with 0 size and a link name */
+ case '1':
+ file_header->mode |= S_IFREG;
+ break;
+ case '7':
+ /* case 0: */
case '0':
+#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
+ if (last_char_is(file_header->name, '/')) {
+ goto set_dir;
+ }
+#endif
file_header->mode |= S_IFREG;
break;
- case '1':
- bb_error_msg("WARNING: Converting hard link to symlink");
case '2':
file_header->mode |= S_IFLNK;
+ /* have seen tarballs with size field containing
+ * the size of the link target's name */
+ size0:
+ file_header->size = 0;
break;
case '3':
file_header->mode |= S_IFCHR;
- break;
+ goto size0; /* paranoia */
case '4':
file_header->mode |= S_IFBLK;
- break;
+ goto size0;
case '5':
+ USE_FEATURE_TAR_OLDGNU_COMPATIBILITY(set_dir:)
file_header->mode |= S_IFDIR;
- break;
+ goto size0;
case '6':
file_header->mode |= S_IFIFO;
- break;
-# endif
-# ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS
- case 'L': {
- longname = xmalloc(file_header->size + 1);
- archive_xread_all(archive_handle, longname, file_header->size);
- longname[file_header->size] = '\0';
- archive_handle->offset += file_header->size;
-
- return(get_header_tar(archive_handle));
- }
- case 'K': {
- linkname = xmalloc(file_header->size + 1);
- archive_xread_all(archive_handle, linkname, file_header->size);
- linkname[file_header->size] = '\0';
- archive_handle->offset += file_header->size;
-
- file_header->name = linkname;
- return(get_header_tar(archive_handle));
- }
- case 'D':
- case 'M':
- case 'N':
- case 'S':
- case 'V':
- bb_error_msg("Ignoring GNU extension type %c", tar.formated.typeflag);
-# endif
+ goto size0;
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+ case 'L':
+ /* free: paranoia: tar with several consecutive longnames */
+ free(p_longname);
+ /* For paranoia reasons we allocate extra NUL char */
+ p_longname = xzalloc(file_header->size + 1);
+ /* We read ASCIZ string, including NUL */
+ xread(archive_handle->src_fd, p_longname, file_header->size);
+ archive_handle->offset += file_header->size;
+ /* return get_header_tar(archive_handle); */
+ /* gcc 4.1.1 didn't optimize it into jump */
+ /* so we will do it ourself, this also saves stack */
+ goto again;
+ case 'K':
+ free(p_linkname);
+ p_linkname = xzalloc(file_header->size + 1);
+ xread(archive_handle->src_fd, p_linkname, file_header->size);
+ archive_handle->offset += file_header->size;
+ /* return get_header_tar(archive_handle); */
+ goto again;
+ case 'D': /* GNU dump dir */
+ case 'M': /* Continuation of multi volume archive */
+ case 'N': /* Old GNU for names > 100 characters */
+ case 'S': /* Sparse file */
+ case 'V': /* Volume header */
+#endif
+ case 'g': /* pax global header */
+ case 'x': { /* pax extended header */
+ off_t sz;
+ bb_error_msg("warning: skipping header '%c'", tar.typeflag);
+ sz = (file_header->size + 511) & ~(off_t)511;
+ archive_handle->offset += sz;
+ sz >>= 9; /* sz /= 512 but w/o contortions for signed div */
+ while (sz--)
+ xread(archive_handle->src_fd, &tar, 512);
+ /* return get_header_tar(archive_handle); */
+ goto again_after_align;
+ }
+ default:
+ bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag);
+ }
+
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+ if (p_longname) {
+ file_header->name = p_longname;
+ p_longname = NULL;
+ }
+ if (p_linkname) {
+ file_header->link_target = p_linkname;
+ p_linkname = NULL;
}
#endif
+ if (strncmp(file_header->name, "/../"+1, 3) == 0
+ || strstr(file_header->name, "/../")
+ ) {
+ bb_error_msg_and_die("name with '..' encountered: '%s'",
+ file_header->name);
+ }
+
+ /* Strip trailing '/' in directories */
+ /* Must be done after mode is set as '/' is used to check if it's a directory */
+ cp = last_char_is(file_header->name, '/');
+
if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
- archive_handle->action_header(archive_handle->file_header);
- archive_handle->flags |= ARCHIVE_EXTRACT_QUIET;
+ archive_handle->action_header(/*archive_handle->*/ file_header);
+ /* Note that we kill the '/' only after action_header() */
+ /* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */
+ if (cp) *cp = '\0';
+ archive_handle->ah_flags |= ARCHIVE_EXTRACT_QUIET;
archive_handle->action_data(archive_handle);
- archive_handle->passed = llist_add_to(archive_handle->passed, archive_handle->file_header->name);
+ llist_add_to(&(archive_handle->passed), file_header->name);
} else {
- data_skip(archive_handle);
+ data_skip(archive_handle);
+ free(file_header->name);
}
archive_handle->offset += file_header->size;
- return(EXIT_SUCCESS);
+ free(file_header->link_target);
+ /* Do not free(file_header->name)! (why?) */
+#if ENABLE_FEATURE_TAR_UNAME_GNAME
+ free(file_header->uname);
+ free(file_header->gname);
+#endif
+ return EXIT_SUCCESS;
}
-
diff --git a/release/src/router/busybox/archival/libunarchive/get_header_tar_bz2.c b/release/src/router/busybox/archival/libunarchive/get_header_tar_bz2.c
index b49ccae1..615bbba4 100644
--- a/release/src/router/busybox/archival/libunarchive/get_header_tar_bz2.c
+++ b/release/src/router/busybox/archival/libunarchive/get_header_tar_bz2.c
@@ -1,42 +1,21 @@
+/* vi: set sw=4 ts=4: */
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <sys/types.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
#include "libbb.h"
#include "unarchive.h"
-extern char get_header_tar_bz2(archive_handle_t *archive_handle)
+char FAST_FUNC get_header_tar_bz2(archive_handle_t *archive_handle)
{
- BZ2_bzReadOpen(archive_handle->src_fd, NULL, 0);
-
- archive_handle->read = read_bz2;
- archive_handle->seek = seek_by_char;
+ /* Can't lseek over pipes */
+ archive_handle->seek = seek_by_read;
+ open_transformer(archive_handle->src_fd, unpack_bz2_stream_prime, "bunzip2");
archive_handle->offset = 0;
- while (get_header_tar(archive_handle) == EXIT_SUCCESS);
+ while (get_header_tar(archive_handle) == EXIT_SUCCESS)
+ continue;
- /* Cleanup */
- BZ2_bzReadClose();
-
- /* Can only do one tar.bz2 per archive */
- return(EXIT_FAILURE);
+ /* Can only do one file at a time */
+ return EXIT_FAILURE;
}
-
diff --git a/release/src/router/busybox/archival/libunarchive/get_header_tar_gz.c b/release/src/router/busybox/archival/libunarchive/get_header_tar_gz.c
index 7792432a..e88b720a 100644
--- a/release/src/router/busybox/archival/libunarchive/get_header_tar_gz.c
+++ b/release/src/router/busybox/archival/libunarchive/get_header_tar_gz.c
@@ -1,49 +1,36 @@
+/* vi: set sw=4 ts=4: */
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdlib.h>
-
#include "libbb.h"
#include "unarchive.h"
-extern char get_header_tar_gz(archive_handle_t *archive_handle)
+char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle)
{
+#if BB_MMU
unsigned char magic[2];
+#endif
+
+ /* Can't lseek over pipes */
+ archive_handle->seek = seek_by_read;
- archive_xread_all(archive_handle, &magic, 2);
+ /* Check gzip magic only if open_transformer will invoke unpack_gz_stream (MMU case).
+ * Otherwise, it will invoke an external helper "gunzip -cf" (NOMMU case) which will
+ * need the header. */
+#if BB_MMU
+ xread(archive_handle->src_fd, &magic, 2);
+ /* Can skip this check, but error message will be less clear */
if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) {
- bb_error_msg_and_die("Invalid gzip magic");
+ bb_error_msg_and_die("invalid gzip magic");
}
+#endif
- check_header_gzip(archive_handle->src_fd);
-
- GZ_gzReadOpen(archive_handle->src_fd, 0, 0);
-
- archive_handle->read = read_gz;
- archive_handle->seek = seek_by_char;
-
+ open_transformer(archive_handle->src_fd, unpack_gz_stream, "gunzip");
archive_handle->offset = 0;
- while (get_header_tar(archive_handle) == EXIT_SUCCESS);
-
- /* Cleanup */
- GZ_gzReadClose();
+ while (get_header_tar(archive_handle) == EXIT_SUCCESS)
+ continue;
- check_trailer_gzip(archive_handle->src_fd);
-
- /* Can only do one tar.bz2 per archive */
- return(EXIT_FAILURE);
+ /* Can only do one file at a time */
+ return EXIT_FAILURE;
}
-
diff --git a/release/src/router/busybox/archival/libunarchive/get_header_tar_lzma.c b/release/src/router/busybox/archival/libunarchive/get_header_tar_lzma.c
new file mode 100644
index 00000000..03b1b792
--- /dev/null
+++ b/release/src/router/busybox/archival/libunarchive/get_header_tar_lzma.c
@@ -0,0 +1,24 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Small lzma deflate implementation.
+ * Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
+ *
+ * Licensed under GPL v2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+char FAST_FUNC get_header_tar_lzma(archive_handle_t *archive_handle)
+{
+ /* Can't lseek over pipes */
+ archive_handle->seek = seek_by_read;
+
+ open_transformer(archive_handle->src_fd, unpack_lzma_stream, "unlzma");
+ archive_handle->offset = 0;
+ while (get_header_tar(archive_handle) == EXIT_SUCCESS)
+ continue;
+
+ /* Can only do one file at a time */
+ return EXIT_FAILURE;
+}
diff --git a/release/src/router/busybox/archival/libunarchive/header_list.c b/release/src/router/busybox/archival/libunarchive/header_list.c
index 5849a762..6ec2df36 100644
--- a/release/src/router/busybox/archival/libunarchive/header_list.c
+++ b/release/src/router/busybox/archival/libunarchive/header_list.c
@@ -1,7 +1,11 @@
-#include <stdio.h>
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
#include "unarchive.h"
-extern void header_list(const file_header_t *file_header)
+void FAST_FUNC header_list(const file_header_t *file_header)
{
puts(file_header->name);
}
diff --git a/release/src/router/busybox/archival/libunarchive/header_skip.c b/release/src/router/busybox/archival/libunarchive/header_skip.c
index 4430178f..a97a9ce8 100644
--- a/release/src/router/busybox/archival/libunarchive/header_skip.c
+++ b/release/src/router/busybox/archival/libunarchive/header_skip.c
@@ -1,7 +1,10 @@
-#include <stdio.h>
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
#include "unarchive.h"
-extern void header_skip(const file_header_t *file_header)
+void FAST_FUNC header_skip(const file_header_t *file_header UNUSED_PARAM)
{
- return;
}
diff --git a/release/src/router/busybox/archival/libunarchive/header_verbose_list.c b/release/src/router/busybox/archival/libunarchive/header_verbose_list.c
index 6739dd39..dc310036 100644
--- a/release/src/router/busybox/archival/libunarchive/header_verbose_list.c
+++ b/release/src/router/busybox/archival/libunarchive/header_verbose_list.c
@@ -1,18 +1,47 @@
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
#include "libbb.h"
#include "unarchive.h"
-extern void header_verbose_list(const file_header_t *file_header)
+void FAST_FUNC header_verbose_list(const file_header_t *file_header)
{
- struct tm *mtime = localtime(&file_header->mtime);
+ struct tm *mtime = localtime(&(file_header->mtime));
+
+#if ENABLE_FEATURE_TAR_UNAME_GNAME
+ char uid[8];
+ char gid[8];
+ char *user = file_header->uname;
+ char *group = file_header->gname;
- printf("%s %d/%d%10u %4u-%02u-%02u %02u:%02u:%02u %s",
+ if (user == NULL) {
+ snprintf(uid, sizeof(uid), "%u", (unsigned)file_header->uid);
+ user = uid;
+ }
+ if (group == NULL) {
+ snprintf(gid, sizeof(gid), "%u", (unsigned)file_header->gid);
+ group = gid;
+ }
+ printf("%s %s/%s %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s",
+ bb_mode_string(file_header->mode),
+ user,
+ group,
+ file_header->size,
+ 1900 + mtime->tm_year,
+ 1 + mtime->tm_mon,
+ mtime->tm_mday,
+ mtime->tm_hour,
+ mtime->tm_min,
+ mtime->tm_sec,
+ file_header->name);
+#else /* !FEATURE_TAR_UNAME_GNAME */
+ printf("%s %d/%d %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s",
bb_mode_string(file_header->mode),
file_header->uid,
file_header->gid,
- (unsigned int) file_header->size,
+ file_header->size,
1900 + mtime->tm_year,
1 + mtime->tm_mon,
mtime->tm_mday,
@@ -20,10 +49,10 @@ extern void header_verbose_list(const file_header_t *file_header)
mtime->tm_min,
mtime->tm_sec,
file_header->name);
+#endif /* FEATURE_TAR_UNAME_GNAME */
- if (file_header->link_name) {
- printf(" -> %s", file_header->link_name);
+ if (file_header->link_target) {
+ printf(" -> %s", file_header->link_target);
}
- /* putchar isnt used anywhere else i dont think */
- puts("");
+ bb_putchar('\n');
}
diff --git a/release/src/router/busybox/archival/libunarchive/init_handle.c b/release/src/router/busybox/archival/libunarchive/init_handle.c
index 2659aa3e..ff7d484e 100644
--- a/release/src/router/busybox/archival/libunarchive/init_handle.c
+++ b/release/src/router/busybox/archival/libunarchive/init_handle.c
@@ -1,37 +1,22 @@
+/* vi: set sw=4 ts=4: */
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <unistd.h>
-#include <string.h>
#include "libbb.h"
#include "unarchive.h"
-archive_handle_t *init_handle(void)
+archive_handle_t* FAST_FUNC init_handle(void)
{
archive_handle_t *archive_handle;
- /* Initialise default values */
- archive_handle = xmalloc(sizeof(archive_handle_t));
- memset(archive_handle, 0, sizeof(archive_handle_t));
- archive_handle->file_header = xmalloc(sizeof(file_header_t));
+ /* Initialize default values */
+ archive_handle = xzalloc(sizeof(archive_handle_t));
+ archive_handle->file_header = xzalloc(sizeof(file_header_t));
archive_handle->action_header = header_skip;
archive_handle->action_data = data_skip;
archive_handle->filter = filter_accept_all;
- archive_handle->read = bb_full_read;
archive_handle->seek = seek_by_jump;
- return(archive_handle);
+ return archive_handle;
}
diff --git a/release/src/router/busybox/archival/libunarchive/open_transformer.c b/release/src/router/busybox/archival/libunarchive/open_transformer.c
new file mode 100644
index 00000000..42fdd96a
--- /dev/null
+++ b/release/src/router/busybox/archival/libunarchive/open_transformer.c
@@ -0,0 +1,64 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+/* transformer(), more than meets the eye */
+/*
+ * On MMU machine, the transform_prog is removed by macro magic
+ * in include/unarchive.h. On NOMMU, transformer is removed.
+ */
+void FAST_FUNC open_transformer(int fd,
+ USE_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd),
+ const char *transform_prog)
+{
+ struct fd_pair fd_pipe;
+ int pid;
+
+ xpiped_pair(fd_pipe);
+
+#if BB_MMU
+ pid = fork();
+ if (pid == -1)
+ bb_perror_msg_and_die("vfork" + 1);
+#else
+ pid = vfork();
+ if (pid == -1)
+ bb_perror_msg_and_die("vfork");
+#endif
+
+ if (pid == 0) {
+ /* child process */
+ close(fd_pipe.rd); /* we don't want to read from the parent */
+ // FIXME: error check?
+#if BB_MMU
+ transformer(fd, fd_pipe.wr);
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ close(fd_pipe.wr); /* send EOF */
+ close(fd);
+ }
+ /* must be _exit! bug was actually seen here */
+ _exit(EXIT_SUCCESS);
+#else
+ {
+ char *argv[4];
+ xmove_fd(fd, 0);
+ xmove_fd(fd_pipe.wr, 1);
+ argv[0] = (char*)transform_prog;
+ argv[1] = (char*)"-cf";
+ argv[2] = (char*)"-";
+ argv[3] = NULL;
+ BB_EXECVP(transform_prog, argv);
+ bb_perror_msg_and_die("can't exec %s", transform_prog);
+ }
+#endif
+ /* notreached */
+ }
+
+ /* parent process */
+ close(fd_pipe.wr); /* don't want to write to the child */
+ xmove_fd(fd_pipe.rd, fd);
+}
diff --git a/release/src/router/busybox/archival/libunarchive/seek_by_char.c b/release/src/router/busybox/archival/libunarchive/seek_by_char.c
deleted file mode 100644
index f33935cb..00000000
--- a/release/src/router/busybox/archival/libunarchive/seek_by_char.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include "unarchive.h"
-
-extern void seek_by_char(const archive_handle_t *archive_handle, const unsigned int amount)
-{
- unsigned int i;
- for (i = 0; i < amount; i++) {
- archive_xread_char(archive_handle);
- }
-}
diff --git a/release/src/router/busybox/archival/libunarchive/seek_by_jump.c b/release/src/router/busybox/archival/libunarchive/seek_by_jump.c
index 578870d9..0a259c96 100644
--- a/release/src/router/busybox/archival/libunarchive/seek_by_jump.c
+++ b/release/src/router/busybox/archival/libunarchive/seek_by_jump.c
@@ -1,35 +1,19 @@
+/* vi: set sw=4 ts=4: */
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <sys/types.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-
#include "libbb.h"
#include "unarchive.h"
-extern void seek_by_jump(const archive_handle_t *archive_handle, const unsigned int amount)
+void FAST_FUNC seek_by_jump(const archive_handle_t *archive_handle, unsigned amount)
{
- if (lseek(archive_handle->src_fd, (off_t) amount, SEEK_CUR) == (off_t) -1) {
-#ifdef CONFIG_FEATURE_UNARCHIVE_TAPE
- if (errno == ESPIPE) {
- seek_by_char(archive_handle, amount);
- } else
-#endif
- bb_perror_msg_and_die("Seek failure");
+ if (amount
+ && lseek(archive_handle->src_fd, (off_t) amount, SEEK_CUR) == (off_t) -1
+ ) {
+ if (errno == ESPIPE)
+ seek_by_read(archive_handle, amount);
+ else
+ bb_perror_msg_and_die("seek failure");
}
}
diff --git a/release/src/router/busybox/archival/libunarchive/seek_by_read.c b/release/src/router/busybox/archival/libunarchive/seek_by_read.c
new file mode 100644
index 00000000..2326a751
--- /dev/null
+++ b/release/src/router/busybox/archival/libunarchive/seek_by_read.c
@@ -0,0 +1,16 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+/* If we are reading through a pipe, or from stdin then we can't lseek,
+ * we must read and discard the data to skip over it.
+ */
+void FAST_FUNC seek_by_read(const archive_handle_t *archive_handle, unsigned jump_size)
+{
+ if (jump_size)
+ bb_copyfd_exact_size(archive_handle->src_fd, -1, jump_size);
+}
diff --git a/release/src/router/busybox/archival/libunarchive/uncompress.c b/release/src/router/busybox/archival/libunarchive/uncompress.c
deleted file mode 100644
index 9851ca39..00000000
--- a/release/src/router/busybox/archival/libunarchive/uncompress.c
+++ /dev/null
@@ -1,298 +0,0 @@
-#include "config.h"
-#include "libbb.h"
-
-#if defined CONFIG_UNCOMPRESS || defined CONFIG_FEATURE_GUNZIP_UNCOMPRESS
-
-/* uncompress for busybox -- (c) 2002 Robert Griebl
- *
- * based on the original compress42.c source
- * (see disclaimer below)
- */
-
-
-/* (N)compress42.c - File compression ala IEEE Computer, Mar 1992.
- *
- * Authors:
- * Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
- * Jim McKie (decvax!mcvax!jim)
- * Steve Davies (decvax!vax135!petsd!peora!srd)
- * Ken Turkowski (decvax!decwrl!turtlevax!ken)
- * James A. Woods (decvax!ihnp4!ames!jaw)
- * Joe Orost (decvax!vax135!petsd!joe)
- * Dave Mack (csu@alembic.acs.com)
- * Peter Jannesen, Network Communication Systems
- * (peter@ncs.nl)
- *
- * marc@suse.de : a small security fix for a buffer overflow
- *
- * [... History snipped ...]
- *
- */
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-/* Defailt input buffer size */
-#define IBUFSIZ 2048
-
-/* Default output buffer size */
-#define OBUFSIZ 2048
-
-/* Defines for third byte of header */
-#define MAGIC_1 (char_type)'\037' /* First byte of compressed file */
-#define MAGIC_2 (char_type)'\235' /* Second byte of compressed file */
-#define BIT_MASK 0x1f /* Mask for 'number of compresssion bits' */
- /* Masks 0x20 and 0x40 are free. */
- /* I think 0x20 should mean that there is */
- /* a fourth header byte (for expansion). */
-#define BLOCK_MODE 0x80 /* Block compresssion if table is full and */
- /* compression rate is dropping flush tables */
- /* the next two codes should not be changed lightly, as they must not */
- /* lie within the contiguous general code space. */
-#define FIRST 257 /* first free entry */
-#define CLEAR 256 /* table clear output code */
-
-#define INIT_BITS 9 /* initial number of bits/code */
-
-
-/* machine variants which require cc -Dmachine: pdp11, z8000, DOS */
-#define FAST
-
-#define HBITS 17 /* 50% occupancy */
-#define HSIZE (1<<HBITS)
-#define HMASK (HSIZE-1)
-#define HPRIME 9941
-#define BITS 16
-#undef MAXSEG_64K
-#define MAXCODE(n) (1L << (n))
-
-/* Block compress mode -C compatible with 2.0 */
-int block_mode = BLOCK_MODE;
-
-/* user settable max # bits/code */
-int maxbits = BITS;
-
-/* Exitcode of compress (-1 no file compressed) */
-int exit_code = -1;
-
-/* Input buffer */
-unsigned char inbuf[IBUFSIZ + 64];
-
-/* Output buffer */
-unsigned char outbuf[OBUFSIZ + 2048];
-
-
-long int htab[HSIZE];
-unsigned short codetab[HSIZE];
-
-#define htabof(i) htab[i]
-#define codetabof(i) codetab[i]
-#define tab_prefixof(i) codetabof(i)
-#define tab_suffixof(i) ((unsigned char *)(htab))[i]
-#define de_stack ((unsigned char *)&(htab[HSIZE-1]))
-#define clear_htab() memset(htab, -1, sizeof(htab))
-#define clear_tab_prefixof() memset(codetab, 0, 256);
-
-
-/*
- * Decompress stdin to stdout. This routine adapts to the codes in the
- * file building the "string" table on-the-fly; requiring no table to
- * be stored in the compressed file. The tables used herein are shared
- * with those of the compress() routine. See the definitions above.
- */
-
-extern int uncompress(int fd_in, int fd_out)
-{
- unsigned char *stackp;
- long int code;
- int finchar;
- long int oldcode;
- long int incode;
- int inbits;
- int posbits;
- int outpos;
- int insize;
- int bitmask;
- long int free_ent;
- long int maxcode;
- long int maxmaxcode;
- int n_bits;
- int rsize = 0;
-
- insize = 0;
-
- inbuf[0] = bb_xread_char(fd_in);
-
- maxbits = inbuf[0] & BIT_MASK;
- block_mode = inbuf[0] & BLOCK_MODE;
- maxmaxcode = MAXCODE(maxbits);
-
- if (maxbits > BITS) {
- bb_error_msg("compressed with %d bits, can only handle %d bits", maxbits,
- BITS);
- return -1;
- }
-
- maxcode = MAXCODE(n_bits = INIT_BITS) - 1;
- bitmask = (1 << n_bits) - 1;
- oldcode = -1;
- finchar = 0;
- outpos = 0;
- posbits = 0 << 3;
-
- free_ent = ((block_mode) ? FIRST : 256);
-
- /* As above, initialize the first 256 entries in the table. */
- clear_tab_prefixof();
-
- for (code = 255; code >= 0; --code) {
- tab_suffixof(code) = (unsigned char) code;
- }
-
- do {
- resetbuf:;
- {
- int i;
- int e;
- int o;
-
- e = insize - (o = (posbits >> 3));
-
- for (i = 0; i < e; ++i)
- inbuf[i] = inbuf[i + o];
-
- insize = e;
- posbits = 0;
- }
-
- if (insize < (int) sizeof(inbuf) - IBUFSIZ) {
- rsize = read(fd_in, inbuf + insize, IBUFSIZ);
- insize += rsize;
- }
-
- inbits = ((rsize > 0) ? (insize - insize % n_bits) << 3 :
- (insize << 3) - (n_bits - 1));
-
- while (inbits > posbits) {
- if (free_ent > maxcode) {
- posbits =
- ((posbits - 1) +
- ((n_bits << 3) -
- (posbits - 1 + (n_bits << 3)) % (n_bits << 3)));
- ++n_bits;
- if (n_bits == maxbits) {
- maxcode = maxmaxcode;
- } else {
- maxcode = MAXCODE(n_bits) - 1;
- }
- bitmask = (1 << n_bits) - 1;
- goto resetbuf;
- }
- {
- unsigned char *p = &inbuf[posbits >> 3];
-
- code =
- ((((long) (p[0])) | ((long) (p[1]) << 8) |
- ((long) (p[2]) << 16)) >> (posbits & 0x7)) & bitmask;
- }
- posbits += n_bits;
-
-
- if (oldcode == -1) {
- outbuf[outpos++] = (unsigned char) (finchar =
- (int) (oldcode = code));
- continue;
- }
-
- if (code == CLEAR && block_mode) {
- clear_tab_prefixof();
- free_ent = FIRST - 1;
- posbits =
- ((posbits - 1) +
- ((n_bits << 3) -
- (posbits - 1 + (n_bits << 3)) % (n_bits << 3)));
- maxcode = MAXCODE(n_bits = INIT_BITS) - 1;
- bitmask = (1 << n_bits) - 1;
- goto resetbuf;
- }
-
- incode = code;
- stackp = de_stack;
-
- /* Special case for KwKwK string. */
- if (code >= free_ent) {
- if (code > free_ent) {
- unsigned char *p;
-
- posbits -= n_bits;
- p = &inbuf[posbits >> 3];
-
- bb_error_msg
- ("insize:%d posbits:%d inbuf:%02X %02X %02X %02X %02X (%d)",
- insize, posbits, p[-1], p[0], p[1], p[2], p[3],
- (posbits & 07));
- bb_error_msg("uncompress: corrupt input");
- return -1;
- }
-
- *--stackp = (unsigned char) finchar;
- code = oldcode;
- }
-
- /* Generate output characters in reverse order */
- while ((long int) code >= (long int) 256) {
- *--stackp = tab_suffixof(code);
- code = tab_prefixof(code);
- }
-
- *--stackp = (unsigned char) (finchar = tab_suffixof(code));
-
- /* And put them out in forward order */
- {
- int i;
-
- if (outpos + (i = (de_stack - stackp)) >= OBUFSIZ) {
- do {
- if (i > OBUFSIZ - outpos) {
- i = OBUFSIZ - outpos;
- }
-
- if (i > 0) {
- memcpy(outbuf + outpos, stackp, i);
- outpos += i;
- }
-
- if (outpos >= OBUFSIZ) {
- write(fd_out, outbuf, outpos);
- outpos = 0;
- }
- stackp += i;
- } while ((i = (de_stack - stackp)) > 0);
- } else {
- memcpy(outbuf + outpos, stackp, i);
- outpos += i;
- }
- }
-
- /* Generate the new entry. */
- if ((code = free_ent) < maxmaxcode) {
- tab_prefixof(code) = (unsigned short) oldcode;
- tab_suffixof(code) = (unsigned char) finchar;
- free_ent = code + 1;
- }
-
- /* Remember previous code. */
- oldcode = incode;
- }
-
- } while (rsize > 0);
-
- if (outpos > 0) {
- write(fd_out, outbuf, outpos);
- }
-
- return 0;
-}
-
-
-#endif
diff --git a/release/src/router/busybox/archival/libunarchive/unpack_ar_archive.c b/release/src/router/busybox/archival/libunarchive/unpack_ar_archive.c
index e8f113bc..dc2eec22 100644
--- a/release/src/router/busybox/archival/libunarchive/unpack_ar_archive.c
+++ b/release/src/router/busybox/archival/libunarchive/unpack_ar_archive.c
@@ -1,34 +1,21 @@
+/* vi: set sw=4 ts=4: */
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
+
+#include "libbb.h"
#include "unarchive.h"
-#include "busybox.h"
-extern void unpack_ar_archive(archive_handle_t *ar_archive)
+void FAST_FUNC unpack_ar_archive(archive_handle_t *ar_archive)
{
char magic[7];
- archive_xread_all(ar_archive, magic, 7);
+ xread(ar_archive->src_fd, magic, 7);
if (strncmp(magic, "!<arch>", 7) != 0) {
- bb_error_msg_and_die("Invalid ar magic");
+ bb_error_msg_and_die("invalid ar magic");
}
ar_archive->offset += 7;
- while (get_header_ar(ar_archive) == EXIT_SUCCESS);
+ while (get_header_ar(ar_archive) == EXIT_SUCCESS)
+ continue;
}
diff --git a/release/src/router/busybox/archival/libunarchive/unzip.c b/release/src/router/busybox/archival/libunarchive/unzip.c
deleted file mode 100644
index 2b16db3c..00000000
--- a/release/src/router/busybox/archival/libunarchive/unzip.c
+++ /dev/null
@@ -1,1040 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * gunzip implementation for busybox
- *
- * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
- *
- * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
- * based on gzip sources
- *
- * Adjusted further by Erik Andersen <andersen@codepoet.org> to support
- * files as well as stdin/stdout, and to generally behave itself wrt
- * command line handling.
- *
- * General cleanup to better adhere to the style guide and make use of standard
- * busybox functions by Glenn McGrath <bug1@optushome.com.au>
- *
- * read_gz interface + associated hacking by Laurence Anderson
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *
- * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * The unzip code was written and put in the public domain by Mark Adler.
- * Portions of the lzw code are derived from the public domain 'compress'
- * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
- * Ken Turkowski, Dave Mack and Peter Jannesen.
- *
- * See the license_msg below and the file COPYING for the software license.
- * See the file algorithm.doc for the compression algorithms and file formats.
- */
-
-#if 0
-static char *license_msg[] = {
- " Copyright (C) 1992-1993 Jean-loup Gailly",
- " This program is free software; you can redistribute it and/or modify",
- " it under the terms of the GNU General Public License as published by",
- " the Free Software Foundation; either version 2, or (at your option)",
- " any later version.",
- "",
- " This program is distributed in the hope that it will be useful,",
- " but WITHOUT ANY WARRANTY; without even the implied warranty of",
- " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the",
- " GNU General Public License for more details.",
- "",
- " You should have received a copy of the GNU General Public License",
- " along with this program; if not, write to the Free Software",
- " Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.",
- 0
-};
-#endif
-
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include "config.h"
-#include "busybox.h"
-#include "unarchive.h"
-
-typedef struct huft_s {
- unsigned char e; /* number of extra bits or operation */
- unsigned char b; /* number of bits in this code or subcode */
- union {
- unsigned short n; /* literal, length base, or distance base */
- struct huft_s *t; /* pointer to next level of table */
- } v;
-} huft_t;
-
-static int gunzip_src_fd;
-unsigned int gunzip_bytes_out; /* number of output bytes */
-static unsigned int gunzip_outbuf_count; /* bytes in output buffer */
-
-/* gunzip_window size--must be a power of two, and
- * at least 32K for zip's deflate method */
-static const int gunzip_wsize = 0x8000;
-static unsigned char *gunzip_window;
-
-static unsigned int *gunzip_crc_table;
-unsigned int gunzip_crc;
-
-/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
-#define BMAX 16 /* maximum bit length of any code (16 for explode) */
-#define N_MAX 288 /* maximum number of codes in any set */
-
-/* bitbuffer */
-static unsigned int gunzip_bb; /* bit buffer */
-static unsigned char gunzip_bk; /* bits in bit buffer */
-
-/* These control the size of the bytebuffer */
-#define BYTEBUFFER_MAX 0x8000
-static unsigned char *bytebuffer = NULL;
-static unsigned int bytebuffer_offset = 0;
-static unsigned int bytebuffer_size = 0;
-
-static const unsigned short mask_bits[] = {
- 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
- 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-};
-
-/* Copy lengths for literal codes 257..285 */
-static const unsigned short cplens[] = {
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
- 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
-};
-
-/* note: see note #13 above about the 258 in this list. */
-/* Extra bits for literal codes 257..285 */
-static const unsigned char cplext[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5,
- 5, 5, 5, 0, 99, 99
-}; /* 99==invalid */
-
-/* Copy offsets for distance codes 0..29 */
-static const unsigned short cpdist[] = {
- 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513,
- 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577
-};
-
-/* Extra bits for distance codes */
-static const unsigned char cpdext[] = {
- 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
- 11, 11, 12, 12, 13, 13
-};
-
-/* Tables for deflate from PKZIP's appnote.txt. */
-/* Order of the bit length code lengths */
-static const unsigned char border[] = {
- 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
-};
-
-static void fill_bytebuffer(void)
-{
- if (bytebuffer_offset >= bytebuffer_size) {
- /* Leave the first 4 bytes empty so we can always unwind the bitbuffer
- * to the front of the bytebuffer, leave 4 bytes free at end of tail
- * so we can easily top up buffer in check_trailer_gzip() */
- bytebuffer_size = 4 + bb_xread(gunzip_src_fd, &bytebuffer[4], BYTEBUFFER_MAX - 8);
- bytebuffer_offset = 4;
- }
-}
-
-static unsigned int fill_bitbuffer(unsigned int bitbuffer, unsigned int *current, const unsigned int required)
-{
- while (*current < required) {
- fill_bytebuffer();
- bitbuffer |= ((unsigned int) bytebuffer[bytebuffer_offset]) << *current;
- bytebuffer_offset++;
- *current += 8;
- }
- return(bitbuffer);
-}
-
-static void make_gunzip_crc_table(void)
-{
- const unsigned int poly = 0xedb88320; /* polynomial exclusive-or pattern */
- unsigned short i; /* counter for all possible eight bit values */
-
- /* initial shift register value */
- gunzip_crc = 0xffffffffL;
- gunzip_crc_table = (unsigned int *) malloc(256 * sizeof(unsigned int));
-
- /* Compute and print table of CRC's, five per line */
- for (i = 0; i < 256; i++) {
- unsigned int table_entry; /* crc shift register */
- unsigned char k; /* byte being shifted into crc apparatus */
-
- table_entry = i;
- /* The idea to initialize the register with the byte instead of
- * zero was stolen from Haruhiko Okumura's ar002
- */
- for (k = 8; k; k--) {
- if (table_entry & 1) {
- table_entry = (table_entry >> 1) ^ poly;
- } else {
- table_entry >>= 1;
- }
- }
- gunzip_crc_table[i] = table_entry;
- }
-}
-
-/*
- * Free the malloc'ed tables built by huft_build(), which makes a linked
- * list of the tables it made, with the links in a dummy first entry of
- * each table.
- * t: table to free
- */
-static int huft_free(huft_t * t)
-{
- huft_t *p;
- huft_t *q;
-
- /* Go through linked list, freeing from the malloced (t[-1]) address. */
- p = t;
- while (p != (huft_t *) NULL) {
- q = (--p)->v.t;
- free((char *) p);
- p = q;
- }
- return 0;
-}
-
-/* Given a list of code lengths and a maximum table size, make a set of
- * tables to decode that set of codes. Return zero on success, one if
- * the given code set is incomplete (the tables are still built in this
- * case), two if the input is invalid (all zero length codes or an
- * oversubscribed set of lengths), and three if not enough memory.
- *
- * b: code lengths in bits (all assumed <= BMAX)
- * n: number of codes (assumed <= N_MAX)
- * s: number of simple-valued codes (0..s-1)
- * d: list of base values for non-simple codes
- * e: list of extra bits for non-simple codes
- * t: result: starting table
- * m: maximum lookup bits, returns actual
- */
-static int huft_build(unsigned int *b, const unsigned int n,
- const unsigned int s, const unsigned short *d,
- const unsigned char *e, huft_t ** t, int *m)
-{
- unsigned a; /* counter for codes of length k */
- unsigned c[BMAX + 1]; /* bit length count table */
- unsigned f; /* i repeats in table every f entries */
- int g; /* maximum code length */
- int h; /* table level */
- register unsigned i; /* counter, current code */
- register unsigned j; /* counter */
- register int k; /* number of bits in current code */
- int l; /* bits per table (returned in m) */
- register unsigned *p; /* pointer into c[], b[], or v[] */
- register huft_t *q; /* points to current table */
- huft_t r; /* table entry for structure assignment */
- huft_t *u[BMAX]; /* table stack */
- unsigned v[N_MAX]; /* values in order of bit length */
- register int w; /* bits before this table == (l * h) */
- unsigned x[BMAX + 1]; /* bit offsets, then code stack */
- unsigned *xp; /* pointer into x */
- int y; /* number of dummy codes added */
- unsigned z; /* number of entries in current table */
-
- /* Generate counts for each bit length */
- memset((void *) (c), 0, sizeof(c));
- p = b;
- i = n;
- do {
- c[*p]++; /* assume all entries <= BMAX */
- p++; /* Can't combine with above line (Solaris bug) */
- } while (--i);
- if (c[0] == n) { /* null input--all zero length codes */
- *t = (huft_t *) NULL;
- *m = 0;
- return 0;
- }
-
- /* Find minimum and maximum length, bound *m by those */
- l = *m;
- for (j = 1; j <= BMAX; j++) {
- if (c[j]) {
- break;
- }
- }
- k = j; /* minimum code length */
- if ((unsigned) l < j) {
- l = j;
- }
- for (i = BMAX; i; i--) {
- if (c[i]) {
- break;
- }
- }
- g = i; /* maximum code length */
- if ((unsigned) l > i) {
- l = i;
- }
- *m = l;
-
- /* Adjust last length count to fill out codes, if needed */
- for (y = 1 << j; j < i; j++, y <<= 1) {
- if ((y -= c[j]) < 0) {
- return 2; /* bad input: more codes than bits */
- }
- }
- if ((y -= c[i]) < 0) {
- return 2;
- }
- c[i] += y;
-
- /* Generate starting offsets into the value table for each length */
- x[1] = j = 0;
- p = c + 1;
- xp = x + 2;
- while (--i) { /* note that i == g from above */
- *xp++ = (j += *p++);
- }
-
- /* Make a table of values in order of bit lengths */
- p = b;
- i = 0;
- do {
- if ((j = *p++) != 0) {
- v[x[j]++] = i;
- }
- } while (++i < n);
-
- /* Generate the Huffman codes and for each, make the table entries */
- x[0] = i = 0; /* first Huffman code is zero */
- p = v; /* grab values in bit order */
- h = -1; /* no tables yet--level -1 */
- w = -l; /* bits decoded == (l * h) */
- u[0] = (huft_t *) NULL; /* just to keep compilers happy */
- q = (huft_t *) NULL; /* ditto */
- z = 0; /* ditto */
-
- /* go through the bit lengths (k already is bits in shortest code) */
- for (; k <= g; k++) {
- a = c[k];
- while (a--) {
- /* here i is the Huffman code of length k bits for value *p */
- /* make tables up to required level */
- while (k > w + l) {
- h++;
- w += l; /* previous table always l bits */
-
- /* compute minimum size table less than or equal to l bits */
- z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */
- if ((f = 1 << (j = k - w)) > a + 1) { /* try a k-w bit table *//* too few codes for k-w bit table */
- f -= a + 1; /* deduct codes from patterns left */
- xp = c + k;
- while (++j < z) { /* try smaller tables up to z bits */
- if ((f <<= 1) <= *++xp) {
- break; /* enough codes to use up j bits */
- }
- f -= *xp; /* else deduct codes from patterns */
- }
- }
- z = 1 << j; /* table entries for j-bit table */
-
- /* allocate and link in new table */
- q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t));
-
- *t = q + 1; /* link to list for huft_free() */
- *(t = &(q->v.t)) = NULL;
- u[h] = ++q; /* table starts after link */
-
- /* connect to last table, if there is one */
- if (h) {
- x[h] = i; /* save pattern for backing up */
- r.b = (unsigned char) l; /* bits to dump before this table */
- r.e = (unsigned char) (16 + j); /* bits in this table */
- r.v.t = q; /* pointer to this table */
- j = i >> (w - l); /* (get around Turbo C bug) */
- u[h - 1][j] = r; /* connect to last table */
- }
- }
-
- /* set up table entry in r */
- r.b = (unsigned char) (k - w);
- if (p >= v + n) {
- r.e = 99; /* out of values--invalid code */
- } else if (*p < s) {
- r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */
- r.v.n = (unsigned short) (*p); /* simple code is just the value */
- p++; /* one compiler does not like *p++ */
- } else {
- r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */
- r.v.n = d[*p++ - s];
- }
-
- /* fill code-like entries with r */
- f = 1 << (k - w);
- for (j = i >> w; j < z; j += f) {
- q[j] = r;
- }
-
- /* backwards increment the k-bit code i */
- for (j = 1 << (k - 1); i & j; j >>= 1) {
- i ^= j;
- }
- i ^= j;
-
- /* backup over finished tables */
- while ((i & ((1 << w) - 1)) != x[h]) {
- h--; /* don't need to update q */
- w -= l;
- }
- }
- }
- /* Return true (1) if we were given an incomplete table */
- return y != 0 && g != 1;
-}
-
-/*
- * inflate (decompress) the codes in a deflated (compressed) block.
- * Return an error code or zero if it all goes ok.
- *
- * tl, td: literal/length and distance decoder tables
- * bl, bd: number of bits decoded by tl[] and td[]
- */
-static int inflate_codes(huft_t * my_tl, huft_t * my_td, const unsigned int my_bl, const unsigned int my_bd, int setup)
-{
- static unsigned int e; /* table entry flag/number of extra bits */
- static unsigned int n, d; /* length and index for copy */
- static unsigned int w; /* current gunzip_window position */
- static huft_t *t; /* pointer to table entry */
- static unsigned int ml, md; /* masks for bl and bd bits */
- static unsigned int b; /* bit buffer */
- static unsigned int k; /* number of bits in bit buffer */
- static huft_t *tl, *td;
- static unsigned int bl, bd;
- static int resumeCopy = 0;
-
- if (setup) { // 1st time we are called, copy in variables
- tl = my_tl;
- td = my_td;
- bl = my_bl;
- bd = my_bd;
- /* make local copies of globals */
- b = gunzip_bb; /* initialize bit buffer */
- k = gunzip_bk;
- w = gunzip_outbuf_count; /* initialize gunzip_window position */
-
- /* inflate the coded data */
- ml = mask_bits[bl]; /* precompute masks for speed */
- md = mask_bits[bd];
- return 0; // Don't actually do anything the first time
- }
-
- if (resumeCopy) goto do_copy;
-
- while (1) { /* do until end of block */
- b = fill_bitbuffer(b, &k, bl);
- if ((e = (t = tl + ((unsigned) b & ml))->e) > 16)
- do {
- if (e == 99) {
- bb_error_msg_and_die("inflate_codes error 1");;
- }
- b >>= t->b;
- k -= t->b;
- e -= 16;
- b = fill_bitbuffer(b, &k, e);
- } while ((e =
- (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
- b >>= t->b;
- k -= t->b;
- if (e == 16) { /* then it's a literal */
- gunzip_window[w++] = (unsigned char) t->v.n;
- if (w == gunzip_wsize) {
- gunzip_outbuf_count = (w);
- //flush_gunzip_window();
- w = 0;
- return 1; // We have a block to read
- }
- } else { /* it's an EOB or a length */
-
- /* exit if end of block */
- if (e == 15) {
- break;
- }
-
- /* get length of block to copy */
- b = fill_bitbuffer(b, &k, e);
- n = t->v.n + ((unsigned) b & mask_bits[e]);
- b >>= e;
- k -= e;
-
- /* decode distance of block to copy */
- b = fill_bitbuffer(b, &k, bd);
- if ((e = (t = td + ((unsigned) b & md))->e) > 16)
- do {
- if (e == 99)
- bb_error_msg_and_die("inflate_codes error 2");;
- b >>= t->b;
- k -= t->b;
- e -= 16;
- b = fill_bitbuffer(b, &k, e);
- } while ((e =
- (t =
- t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
- b >>= t->b;
- k -= t->b;
- b = fill_bitbuffer(b, &k, e);
- d = w - t->v.n - ((unsigned) b & mask_bits[e]);
- b >>= e;
- k -= e;
-
- /* do the copy */
-do_copy: do {
- n -= (e =
- (e =
- gunzip_wsize - ((d &= gunzip_wsize - 1) > w ? d : w)) > n ? n : e);
- /* copy to new buffer to prevent possible overwrite */
- if (w - d >= e) { /* (this test assumes unsigned comparison) */
- memcpy(gunzip_window + w, gunzip_window + d, e);
- w += e;
- d += e;
- } else {
- /* do it slow to avoid memcpy() overlap */
- /* !NOMEMCPY */
- do {
- gunzip_window[w++] = gunzip_window[d++];
- } while (--e);
- }
- if (w == gunzip_wsize) {
- gunzip_outbuf_count = (w);
- if (n) resumeCopy = 1;
- else resumeCopy = 0;
- //flush_gunzip_window();
- w = 0;
- return 1;
- }
- } while (n);
- resumeCopy = 0;
- }
- }
-
- /* restore the globals from the locals */
- gunzip_outbuf_count = w; /* restore global gunzip_window pointer */
- gunzip_bb = b; /* restore global bit buffer */
- gunzip_bk = k;
-
- /* normally just after call to inflate_codes, but save code by putting it here */
- /* free the decoding tables, return */
- huft_free(tl);
- huft_free(td);
-
- /* done */
- return 0;
-}
-
-static int inflate_stored(int my_n, int my_b_stored, int my_k_stored, int setup)
-{
- static int n, b_stored, k_stored, w;
- if (setup) {
- n = my_n;
- b_stored = my_b_stored;
- k_stored = my_k_stored;
- w = gunzip_outbuf_count; /* initialize gunzip_window position */
- return 0; // Don't do anything first time
- }
-
- /* read and output the compressed data */
- while (n--) {
- b_stored = fill_bitbuffer(b_stored, &k_stored, 8);
- gunzip_window[w++] = (unsigned char) b_stored;
- if (w == (unsigned int) gunzip_wsize) {
- gunzip_outbuf_count = (w);
- //flush_gunzip_window();
- w = 0;
- b_stored >>= 8;
- k_stored -= 8;
- return 1; // We have a block
- }
- b_stored >>= 8;
- k_stored -= 8;
- }
-
- /* restore the globals from the locals */
- gunzip_outbuf_count = w; /* restore global gunzip_window pointer */
- gunzip_bb = b_stored; /* restore global bit buffer */
- gunzip_bk = k_stored;
- return 0; // Finished
-}
-
-/*
- * decompress an inflated block
- * e: last block flag
- *
- * GLOBAL VARIABLES: bb, kk,
- */
- // Return values: -1 = inflate_stored, -2 = inflate_codes
-static int inflate_block(int *e)
-{
- unsigned t; /* block type */
- register unsigned int b; /* bit buffer */
- unsigned int k; /* number of bits in bit buffer */
-
- /* make local bit buffer */
-
- b = gunzip_bb;
- k = gunzip_bk;
-
- /* read in last block bit */
- b = fill_bitbuffer(b, &k, 1);
- *e = (int) b & 1;
- b >>= 1;
- k -= 1;
-
- /* read in block type */
- b = fill_bitbuffer(b, &k, 2);
- t = (unsigned) b & 3;
- b >>= 2;
- k -= 2;
-
- /* restore the global bit buffer */
- gunzip_bb = b;
- gunzip_bk = k;
-
- /* inflate that block type */
- switch (t) {
- case 0: /* Inflate stored */
- {
- unsigned int n; /* number of bytes in block */
- unsigned int b_stored; /* bit buffer */
- unsigned int k_stored; /* number of bits in bit buffer */
-
- /* make local copies of globals */
- b_stored = gunzip_bb; /* initialize bit buffer */
- k_stored = gunzip_bk;
-
- /* go to byte boundary */
- n = k_stored & 7;
- b_stored >>= n;
- k_stored -= n;
-
- /* get the length and its complement */
- b_stored = fill_bitbuffer(b_stored, &k_stored, 16);
- n = ((unsigned) b_stored & 0xffff);
- b_stored >>= 16;
- k_stored -= 16;
-
- b_stored = fill_bitbuffer(b_stored, &k_stored, 16);
- if (n != (unsigned) ((~b_stored) & 0xffff)) {
- return 1; /* error in compressed data */
- }
- b_stored >>= 16;
- k_stored -= 16;
-
- inflate_stored(n, b_stored, k_stored, 1); // Setup inflate_stored
- return -1;
- }
- case 1: /* Inflate fixed
- * decompress an inflated type 1 (fixed Huffman codes) block. We should
- * either replace this with a custom decoder, or at least precompute the
- * Huffman tables.
- */
- {
- int i; /* temporary variable */
- huft_t *tl; /* literal/length code table */
- huft_t *td; /* distance code table */
- unsigned int bl; /* lookup bits for tl */
- unsigned int bd; /* lookup bits for td */
- unsigned int l[288]; /* length list for huft_build */
-
- /* set up literal table */
- for (i = 0; i < 144; i++) {
- l[i] = 8;
- }
- for (; i < 256; i++) {
- l[i] = 9;
- }
- for (; i < 280; i++) {
- l[i] = 7;
- }
- for (; i < 288; i++) { /* make a complete, but wrong code set */
- l[i] = 8;
- }
- bl = 7;
- if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) {
- return i;
- }
-
- /* set up distance table */
- for (i = 0; i < 30; i++) { /* make an incomplete code set */
- l[i] = 5;
- }
- bd = 5;
- if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) {
- huft_free(tl);
- return i;
- }
-
- /* decompress until an end-of-block code */
- inflate_codes(tl, td, bl, bd, 1); // Setup inflate_codes
-
- /* huft_free code moved into inflate_codes */
-
- return -2;
- }
- case 2: /* Inflate dynamic */
- {
- const int dbits = 6; /* bits in base distance lookup table */
- const int lbits = 9; /* bits in base literal/length lookup table */
-
- huft_t *tl; /* literal/length code table */
- huft_t *td; /* distance code table */
- unsigned int i; /* temporary variables */
- unsigned int j;
- unsigned int l; /* last length */
- unsigned int m; /* mask for bit lengths table */
- unsigned int n; /* number of lengths to get */
- unsigned int bl; /* lookup bits for tl */
- unsigned int bd; /* lookup bits for td */
- unsigned int nb; /* number of bit length codes */
- unsigned int nl; /* number of literal/length codes */
- unsigned int nd; /* number of distance codes */
-
- unsigned int ll[286 + 30]; /* literal/length and distance code lengths */
- unsigned int b_dynamic; /* bit buffer */
- unsigned int k_dynamic; /* number of bits in bit buffer */
-
- /* make local bit buffer */
- b_dynamic = gunzip_bb;
- k_dynamic = gunzip_bk;
-
- /* read in table lengths */
- b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5);
- nl = 257 + ((unsigned int) b_dynamic & 0x1f); /* number of literal/length codes */
-
- b_dynamic >>= 5;
- k_dynamic -= 5;
- b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5);
- nd = 1 + ((unsigned int) b_dynamic & 0x1f); /* number of distance codes */
-
- b_dynamic >>= 5;
- k_dynamic -= 5;
- b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 4);
- nb = 4 + ((unsigned int) b_dynamic & 0xf); /* number of bit length codes */
-
- b_dynamic >>= 4;
- k_dynamic -= 4;
- if (nl > 286 || nd > 30) {
- return 1; /* bad lengths */
- }
-
- /* read in bit-length-code lengths */
- for (j = 0; j < nb; j++) {
- b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3);
- ll[border[j]] = (unsigned int) b_dynamic & 7;
- b_dynamic >>= 3;
- k_dynamic -= 3;
- }
- for (; j < 19; j++) {
- ll[border[j]] = 0;
- }
-
- /* build decoding table for trees--single level, 7 bit lookup */
- bl = 7;
- i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl);
- if (i != 0) {
- if (i == 1) {
- huft_free(tl);
- }
- return i; /* incomplete code set */
- }
-
- /* read in literal and distance code lengths */
- n = nl + nd;
- m = mask_bits[bl];
- i = l = 0;
- while ((unsigned int) i < n) {
- b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, (unsigned int)bl);
- j = (td = tl + ((unsigned int) b_dynamic & m))->b;
- b_dynamic >>= j;
- k_dynamic -= j;
- j = td->v.n;
- if (j < 16) { /* length of code in bits (0..15) */
- ll[i++] = l = j; /* save last length in l */
- } else if (j == 16) { /* repeat last length 3 to 6 times */
- b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 2);
- j = 3 + ((unsigned int) b_dynamic & 3);
- b_dynamic >>= 2;
- k_dynamic -= 2;
- if ((unsigned int) i + j > n) {
- return 1;
- }
- while (j--) {
- ll[i++] = l;
- }
- } else if (j == 17) { /* 3 to 10 zero length codes */
- b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3);
- j = 3 + ((unsigned int) b_dynamic & 7);
- b_dynamic >>= 3;
- k_dynamic -= 3;
- if ((unsigned int) i + j > n) {
- return 1;
- }
- while (j--) {
- ll[i++] = 0;
- }
- l = 0;
- } else { /* j == 18: 11 to 138 zero length codes */
- b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 7);
- j = 11 + ((unsigned int) b_dynamic & 0x7f);
- b_dynamic >>= 7;
- k_dynamic -= 7;
- if ((unsigned int) i + j > n) {
- return 1;
- }
- while (j--) {
- ll[i++] = 0;
- }
- l = 0;
- }
- }
-
- /* free decoding table for trees */
- huft_free(tl);
-
- /* restore the global bit buffer */
- gunzip_bb = b_dynamic;
- gunzip_bk = k_dynamic;
-
- /* build the decoding tables for literal/length and distance codes */
- bl = lbits;
-
- if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) {
- if (i == 1) {
- bb_error_msg_and_die("Incomplete literal tree");
- huft_free(tl);
- }
- return i; /* incomplete code set */
- }
-
- bd = dbits;
- if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) {
- if (i == 1) {
- bb_error_msg_and_die("incomplete distance tree");
- huft_free(td);
- }
- huft_free(tl);
- return i; /* incomplete code set */
- }
-
- /* decompress until an end-of-block code */
- inflate_codes(tl, td, bl, bd, 1); // Setup inflate_codes
-
- /* huft_free code moved into inflate_codes */
-
- return -2;
- }
- default:
- /* bad block type */
- bb_error_msg_and_die("bad block type %d\n", t);
- }
-}
-
-static void calculate_gunzip_crc(void)
-{
- int n;
- for (n = 0; n < gunzip_outbuf_count; n++) {
- gunzip_crc = gunzip_crc_table[((int) gunzip_crc ^ (gunzip_window[n])) & 0xff] ^ (gunzip_crc >> 8);
- }
- gunzip_bytes_out += gunzip_outbuf_count;
-}
-
-static int inflate_get_next_window(void)
-{
- static int needAnotherBlock = 1;
- static int method = -1; // Method == -1 for stored, -2 for codes
- static int e = 0;
-
- gunzip_outbuf_count = 0;
-
- while(1) {
- int ret;
-
- if (needAnotherBlock) {
- if(e) {
- calculate_gunzip_crc();
- return 0;
- } // Last block
- method = inflate_block(&e);
- needAnotherBlock = 0;
- }
-
- switch (method) {
- case -1: ret = inflate_stored(0,0,0,0);
- break;
- case -2: ret = inflate_codes(0,0,0,0,0);
- break;
- default: bb_error_msg_and_die("inflate error %d", method);
- }
-
- if (ret == 1) {
- calculate_gunzip_crc();
- return 1; // More data left
- } else needAnotherBlock = 1; // End of that block
- }
- /* Doesnt get here */
-}
-
-/*
- * User functions
- *
- * read_gz, GZ_gzReadOpen, GZ_gzReadClose, inflate
- */
-
-extern ssize_t read_gz(int fd, void *buf, size_t count)
-{
- static int morebytes = 0, finished = 0;
-
- if (morebytes) {
- int bytesRead = morebytes > count ? count : morebytes;
- memcpy(buf, gunzip_window + (gunzip_outbuf_count - morebytes), bytesRead);
- morebytes -= bytesRead;
- return bytesRead;
- } else if (finished) {
- return 0;
- } else if (count >= 0x8000) { // We can decompress direcly to the buffer, 32k at a time
- // Could decompress to larger buffer, but it must be a power of 2, and calculating that is probably more expensive than the benefit
- unsigned char *old_gunzip_window = gunzip_window; // Save old window
- gunzip_window = buf;
- if (inflate_get_next_window() == 0) finished = 1;
- gunzip_window = old_gunzip_window; // Restore old window
- return gunzip_outbuf_count;
- } else { // Oh well, need to split up the gunzip_window
- int bytesRead;
- if (inflate_get_next_window() == 0) finished = 1;
- morebytes = gunzip_outbuf_count;
- bytesRead = morebytes > count ? count : morebytes;
- memcpy(buf, gunzip_window, bytesRead);
- morebytes -= bytesRead;
- return bytesRead;
- }
-
-}
-
-extern void GZ_gzReadOpen(int fd, void *unused, int nUnused)
-{
- typedef void (*sig_type) (int);
-
- /* Allocate all global buffers (for DYN_ALLOC option) */
- gunzip_window = xmalloc(gunzip_wsize);
- gunzip_outbuf_count = 0;
- gunzip_bytes_out = 0;
- gunzip_src_fd = fd;
-
- /* Input buffer */
- bytebuffer = xmalloc(BYTEBUFFER_MAX);
-
- /* initialize gunzip_window, bit buffer */
- gunzip_bk = 0;
- gunzip_bb = 0;
-
- /* Create the crc table */
- make_gunzip_crc_table();
-}
-
-extern void GZ_gzReadClose(void)
-{
- /* Cleanup */
- free(gunzip_window);
- free(gunzip_crc_table);
-
- /* Store unused bytes in a global buffer so calling applets can access it */
- if (gunzip_bk >= 8) {
- /* Undo too much lookahead. The next read will be byte aligned
- * so we can discard unused bits in the last meaningful byte. */
- bytebuffer_offset--;
- bytebuffer[bytebuffer_offset] = gunzip_bb & 0xff;
- gunzip_bb >>= 8;
- gunzip_bk -= 8;
- }
-}
-
-/*extern int inflate(int in, int out) // Useful for testing read_gz
-{
- char buf[8192];
- ssize_t nread, nwrote;
-
- GZ_gzReadOpen(in, 0, 0);
- while(1) { // Robbed from bb_copyfd.c
- nread = read_gz(in, buf, sizeof(buf));
- if (nread == 0) break; // no data to write
- else if (nread == -1) {
- bb_perror_msg("read");
- return -1;
- }
- nwrote = bb_full_write(out, buf, nread);
- if (nwrote == -1) {
- bb_perror_msg("write");
- return -1;
- }
- }
- GZ_gzReadClose();
- return 0;
-}*/
-
-extern int inflate(int in, int out)
-{
- ssize_t nwrote;
- GZ_gzReadOpen(in, 0, 0);
- while(1) {
- int ret = inflate_get_next_window();
- nwrote = bb_full_write(out, gunzip_window, gunzip_outbuf_count);
- if (nwrote == -1) {
- bb_perror_msg("write");
- return -1;
- }
- if (ret == 0) break;
- }
- GZ_gzReadClose();
- return 0;
-}
-
-extern void check_trailer_gzip(int src_fd)
-{
- unsigned int stored_crc = 0;
- unsigned char count;
-
- /* top up the input buffer with the rest of the trailer */
- count = bytebuffer_size - bytebuffer_offset;
- if (count < 8) {
- bb_xread_all(src_fd, &bytebuffer[bytebuffer_size], 8 - count);
- bytebuffer_size += 8 - count;
- }
- for (count = 0; count != 4; count++) {
- stored_crc |= (bytebuffer[bytebuffer_offset] << (count * 8));
- bytebuffer_offset++;
- }
-
- /* Validate decompression - crc */
- if (stored_crc != (gunzip_crc ^ 0xffffffffL)) {
- bb_error_msg_and_die("crc error");
- }
-
- /* Validate decompression - size */
- if (gunzip_bytes_out !=
- (bytebuffer[bytebuffer_offset] | (bytebuffer[bytebuffer_offset+1] << 8) |
- (bytebuffer[bytebuffer_offset+2] << 16) | (bytebuffer[bytebuffer_offset+3] << 24))) {
- bb_error_msg_and_die("Incorrect length, but crc is correct");
- }
-
-}