aboutsummaryrefslogtreecommitdiff
path: root/lib/timidity/libarc
diff options
context:
space:
mode:
authortheuni <theuni-nospam-@xbmc.org>2011-01-24 16:05:21 -0500
committertheuni <theuni-nospam-@xbmc.org>2011-01-24 16:05:21 -0500
commitc51b1189e3d5353e842991f5859ddcea0f73e426 (patch)
treeef2cb8a6184699aa614f3655dca4ce661cdc108e /lib/timidity/libarc
parentbe61ebdc9e897fe40c6f371111724de79ddee8d5 (diff)
Merged cptspiff's code-reshuffle branch.
Squashed commit due to build breakage during code-reshuffle history. Conflicts: xbmc/Util.cpp xbmc/cdrip/CDDARipper.cpp xbmc/filesystem/Directory.cpp xbmc/filesystem/File.cpp
Diffstat (limited to 'lib/timidity/libarc')
-rw-r--r--lib/timidity/libarc/Makefile.am106
-rw-r--r--lib/timidity/libarc/Makefile.in688
-rw-r--r--lib/timidity/libarc/arc.c1168
-rw-r--r--lib/timidity/libarc/arc.h143
-rw-r--r--lib/timidity/libarc/arc_lzh.c552
-rw-r--r--lib/timidity/libarc/arc_mime.c647
-rw-r--r--lib/timidity/libarc/arc_tar.c181
-rw-r--r--lib/timidity/libarc/arc_zip.c236
-rw-r--r--lib/timidity/libarc/deflate.c1937
-rw-r--r--lib/timidity/libarc/explode.c1052
-rw-r--r--lib/timidity/libarc/explode.h47
-rw-r--r--lib/timidity/libarc/inflate.c1045
-rw-r--r--lib/timidity/libarc/unlzh.c1209
-rw-r--r--lib/timidity/libarc/unlzh.h35
-rw-r--r--lib/timidity/libarc/url.c567
-rw-r--r--lib/timidity/libarc/url.h239
-rw-r--r--lib/timidity/libarc/url_b64decode.c254
-rw-r--r--lib/timidity/libarc/url_buff.c345
-rw-r--r--lib/timidity/libarc/url_cache.c255
-rw-r--r--lib/timidity/libarc/url_dir.c487
-rw-r--r--lib/timidity/libarc/url_file.c461
-rw-r--r--lib/timidity/libarc/url_ftp.c561
-rw-r--r--lib/timidity/libarc/url_hqxdecode.c453
-rw-r--r--lib/timidity/libarc/url_http.c342
-rw-r--r--lib/timidity/libarc/url_inflate.c135
-rw-r--r--lib/timidity/libarc/url_mem.c180
-rw-r--r--lib/timidity/libarc/url_news.c494
-rw-r--r--lib/timidity/libarc/url_newsgroup.c546
-rw-r--r--lib/timidity/libarc/url_pipe.c174
-rw-r--r--lib/timidity/libarc/url_qsdecode.c252
-rw-r--r--lib/timidity/libarc/url_uudecode.c282
-rw-r--r--lib/timidity/libarc/zip.h116
32 files changed, 15189 insertions, 0 deletions
diff --git a/lib/timidity/libarc/Makefile.am b/lib/timidity/libarc/Makefile.am
new file mode 100644
index 0000000000..d2da9c5541
--- /dev/null
+++ b/lib/timidity/libarc/Makefile.am
@@ -0,0 +1,106 @@
+# TiMidity++ -- MIDI to WAVE converter and player
+# Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+# Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+#
+# 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 $(top_srcdir)/common.makefile.in
+
+INCLUDES = \
+ -I$(top_srcdir)/timidity \
+ -I$(top_srcdir)/utils \
+ $(EXTRAINCS)
+
+noinst_LIBRARIES = libarc.a
+
+libarc_a_SOURCES = \
+ arc.c \
+ arc.h \
+ arc_lzh.c \
+ arc_mime.c \
+ arc_tar.c \
+ arc_zip.c \
+ deflate.c \
+ explode.c \
+ explode.h \
+ inflate.c \
+ unlzh.c \
+ unlzh.h \
+ url.c \
+ url.h \
+ url_b64decode.c \
+ url_buff.c \
+ url_cache.c \
+ url_dir.c \
+ url_file.c \
+ url_hqxdecode.c \
+ url_inflate.c \
+ url_mem.c \
+ url_pipe.c \
+ url_qsdecode.c \
+ url_uudecode.c \
+ zip.h
+
+EXTRA_libarc_a_SOURCES = \
+ url_http.c \
+ url_ftp.c \
+ url_news.c \
+ url_newsgroup.c
+
+if ENABLE_NETWORK
+NET_OBJS = \
+ url_http.$(OBJEXT) \
+ url_ftp.$(OBJEXT) \
+ url_news.$(OBJEXT) \
+ url_newsgroup.$(OBJEXT)
+endif
+
+libarc_a_LIBADD = $(NET_OBJS)
+
+libarc.a: $(libarc_a_OBJECTS) $(libarc_a_DEPENDENCIES)
+if VCPP
+ rm -f libarc.a
+ rm -f arc.lib
+ link -lib $(libarc_a_OBJECTS) $(libarc_a_LIBADD) -out:arc.lib
+ if test -f arc.lib ; then touch $@ ; fi
+else
+if BORLANDC
+ rm -f libarc.a
+ rm -f arc.lib
+ for foo in $(libarc_a_OBJECTS) $(libarc_a_LIBADD);do \
+ tlib arc.lib +$$foo; \
+ done
+ if test -f arc.lib ; then touch $@ ; fi
+else
+if WATCOM_C
+ rm -f libarc.a
+ rm -f arc.lib
+ for foo in $(libarc_a_OBJECTS) $(libarc_a_LIBADD);do \
+ wlib -q arc.lib +$$foo; \
+ done
+ if test -f arc.lib ; then touch $@ ; fi
+else
+ -rm -f libarc.a
+ $(libarc_a_AR) libarc.a $(libarc_a_OBJECTS) $(libarc_a_LIBADD)
+ $(RANLIB) libarc.a
+endif
+endif
+endif
+
+clean:
+ rm -f *.$(OBJEXT)
+ rm -f *.$(so)
+ rm -f *.a
+ rm -f *.lib
diff --git a/lib/timidity/libarc/Makefile.in b/lib/timidity/libarc/Makefile.in
new file mode 100644
index 0000000000..0c75cfebb3
--- /dev/null
+++ b/lib/timidity/libarc/Makefile.in
@@ -0,0 +1,688 @@
+# Makefile.in generated by automake 1.7.6 from Makefile.am.
+# @configure_input@
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# TiMidity++ -- MIDI to WAVE converter and player
+# Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+# Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+#
+# 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
+
+# Define follows if you want to change.
+# Note that the definition of beginning with just one `#' implies
+# default value from configure.
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+pkgdatadir = @pkgdatadir@
+
+#CC= @CC@
+#CFLAGS = @CFLAGS@
+# For pentium gcc
+# For PGCC
+#CPPFLAGS = @CPPFLAGS@
+
+#DEFS = @DEFS@
+#LDFLAGS = @LDFLAGS@
+#LIBS = @LIBS@
+#SHLD = @SHLD@
+#SHCFLAGS = @SHCFLAGS@
+#@SET_MAKE@
+
+#prefix = @prefix@
+#exec_prefix = @exec_prefix@
+#bindir = @bindir@
+#libdir = @libdir@
+#datadir = @datadir@
+#mandir = @mandir@
+pkglibdir = @pkglibdir@
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AO_CFLAGS = @AO_CFLAGS@
+AO_LIBS = @AO_LIBS@
+ARTS_CFLAGS = @ARTS_CFLAGS@
+ARTS_CONFIG = @ARTS_CONFIG@
+ARTS_LIBS = @ARTS_LIBS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+A_so_libs = @A_so_libs@
+BORLANDC_FALSE = @BORLANDC_FALSE@
+BORLANDC_LDFLAGS = @BORLANDC_LDFLAGS@
+BORLANDC_START = @BORLANDC_START@
+BORLANDC_TRUE = @BORLANDC_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGNUS_FALSE = @CYGNUS_FALSE@
+CYGNUS_TRUE = @CYGNUS_TRUE@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ELFILES = @ELFILES@
+EMACS = @EMACS@
+ENABLE_ALSASEQ_FALSE = @ENABLE_ALSASEQ_FALSE@
+ENABLE_ALSASEQ_TRUE = @ENABLE_ALSASEQ_TRUE@
+ENABLE_DYNAMIC_TCLTK_FALSE = @ENABLE_DYNAMIC_TCLTK_FALSE@
+ENABLE_DYNAMIC_TCLTK_TRUE = @ENABLE_DYNAMIC_TCLTK_TRUE@
+ENABLE_DYNAMIC_XAW_FALSE = @ENABLE_DYNAMIC_XAW_FALSE@
+ENABLE_DYNAMIC_XAW_TRUE = @ENABLE_DYNAMIC_XAW_TRUE@
+ENABLE_EMACS_FALSE = @ENABLE_EMACS_FALSE@
+ENABLE_EMACS_TRUE = @ENABLE_EMACS_TRUE@
+ENABLE_GTK_FALSE = @ENABLE_GTK_FALSE@
+ENABLE_GTK_TRUE = @ENABLE_GTK_TRUE@
+ENABLE_MOTIF_FALSE = @ENABLE_MOTIF_FALSE@
+ENABLE_MOTIF_TRUE = @ENABLE_MOTIF_TRUE@
+ENABLE_NCURSES_FALSE = @ENABLE_NCURSES_FALSE@
+ENABLE_NCURSES_TRUE = @ENABLE_NCURSES_TRUE@
+ENABLE_NETWORK_FALSE = @ENABLE_NETWORK_FALSE@
+ENABLE_NETWORK_TRUE = @ENABLE_NETWORK_TRUE@
+ENABLE_PLUGIN_FALSE = @ENABLE_PLUGIN_FALSE@
+ENABLE_PLUGIN_TRUE = @ENABLE_PLUGIN_TRUE@
+ENABLE_PORTMIDISYN_FALSE = @ENABLE_PORTMIDISYN_FALSE@
+ENABLE_PORTMIDISYN_TRUE = @ENABLE_PORTMIDISYN_TRUE@
+ENABLE_SERVER_FALSE = @ENABLE_SERVER_FALSE@
+ENABLE_SERVER_TRUE = @ENABLE_SERVER_TRUE@
+ENABLE_SLANG_FALSE = @ENABLE_SLANG_FALSE@
+ENABLE_SLANG_TRUE = @ENABLE_SLANG_TRUE@
+ENABLE_SOUND_SPEC_FALSE = @ENABLE_SOUND_SPEC_FALSE@
+ENABLE_SOUND_SPEC_TRUE = @ENABLE_SOUND_SPEC_TRUE@
+ENABLE_TCLTK_FALSE = @ENABLE_TCLTK_FALSE@
+ENABLE_TCLTK_TRUE = @ENABLE_TCLTK_TRUE@
+ENABLE_VT100_FALSE = @ENABLE_VT100_FALSE@
+ENABLE_VT100_TRUE = @ENABLE_VT100_TRUE@
+ENABLE_W32GUI_FALSE = @ENABLE_W32GUI_FALSE@
+ENABLE_W32GUI_TRUE = @ENABLE_W32GUI_TRUE@
+ENABLE_W32G_SYN_FALSE = @ENABLE_W32G_SYN_FALSE@
+ENABLE_W32G_SYN_TRUE = @ENABLE_W32G_SYN_TRUE@
+ENABLE_WINSYN_FALSE = @ENABLE_WINSYN_FALSE@
+ENABLE_WINSYN_TRUE = @ENABLE_WINSYN_TRUE@
+ENABLE_WRD_FALSE = @ENABLE_WRD_FALSE@
+ENABLE_WRD_TRUE = @ENABLE_WRD_TRUE@
+ENABLE_XAW_FALSE = @ENABLE_XAW_FALSE@
+ENABLE_XAW_TRUE = @ENABLE_XAW_TRUE@
+ENABLE_XSKIN_FALSE = @ENABLE_XSKIN_FALSE@
+ENABLE_XSKIN_TRUE = @ENABLE_XSKIN_TRUE@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+EXTRALIBS = @EXTRALIBS@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_CONFIG = @GTK_CONFIG@
+GTK_LIBS = @GTK_LIBS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTERFACE_SRCS = @INTERFACE_SRCS@
+LDFLAGS = @LDFLAGS@
+LIBFLAC_CFLAGS = @LIBFLAC_CFLAGS@
+LIBFLAC_LIBS = @LIBFLAC_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBOGGFLAC_CFLAGS = @LIBOGGFLAC_CFLAGS@
+LIBOGGFLAC_LIBS = @LIBOGGFLAC_LIBS@
+LIBS = @LIBS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MSYS_FALSE = @MSYS_FALSE@
+MSYS_TRUE = @MSYS_TRUE@
+NEEDDLOPEN_FALSE = @NEEDDLOPEN_FALSE@
+NEEDDLOPEN_TRUE = @NEEDDLOPEN_TRUE@
+NEEDGETOPT_FALSE = @NEEDGETOPT_FALSE@
+NEEDGETOPT_TRUE = @NEEDGETOPT_TRUE@
+NETSRCS = @NETSRCS@
+OBJEXT = @OBJEXT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+P_so_libs = @P_so_libs@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHCFLAGS = @SHCFLAGS@
+
+SHELL = @SHELL@
+SHLD = @SHLD@
+STRIP = @STRIP@
+SYSEXTRAS = @SYSEXTRAS@
+T_so_libs = @T_so_libs@
+VCPP_FALSE = @VCPP_FALSE@
+VCPP_LDFLAGS = @VCPP_LDFLAGS@
+VCPP_TRUE = @VCPP_TRUE@
+VERSION = @VERSION@
+VORBISENC_LIBS = @VORBISENC_LIBS@
+VORBISFILE_LIBS = @VORBISFILE_LIBS@
+VORBIS_CFLAGS = @VORBIS_CFLAGS@
+VORBIS_LIBS = @VORBIS_LIBS@
+W32READDIR_FALSE = @W32READDIR_FALSE@
+W32READDIR_TRUE = @W32READDIR_TRUE@
+WATCOM_C_FALSE = @WATCOM_C_FALSE@
+WATCOM_C_TRUE = @WATCOM_C_TRUE@
+WATCOM_LDFLAGS = @WATCOM_LDFLAGS@
+WISH = @WISH@
+W_so_libs = @W_so_libs@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+a_so_libs = @a_so_libs@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+dynamic_targets = @dynamic_targets@
+e_so_libs = @e_so_libs@
+exec_prefix = @exec_prefix@
+g_so_libs = @g_so_libs@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+i_so_libs = @i_so_libs@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+k_so_libs = @k_so_libs@
+libdir = @libdir@
+libexecdir = @libexecdir@
+lispdir = @lispdir@
+localstatedir = @localstatedir@
+m_so_libs = @m_so_libs@
+mandir = @mandir@
+n_so_libs = @n_so_libs@
+oldincludedir = @oldincludedir@
+p_so_libs = @p_so_libs@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+r_so_libs = @r_so_libs@
+s_so_libs = @s_so_libs@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+so = @so@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+tcltk_dep = @tcltk_dep@
+timidity_LDFLAGS = @timidity_LDFLAGS@
+w_so_libs = @w_so_libs@
+#INSTALL = @INSTALL@
+
+# Where to install the patches, config files.
+PKGDATADIR = $(pkgdatadir)
+
+# Where to install the Tcl code and the bitmaps.
+# It also contains bitmaps which are shared with XAW interface.
+PKGLIBDIR = $(pkglibdir)
+
+# Where to install the dynamic link interface.
+SHLIB_DIR = $(pkglibdir)
+
+# Where to install timidity.el
+ELISP_DIR = $(lispdir)
+
+# If you want to change TCL_DIR, please do follows.
+# * Add -DTKPROGPATH=\"$(TCL_DIR)/tkmidity.tcl\" to CPPFLAGS.
+# * Make a symbolic link $(PKGLIBDIR)/bitmaps to $(TCL_DIR)/bitmaps
+TCL_DIR = $(PKGLIBDIR)
+
+# Define the timidity default file search path.
+DEF_DEFAULT_PATH = -DDEFAULT_PATH=\"$(PKGDATADIR)\"
+
+# You sould not change follows definitions.
+DEF_PKGDATADIR = -DPKGDATADIR=\"$(PKGDATADIR)\"
+DEF_PKGLIBDIR = -DPKGLIBDIR=\"$(PKGLIBDIR)\"
+DEF_SHLIB_DIR = -DSHLIB_DIR=\"$(SHLIB_DIR)\"
+BITMAP_DIR = $(TCL_DIR)/bitmaps
+
+INCLUDES = \
+ -I$(top_srcdir)/timidity \
+ -I$(top_srcdir)/utils \
+ $(EXTRAINCS)
+
+
+noinst_LIBRARIES = libarc.a
+
+libarc_a_SOURCES = \
+ arc.c \
+ arc.h \
+ arc_lzh.c \
+ arc_mime.c \
+ arc_tar.c \
+ arc_zip.c \
+ deflate.c \
+ explode.c \
+ explode.h \
+ inflate.c \
+ unlzh.c \
+ unlzh.h \
+ url.c \
+ url.h \
+ url_b64decode.c \
+ url_buff.c \
+ url_cache.c \
+ url_dir.c \
+ url_file.c \
+ url_hqxdecode.c \
+ url_inflate.c \
+ url_mem.c \
+ url_pipe.c \
+ url_qsdecode.c \
+ url_uudecode.c \
+ zip.h
+
+
+EXTRA_libarc_a_SOURCES = \
+ url_http.c \
+ url_ftp.c \
+ url_news.c \
+ url_newsgroup.c
+
+
+@ENABLE_NETWORK_TRUE@NET_OBJS = \
+@ENABLE_NETWORK_TRUE@ url_http.$(OBJEXT) \
+@ENABLE_NETWORK_TRUE@ url_ftp.$(OBJEXT) \
+@ENABLE_NETWORK_TRUE@ url_news.$(OBJEXT) \
+@ENABLE_NETWORK_TRUE@ url_newsgroup.$(OBJEXT)
+
+
+libarc_a_LIBADD = $(NET_OBJS)
+subdir = libarc
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/autoconf/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h $(top_builddir)/interface.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+libarc_a_AR = $(AR) cru
+@ENABLE_NETWORK_TRUE@libarc_a_DEPENDENCIES = url_http.$(OBJEXT) \
+@ENABLE_NETWORK_TRUE@ url_ftp.$(OBJEXT) url_news.$(OBJEXT) \
+@ENABLE_NETWORK_TRUE@ url_newsgroup.$(OBJEXT)
+@ENABLE_NETWORK_FALSE@libarc_a_DEPENDENCIES =
+am_libarc_a_OBJECTS = arc.$(OBJEXT) arc_lzh.$(OBJEXT) arc_mime.$(OBJEXT) \
+ arc_tar.$(OBJEXT) arc_zip.$(OBJEXT) deflate.$(OBJEXT) \
+ explode.$(OBJEXT) inflate.$(OBJEXT) unlzh.$(OBJEXT) \
+ url.$(OBJEXT) url_b64decode.$(OBJEXT) url_buff.$(OBJEXT) \
+ url_cache.$(OBJEXT) url_dir.$(OBJEXT) url_file.$(OBJEXT) \
+ url_hqxdecode.$(OBJEXT) url_inflate.$(OBJEXT) url_mem.$(OBJEXT) \
+ url_pipe.$(OBJEXT) url_qsdecode.$(OBJEXT) \
+ url_uudecode.$(OBJEXT)
+libarc_a_OBJECTS = $(am_libarc_a_OBJECTS)
+
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/autoconf/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/arc.Po ./$(DEPDIR)/arc_lzh.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/arc_mime.Po ./$(DEPDIR)/arc_tar.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/arc_zip.Po ./$(DEPDIR)/deflate.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/explode.Po ./$(DEPDIR)/inflate.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/unlzh.Po ./$(DEPDIR)/url.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/url_b64decode.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/url_buff.Po ./$(DEPDIR)/url_cache.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/url_dir.Po ./$(DEPDIR)/url_file.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/url_ftp.Po ./$(DEPDIR)/url_hqxdecode.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/url_http.Po ./$(DEPDIR)/url_inflate.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/url_mem.Po ./$(DEPDIR)/url_news.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/url_newsgroup.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/url_pipe.Po ./$(DEPDIR)/url_qsdecode.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/url_uudecode.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(libarc_a_SOURCES) $(EXTRA_libarc_a_SOURCES)
+DIST_COMMON = $(top_srcdir)/common.makefile.in Makefile.am Makefile.in
+SOURCES = $(libarc_a_SOURCES) $(EXTRA_libarc_a_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/common.makefile.in $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libarc/Makefile
+Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+
+AR = ar
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arc_lzh.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arc_mime.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arc_tar.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arc_zip.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/deflate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/explode.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inflate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unlzh.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url_b64decode.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url_buff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url_cache.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url_dir.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url_file.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url_ftp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url_hqxdecode.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url_http.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url_inflate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url_mem.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url_news.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url_newsgroup.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url_pipe.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url_qsdecode.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url_uudecode.Po@am__quote@
+
+distclean-depend:
+ -rm -rf ./$(DEPDIR)
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@ fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@ fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`
+uninstall-info-am:
+
+ETAGS = etags
+ETAGSFLAGS =
+
+CTAGS = ctags
+CTAGSFLAGS =
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$tags$$unique" \
+ || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique
+
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ $(mkinstalldirs) $(distdir)/..
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkinstalldirs) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES)
+
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+ distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-noinstLIBRARIES ctags distclean distclean-compile \
+ distclean-depend distclean-generic distclean-tags distdir dvi \
+ dvi-am info info-am install install-am install-data \
+ install-data-am install-exec install-exec-am install-info \
+ install-info-am install-man install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-info-am
+
+
+libarc.a: $(libarc_a_OBJECTS) $(libarc_a_DEPENDENCIES)
+@VCPP_TRUE@ rm -f libarc.a
+@VCPP_TRUE@ rm -f arc.lib
+@VCPP_TRUE@ link -lib $(libarc_a_OBJECTS) $(libarc_a_LIBADD) -out:arc.lib
+@VCPP_TRUE@ if test -f arc.lib ; then touch $@ ; fi
+@BORLANDC_TRUE@@VCPP_FALSE@ rm -f libarc.a
+@BORLANDC_TRUE@@VCPP_FALSE@ rm -f arc.lib
+@BORLANDC_TRUE@@VCPP_FALSE@ for foo in $(libarc_a_OBJECTS) $(libarc_a_LIBADD);do \
+@BORLANDC_TRUE@@VCPP_FALSE@ tlib arc.lib +$$foo; \
+@BORLANDC_TRUE@@VCPP_FALSE@ done
+@BORLANDC_TRUE@@VCPP_FALSE@ if test -f arc.lib ; then touch $@ ; fi
+@BORLANDC_FALSE@@VCPP_FALSE@@WATCOM_C_TRUE@ rm -f libarc.a
+@BORLANDC_FALSE@@VCPP_FALSE@@WATCOM_C_TRUE@ rm -f arc.lib
+@BORLANDC_FALSE@@VCPP_FALSE@@WATCOM_C_TRUE@ for foo in $(libarc_a_OBJECTS) $(libarc_a_LIBADD);do \
+@BORLANDC_FALSE@@VCPP_FALSE@@WATCOM_C_TRUE@ wlib -q arc.lib +$$foo; \
+@BORLANDC_FALSE@@VCPP_FALSE@@WATCOM_C_TRUE@ done
+@BORLANDC_FALSE@@VCPP_FALSE@@WATCOM_C_TRUE@ if test -f arc.lib ; then touch $@ ; fi
+@BORLANDC_FALSE@@VCPP_FALSE@@WATCOM_C_FALSE@ -rm -f libarc.a
+@BORLANDC_FALSE@@VCPP_FALSE@@WATCOM_C_FALSE@ $(libarc_a_AR) libarc.a $(libarc_a_OBJECTS) $(libarc_a_LIBADD)
+@BORLANDC_FALSE@@VCPP_FALSE@@WATCOM_C_FALSE@ $(RANLIB) libarc.a
+
+clean:
+ rm -f *.$(OBJEXT)
+ rm -f *.$(so)
+ rm -f *.a
+ rm -f *.lib
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lib/timidity/libarc/arc.c b/lib/timidity/libarc/arc.c
new file mode 100644
index 0000000000..f7f73d7c89
--- /dev/null
+++ b/lib/timidity/libarc/arc.c
@@ -0,0 +1,1168 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include <stdlib.h>
+
+#include "timidity.h"
+#include "common.h"
+#include "arc.h"
+#include "strtab.h"
+#include "zip.h"
+#include "unlzh.h"
+#include "explode.h"
+
+char *arc_lib_version = ARC_LIB_VERSION;
+
+#define GZIP_ASCIIFLAG (1u<<0)
+#define GZIP_MULTIPARTFLAG (1u<<1)
+#define GZIP_EXTRAFLAG (1u<<2)
+#define GZIP_FILEFLAG (1u<<3)
+#define GZIP_COMMFLAG (1u<<4)
+#define GZIP_ENCFLAG (1u<<5)
+
+#ifndef TRUE
+#define TRUE 1
+#endif /* TRUE */
+#ifndef FALSE
+#define FALSE 0
+#endif /* FALSE */
+#define ABORT -1
+
+ArchiveHandler arc_handler;
+static MBlockList arc_buffer;
+
+typedef struct _ArchiveFileList
+{
+ char *archive_name;
+ ArchiveEntryNode *entry_list;
+ struct _ArchiveFileList *next;
+} ArchiveFileList;
+static ArchiveFileList *arc_filelist = NULL;
+
+static struct
+{
+ char *ext;
+ int type;
+} archive_ext_list[] =
+{
+ {".tar", ARCHIVE_TAR},
+ {".tar.gz", ARCHIVE_TGZ},
+ {".tgz", ARCHIVE_TGZ},
+ {".zip", ARCHIVE_ZIP},
+ {".neo", ARCHIVE_ZIP},
+ {".lzh", ARCHIVE_LZH},
+ {".lha", ARCHIVE_LZH},
+ {".mime", ARCHIVE_MIME},
+ {PATH_STRING, ARCHIVE_DIR},
+ {NULL, -1}
+};
+
+int skip_gzip_header(URL url)
+{
+ unsigned char flags;
+ int m1, method;
+
+ /* magic */
+ m1 = url_getc(url);
+ if(m1 == 0)
+ {
+ url_skip(url, 128 - 1);
+ m1 = url_getc(url);
+ }
+ if(m1 != 0x1f)
+ return -1;
+ if(url_getc(url) != 0x8b)
+ return -1;
+
+ /* method */
+ method = url_getc(url);
+ switch(method)
+ {
+ case 8: /* deflated */
+ method = ARCHIVEC_DEFLATED;
+ break;
+ default:
+ return -1;
+ }
+ /* flags */
+ flags = url_getc(url);
+ if(flags & GZIP_ENCFLAG)
+ return -1;
+ /* time */
+ url_getc(url); url_getc(url); url_getc(url); url_getc(url);
+
+ url_getc(url); /* extra flags */
+ url_getc(url); /* OS type */
+
+ if(flags & GZIP_MULTIPARTFLAG)
+ {
+ /* part number */
+ url_getc(url); url_getc(url);
+ }
+
+ if(flags & GZIP_EXTRAFLAG)
+ {
+ unsigned short len;
+ int i;
+
+ /* extra field */
+
+ len = url_getc(url);
+ len |= ((unsigned short)url_getc(url)) << 8;
+ for(i = 0; i < len; i++)
+ url_getc(url);
+ }
+
+ if(flags & GZIP_FILEFLAG)
+ {
+ /* file name */
+ int c;
+
+ do
+ {
+ c = url_getc(url);
+ if(c == EOF)
+ return -1;
+ } while(c != '\0');
+ }
+
+ if(flags & GZIP_COMMFLAG)
+ {
+ /* comment */
+ int c;
+
+ do
+ {
+ c = url_getc(url);
+ if(c == EOF)
+ return -1;
+ } while(c != '\0');
+ }
+
+ return method;
+}
+
+int parse_gzip_header_bytes(char *gz, long maxparse, int *hdrsiz)
+{
+ URL url = url_mem_open(gz, maxparse, 0);
+ int method;
+
+ if(!url)
+ return -1;
+ method = skip_gzip_header(url);
+ *hdrsiz = url_tell(url);
+ url_close(url);
+ return method;
+}
+
+void (* arc_error_handler)(char *error_message) = NULL;
+
+static void arc_cant_open(char *s)
+{
+ if(arc_error_handler != NULL)
+ {
+ char buff[BUFSIZ];
+ snprintf(buff, sizeof(buff), "%s: Can't open", s);
+ arc_error_handler(buff);
+ }
+}
+
+int get_archive_type(char *archive_name)
+{
+ int i, len;
+ char *p;
+ int archive_name_length, delim;
+
+#ifdef SUPPORT_SOCKET
+ int type = url_check_type(archive_name);
+ if(type == URL_news_t)
+ return ARCHIVE_MIME;
+ if(type == URL_newsgroup_t)
+ return ARCHIVE_NEWSGROUP;
+#endif /* SUPPORT_SOCKET */
+
+ if(strncmp(archive_name, "mail:", 5) == 0 ||
+ strncmp(archive_name, "mime:", 5) == 0)
+ return ARCHIVE_MIME;
+
+ if((p = strrchr(archive_name, '#')) != NULL)
+ {
+ archive_name_length = p - archive_name;
+ delim = '#';
+ }
+ else
+ {
+ archive_name_length = strlen(archive_name);
+ delim = '\0';
+ }
+
+ for(i = 0; archive_ext_list[i].ext; i++)
+ {
+ len = strlen(archive_ext_list[i].ext);
+ if(len <= archive_name_length &&
+ strncasecmp(archive_name + archive_name_length - len,
+ archive_ext_list[i].ext, len) == 0 &&
+ archive_name[archive_name_length] == delim)
+ return archive_ext_list[i].type; /* Found */
+ }
+
+ if(url_check_type(archive_name) == URL_dir_t)
+ return ARCHIVE_DIR;
+
+ return -1; /* Not found */
+}
+
+static ArchiveFileList *find_arc_filelist(char *basename)
+{
+ ArchiveFileList *p;
+
+ for(p = arc_filelist; p; p = p->next)
+ {
+ if(strcmp(basename, p->archive_name) == 0)
+ return p;
+ }
+ return NULL;
+}
+
+ArchiveEntryNode *arc_parse_entry(URL url, int archive_type)
+{
+ ArchiveEntryNode *entry_first, *entry_last, *entry;
+ ArchiveEntryNode *(* next_header_entry)(void);
+ int gzip_method;
+ URL orig;
+
+ orig = NULL;
+ switch(archive_type)
+ {
+ case ARCHIVE_TAR:
+ next_header_entry = next_tar_entry;
+ break;
+ case ARCHIVE_TGZ:
+ gzip_method = skip_gzip_header(url);
+ if(gzip_method != ARCHIVEC_DEFLATED)
+ {
+ url_close(url);
+ return NULL;
+ }
+ orig = url;
+ if((url = url_inflate_open(orig, -1, 0)) == NULL)
+ return NULL;
+ next_header_entry = next_tar_entry;
+ break;
+ case ARCHIVE_ZIP:
+ next_header_entry = next_zip_entry;
+ break;
+ case ARCHIVE_LZH:
+ next_header_entry = next_lzh_entry;
+ break;
+ case ARCHIVE_MIME:
+ if(!IS_URL_SEEK_SAFE(url))
+ {
+ orig = url;
+ if((url = url_cache_open(orig, 0)) == NULL)
+ return NULL;
+ }
+ next_header_entry = next_mime_entry;
+ break;
+ default:
+ return NULL;
+ }
+
+ arc_handler.isfile = (url->type == URL_file_t);
+ arc_handler.url = url;
+ arc_handler.counter = 0;
+ entry_first = entry_last = NULL;
+ arc_handler.pos = 0;
+ while((entry = next_header_entry()) != NULL)
+ {
+ if(entry_first != NULL)
+ entry_last->next = entry;
+ else
+ entry_first = entry_last = entry;
+ while(entry_last->next)
+ entry_last = entry_last->next;
+ arc_handler.counter++;
+ }
+ url_close(url);
+ if(orig)
+ url_close(orig);
+ return entry_first; /* Note that NULL if no archive file */
+}
+
+static ArchiveFileList *add_arc_filelist(char *basename, int archive_type)
+{
+ URL url;
+ ArchiveFileList *afl;
+ ArchiveEntryNode *entry;
+
+ switch(archive_type)
+ {
+ case ARCHIVE_TAR:
+ case ARCHIVE_TGZ:
+ case ARCHIVE_ZIP:
+ case ARCHIVE_LZH:
+ case ARCHIVE_MIME:
+ break;
+ default:
+ return NULL;
+ }
+
+ if((url = url_open(basename)) == NULL)
+ {
+ arc_cant_open(basename);
+ return NULL;
+ }
+
+ entry = arc_parse_entry(url, archive_type);
+
+ afl = (ArchiveFileList *)safe_malloc(sizeof(ArchiveFileList));
+ afl->archive_name = safe_strdup(basename);
+ afl->entry_list = entry;
+ afl->next = arc_filelist;
+ arc_filelist = afl;
+ return afl;
+}
+
+static ArchiveFileList *regist_archive(char *archive_filename)
+{
+ int archive_type;
+
+ if((archive_type = get_archive_type(archive_filename)) < 0)
+ return NULL; /* Unknown archive */
+ archive_filename = url_expand_home_dir(archive_filename);
+ if(find_arc_filelist(archive_filename))
+ return NULL; /* Already registerd */
+ return add_arc_filelist(archive_filename, archive_type);
+}
+
+static int arc_expand_newfile(StringTable *s, ArchiveFileList *afl,
+ char *pattern)
+{
+ ArchiveEntryNode *entry;
+ char *p;
+
+ for(entry = afl->entry_list; entry; entry = entry->next)
+ {
+ if(arc_case_wildmat(entry->name, pattern))
+ {
+ p = new_segment(&arc_buffer, strlen(afl->archive_name) +
+ strlen(entry->name) + 2);
+ strcpy(p, afl->archive_name);
+ strcat(p, "#");
+ strcat(p, entry->name);
+ if(put_string_table(s, p, strlen(p)) == NULL)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+char **expand_archive_names(int *nfiles_in_out, char **files)
+{
+ int i, nfiles, arc_type;
+ char *infile_name;
+ char *base, *pattern, *p, buff[BUFSIZ];
+ char *one_file[1];
+ int one;
+ ArchiveFileList *afl;
+
+ /* Recusive global */
+ static MBlockList *pool;
+ static StringTable stab;
+ static int error_flag = 0;
+ static int depth = 0;
+
+ if(depth == 0)
+ {
+ error_flag = 0;
+ init_string_table(&stab);
+ pool = &arc_buffer;
+ }
+
+ nfiles = *nfiles_in_out;
+
+ for(i = 0; i < nfiles; i++)
+ {
+ infile_name = url_expand_home_dir(files[i]);
+ if((p = strrchr(infile_name, '#')) == NULL)
+ {
+ base = infile_name;
+ pattern = "*";
+ }
+ else
+ {
+ int len = p - infile_name;
+ base = new_segment(pool, len + 1); /* +1 for '\0' */
+ memcpy(base, infile_name, len);
+ base[len] = '\0';
+ pattern = p + 1;
+ }
+
+ if((afl = find_arc_filelist(base)) != NULL)
+ {
+ if(arc_expand_newfile(&stab, afl, pattern) == -1)
+ goto abort_expand;
+ continue;
+ }
+
+ arc_type = get_archive_type(base);
+ if(arc_type == -1)
+ {
+ if(put_string_table(&stab, infile_name, strlen(infile_name))
+ == NULL)
+ goto abort_expand;
+ continue;
+ }
+
+#ifdef SUPPORT_SOCKET
+ if(arc_type == ARCHIVE_NEWSGROUP)
+ {
+ URL url;
+ int len1, len2;
+ char *news_prefix;
+
+ if((url = url_newsgroup_open(base)) == NULL)
+ {
+ arc_cant_open(base);
+ continue;
+ }
+
+ strncpy(buff, base, sizeof(buff)-1);
+ p = strchr(buff + 7, '/') + 1; /* news://..../ */
+ *p = '\0';
+ news_prefix = strdup_mblock(pool, buff);
+ len1 = strlen(news_prefix);
+
+ while(url_gets(url, buff, sizeof(buff)))
+ {
+ len2 = strlen(buff);
+ p = (char *)new_segment(pool, len1 + len2 + 1);
+ strcpy(p, news_prefix);
+ strcpy(p + len1, buff);
+ one_file[0] = p;
+ one = 1;
+ depth++;
+ expand_archive_names(&one, one_file);
+ depth--;
+ }
+ url_close(url);
+ if(error_flag)
+ goto abort_expand;
+ continue;
+ }
+#endif /* SUPPORT_SOCKET */
+
+ if(arc_type == ARCHIVE_DIR)
+ {
+ URL url;
+ int len1, len2;
+
+ if((url = url_dir_open(base)) == NULL)
+ {
+ arc_cant_open(base);
+ continue;
+ }
+
+ if(strncmp(base, "dir:", 4) == 0)
+ base += 4;
+ len1 = strlen(base);
+ if(IS_PATH_SEP(base[len1 - 1]))
+ len1--;
+ while(url_gets(url, buff, sizeof(buff)))
+ {
+ if(strcmp(buff, ".") == 0 || strcmp(buff, "..") == 0)
+ continue;
+
+ len2 = strlen(buff);
+ p = (char *)new_segment(pool, len1 + len2 + 2);
+ strcpy(p, base);
+ p[len1] = PATH_SEP;
+ strcpy(p + len1 + 1, buff);
+ one_file[0] = p;
+ one = 1;
+ depth++;
+ expand_archive_names(&one, one_file);
+ depth--;
+ }
+ url_close(url);
+ if(error_flag)
+ goto abort_expand;
+ continue;
+ }
+
+ if((afl = add_arc_filelist(base, arc_type)) != NULL)
+ {
+ if(arc_expand_newfile(&stab, afl, pattern) == -1)
+ goto abort_expand;
+ }
+ }
+
+ if(depth)
+ return NULL;
+ *nfiles_in_out = stab.nstring;
+ reuse_mblock(pool);
+ return make_string_array(&stab); /* It is possible NULL */
+
+ abort_expand:
+ error_flag = 1;
+ if(depth)
+ return NULL;
+ delete_string_table(&stab);
+ free_global_mblock();
+ *nfiles_in_out = 0;
+ return NULL;
+}
+
+ArchiveEntryNode *new_entry_node(char *name, int len)
+{
+ ArchiveEntryNode *entry;
+ entry = (ArchiveEntryNode *)safe_malloc(sizeof(ArchiveEntryNode));
+ memset(entry, 0, sizeof(ArchiveEntryNode));
+ entry->name = (char *)safe_malloc(len + 1);
+ memcpy(entry->name, name, len);
+ entry->name[len] = '\0';
+ return entry;
+}
+
+void free_entry_node(ArchiveEntryNode *entry)
+{
+ free(entry->name);
+ if(entry->cache != NULL)
+ free(entry->cache);
+ free(entry);
+}
+
+
+static char *compress_buff;
+long compress_buff_len;
+static long arc_compress_func(char *buff, long size, void *user_val)
+{
+ if(compress_buff_len <= 0)
+ return 0;
+ if(size > compress_buff_len)
+ size = compress_buff_len;
+ memcpy(buff, compress_buff, size);
+ compress_buff += size;
+ compress_buff_len -= size;
+ return size;
+}
+
+void *arc_compress(void *buff, long bufsiz,
+ int compress_level, long *compressed_size)
+{
+ DeflateHandler compressor;
+ long allocated, offset, space, nbytes;
+ char *compressed;
+
+ compress_buff = (char *)buff;
+ compress_buff_len = bufsiz;
+ compressor = open_deflate_handler(arc_compress_func, NULL,
+ compress_level);
+ allocated = 1024;
+ compressed = (char *)safe_malloc(allocated);
+ offset = 0;
+ space = allocated;
+ while((nbytes = zip_deflate(compressor, compressed + offset, space)) > 0)
+ {
+ offset += nbytes;
+ space -= nbytes;
+ if(space == 0)
+ {
+ space = allocated;
+ allocated += space;
+ compressed = (char *)safe_realloc(compressed, allocated);
+ }
+ }
+ close_deflate_handler(compressor);
+ if(offset == 0)
+ {
+ free(buff);
+ return NULL;
+ }
+ *compressed_size = offset;
+ return compressed;
+}
+
+void *arc_decompress(void *buff, long bufsiz, long *decompressed_size)
+{
+ InflateHandler decompressor;
+ long allocated, offset, space, nbytes;
+ char *decompressed;
+
+ compress_buff = (char *)buff;
+ compress_buff_len = bufsiz;
+ decompressor = open_inflate_handler(arc_compress_func, NULL);
+ allocated = 1024;
+ decompressed = (char *)safe_malloc(allocated);
+ offset = 0;
+ space = allocated;
+ while((nbytes = zip_inflate(decompressor, decompressed + offset, space)) > 0)
+ {
+ offset += nbytes;
+ space -= nbytes;
+ if(space == 0)
+ {
+ space = allocated;
+ allocated += space;
+ decompressed = (char *)safe_realloc(decompressed, allocated);
+ }
+ }
+ close_inflate_handler(decompressor);
+ if(offset == 0)
+ {
+ free(buff);
+ return NULL;
+ }
+ *decompressed_size = offset;
+ return decompressed;
+}
+
+void free_archive_files(void)
+{
+ ArchiveEntryNode *entry, *ecur;
+ ArchiveFileList *acur;
+
+ while(arc_filelist)
+ {
+ acur = arc_filelist;
+ arc_filelist = arc_filelist->next;
+ entry = acur->entry_list;
+ while(entry)
+ {
+ ecur = entry;
+ entry = entry->next;
+ free_entry_node(ecur);
+ }
+ free(acur->archive_name);
+ free(acur);
+ }
+}
+
+/******************************************************************************
+* url_arc
+*****************************************************************************/
+typedef struct _URL_arc
+{
+ char common[sizeof(struct _URL)];
+ URL instream;
+ long pos, size;
+ int comptype;
+ void *decoder;
+} URL_arc;
+
+static long url_arc_read(URL url, void *buff, long n);
+static long url_arc_tell(URL url);
+static void url_arc_close(URL url);
+
+static long archiver_read_func(char *buff, long buff_size, void *v)
+{
+ URL_arc *url;
+ long n;
+
+ url = (URL_arc *)v;
+
+ if(url->size < 0)
+ n = buff_size;
+ else
+ {
+ n = url->size - url->pos;
+ if(n > buff_size)
+ n = buff_size;
+ }
+
+ if(n <= 0)
+ return 0;
+ n = url_read(url->instream, buff, n);
+ if(n <= 0)
+ return n;
+
+ return n;
+}
+
+URL url_arc_open(char *name)
+{
+ URL_arc *url;
+ char *base, *p;
+ int len;
+ ArchiveFileList *afl;
+ ArchiveEntryNode *entry;
+ URL instream;
+
+ if((p = strrchr(name, '#')) == NULL)
+ return NULL;
+ len = p - name;
+ base = new_segment(&arc_buffer, len + 1);
+ memcpy(base, name, len);
+ base[len] = '\0';
+ base = url_expand_home_dir(base);
+
+ if((afl = find_arc_filelist(base)) == NULL)
+ afl = regist_archive(base);
+ if(afl == NULL)
+ return NULL;
+ reuse_mblock(&arc_buffer); /* free `base' */
+ name += len + 1;
+ while(name[0] == '/') name++; /* skip '/'s right after # */
+
+ for(entry = afl->entry_list; entry; entry = entry->next)
+ {
+ if(strcasecmp(entry->name, name) == 0)
+ break;
+ }
+ if(entry == NULL)
+ return NULL;
+
+ if(entry->cache != NULL)
+ instream = url_mem_open((char *)entry->cache + entry->start,
+ entry->compsize, 0);
+ else
+ {
+ if((instream = url_file_open(base)) == NULL)
+ return NULL;
+ url_seek(instream, entry->start, 0);
+ }
+
+ url = (URL_arc *)alloc_url(sizeof(URL_arc));
+ if(url == NULL)
+ {
+ url_errno = errno;
+ return NULL;
+ }
+
+ /* open decoder */
+ switch(entry->comptype)
+ {
+ case ARCHIVEC_STORED: /* No compression */
+ case ARCHIVEC_LZHED_LH0: /* -lh0- */
+ case ARCHIVEC_LZHED_LZ4: /* -lz4- */
+ url->decoder = NULL;
+
+ case ARCHIVEC_DEFLATED: /* deflate */
+ url->decoder =
+ (void *)open_inflate_handler(archiver_read_func, url);
+ if(url->decoder == NULL)
+ {
+ url_arc_close((URL)url);
+ return NULL;
+ }
+ break;
+
+ case ARCHIVEC_IMPLODED_LIT8:
+ case ARCHIVEC_IMPLODED_LIT4:
+ case ARCHIVEC_IMPLODED_NOLIT8:
+ case ARCHIVEC_IMPLODED_NOLIT4:
+ url->decoder =
+ (void *)open_explode_handler(archiver_read_func,
+ entry->comptype - ARCHIVEC_IMPLODED - 1,
+ entry->compsize, entry->origsize, url);
+ if(url->decoder == NULL)
+ {
+ url_arc_close((URL)url);
+ return NULL;
+ }
+ break;
+
+ case ARCHIVEC_LZHED_LH1: /* -lh1- */
+ case ARCHIVEC_LZHED_LH2: /* -lh2- */
+ case ARCHIVEC_LZHED_LH3: /* -lh3- */
+ case ARCHIVEC_LZHED_LH4: /* -lh4- */
+ case ARCHIVEC_LZHED_LH5: /* -lh5- */
+ case ARCHIVEC_LZHED_LZS: /* -lzs- */
+ case ARCHIVEC_LZHED_LZ5: /* -lz5- */
+ case ARCHIVEC_LZHED_LHD: /* -lhd- */
+ case ARCHIVEC_LZHED_LH6: /* -lh6- */
+ case ARCHIVEC_LZHED_LH7: /* -lh7- */
+ url->decoder =
+ (void *)open_unlzh_handler(
+ archiver_read_func,
+ lzh_methods[entry->comptype - ARCHIVEC_LZHED - 1],
+ entry->compsize, entry->origsize, url);
+ if(url->decoder == NULL)
+ {
+ url_arc_close((URL)url);
+ return NULL;
+ }
+ break;
+ default:
+ url_arc_close((URL)url);
+ return NULL;
+ }
+
+
+ /* common members */
+ URLm(url, type) = URL_arc_t;
+ URLm(url, url_read) = url_arc_read;
+ URLm(url, url_gets) = NULL;
+ URLm(url, url_fgetc) = NULL;
+ URLm(url, url_seek) = NULL;
+ URLm(url, url_tell) = url_arc_tell;
+ URLm(url, url_close) = url_arc_close;
+
+ /* private members */
+ url->instream = instream;
+ url->pos = 0;
+ url->size = entry->origsize;
+ url->comptype = entry->comptype;
+ return (URL)url;
+}
+
+static long url_arc_read(URL url, void *vp, long bufsiz)
+{
+ URL_arc *urlp = (URL_arc *)url;
+ long n = 0;
+ int comptype;
+ void *decoder;
+ char *buff = (char *)vp;
+
+ if(urlp->pos == -1)
+ return 0;
+
+ comptype = urlp->comptype;
+ decoder = urlp->decoder;
+ switch(comptype)
+ {
+ case ARCHIVEC_STORED:
+ case ARCHIVEC_LZHED_LH0: /* -lh0- */
+ case ARCHIVEC_LZHED_LZ4: /* -lz4- */
+ n = archiver_read_func(buff, bufsiz, (void *)urlp);
+ break;
+
+ case ARCHIVEC_DEFLATED:
+ n = zip_inflate((InflateHandler)decoder, buff, bufsiz);
+ break;
+
+ case ARCHIVEC_IMPLODED_LIT8:
+ case ARCHIVEC_IMPLODED_LIT4:
+ case ARCHIVEC_IMPLODED_NOLIT8:
+ case ARCHIVEC_IMPLODED_NOLIT4:
+ n = explode((ExplodeHandler)decoder, buff, bufsiz);
+ break;
+
+ case ARCHIVEC_LZHED_LH1: /* -lh1- */
+ case ARCHIVEC_LZHED_LH2: /* -lh2- */
+ case ARCHIVEC_LZHED_LH3: /* -lh3- */
+ case ARCHIVEC_LZHED_LH4: /* -lh4- */
+ case ARCHIVEC_LZHED_LH5: /* -lh5- */
+ case ARCHIVEC_LZHED_LZS: /* -lzs- */
+ case ARCHIVEC_LZHED_LZ5: /* -lz5- */
+ case ARCHIVEC_LZHED_LHD: /* -lhd- */
+ case ARCHIVEC_LZHED_LH6: /* -lh6- */
+ case ARCHIVEC_LZHED_LH7: /* -lh7- */
+ n = unlzh((UNLZHHandler)decoder, buff, bufsiz);
+ break;
+
+ case ARCHIVEC_UU: /* uu encoded */
+ case ARCHIVEC_B64: /* base64 encoded */
+ case ARCHIVEC_QS: /* quoted string encoded */
+ case ARCHIVEC_HQX: /* HQX encoded */
+ n = url_read((URL)decoder, buff, bufsiz);
+ break;
+ }
+
+ if(n > 0)
+ urlp->pos += n;
+ return n;
+}
+
+static long url_arc_tell(URL url)
+{
+ return ((URL_arc *)url)->pos;
+}
+
+static void url_arc_close(URL url)
+{
+ URL_arc *urlp = (URL_arc *)url;
+ void *decoder;
+ int save_errno = errno;
+
+ /* 1. close decoder
+ * 2. close decode_stream
+ * 3. free url
+ */
+
+ decoder = urlp->decoder;
+ if(decoder != NULL)
+ {
+ switch(urlp->comptype)
+ {
+ case ARCHIVEC_DEFLATED:
+ close_inflate_handler((InflateHandler)decoder);
+ break;
+
+ case ARCHIVEC_IMPLODED_LIT8:
+ case ARCHIVEC_IMPLODED_LIT4:
+ case ARCHIVEC_IMPLODED_NOLIT8:
+ case ARCHIVEC_IMPLODED_NOLIT4:
+ close_explode_handler((ExplodeHandler)decoder);
+ break;
+
+ case ARCHIVEC_LZHED_LH1: /* -lh1- */
+ case ARCHIVEC_LZHED_LH2: /* -lh2- */
+ case ARCHIVEC_LZHED_LH3: /* -lh3- */
+ case ARCHIVEC_LZHED_LH4: /* -lh4- */
+ case ARCHIVEC_LZHED_LH5: /* -lh5- */
+ case ARCHIVEC_LZHED_LZS: /* -lzs- */
+ case ARCHIVEC_LZHED_LZ5: /* -lz5- */
+ case ARCHIVEC_LZHED_LHD: /* -lhd- */
+ case ARCHIVEC_LZHED_LH6: /* -lh6- */
+ case ARCHIVEC_LZHED_LH7: /* -lh7- */
+ close_unlzh_handler((UNLZHHandler)decoder);
+ break;
+
+ case ARCHIVEC_UU: /* uu encoded */
+ case ARCHIVEC_B64: /* base64 encoded */
+ case ARCHIVEC_QS: /* quoted string encoded */
+ case ARCHIVEC_HQX: /* HQX encoded */
+ url_close((URL)decoder);
+ break;
+ }
+ }
+
+ if(urlp->instream != NULL)
+ url_close(urlp->instream);
+ free(urlp);
+ errno = save_errno;
+}
+
+
+
+/************** wildmat ***************/
+/* What character marks an inverted character class? */
+#define NEGATE_CLASS '!'
+
+/* Is "*" a common pattern? */
+#define OPTIMIZE_JUST_STAR
+
+/* Do tar(1) matching rules, which ignore a trailing slash? */
+#undef MATCH_TAR_PATTERN
+
+/* Define if case is ignored */
+#define MATCH_CASE_IGNORE
+
+#include <ctype.h>
+#define TEXT_CASE_CHAR(c) (toupper(c))
+#define CHAR_CASE_COMP(a, b) (TEXT_CASE_CHAR(a) == TEXT_CASE_CHAR(b))
+
+static char *ParseHex(char *p, int *val)
+{
+ int i, v;
+
+ *val = 0;
+ for(i = 0; i < 2; i++)
+ {
+ v = *p++;
+ if('0' <= v && v <= '9')
+ v = v - '0';
+ else if('A' <= v && v <= 'F')
+ v = v - 'A' + 10;
+ else if('a' <= v && v <= 'f')
+ v = v - 'a' + 10;
+ else
+ return NULL;
+ *val = (*val << 4 | v);
+ }
+ return p;
+}
+
+/*
+ * Match text and p, return TRUE, FALSE, or ABORT.
+ */
+static int DoMatch(char *text, char *p)
+{
+ register int last;
+ register int matched;
+ register int reverse;
+
+ for ( ; *p; text++, p++) {
+ if (*text == '\0' && *p != '*')
+ return ABORT;
+ switch (*p) {
+ case '\\':
+ p++;
+ if(*p == 'x')
+ {
+ int c;
+ if((p = ParseHex(++p, &c)) == NULL)
+ return ABORT;
+ if(*text != c)
+ return FALSE;
+ continue;
+ }
+ /* Literal match with following character. */
+
+ /* FALLTHROUGH */
+ default:
+ if (*text != *p)
+ return FALSE;
+ continue;
+ case '?':
+ /* Match anything. */
+ continue;
+ case '*':
+ while (*++p == '*')
+ /* Consecutive stars act just like one. */
+ continue;
+ if (*p == '\0')
+ /* Trailing star matches everything. */
+ return TRUE;
+ while (*text)
+ if ((matched = DoMatch(text++, p)) != FALSE)
+ return matched;
+ return ABORT;
+ case '[':
+ reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE;
+ if (reverse)
+ /* Inverted character class. */
+ p++;
+ matched = FALSE;
+ if (p[1] == ']' || p[1] == '-')
+ if (*++p == *text)
+ matched = TRUE;
+ for (last = *p; *++p && *p != ']'; last = *p)
+ /* This next line requires a good C compiler. */
+ if (*p == '-' && p[1] != ']'
+ ? *text <= *++p && *text >= last : *text == *p)
+ matched = TRUE;
+ if (matched == reverse)
+ return FALSE;
+ continue;
+ }
+ }
+
+#ifdef MATCH_TAR_PATTERN
+ if (*text == '/')
+ return TRUE;
+#endif /* MATCH_TAR_ATTERN */
+ return *text == '\0';
+}
+
+static int DoCaseMatch(char *text, char *p)
+{
+ register int last;
+ register int matched;
+ register int reverse;
+
+ for(; *p; text++, p++)
+ {
+ if(*text == '\0' && *p != '*')
+ return ABORT;
+ switch (*p)
+ {
+ case '\\':
+ p++;
+ if(*p == 'x')
+ {
+ int c;
+ if((p = ParseHex(++p, &c)) == NULL)
+ return ABORT;
+ if(!CHAR_CASE_COMP(*text, c))
+ return FALSE;
+ continue;
+ }
+ /* Literal match with following character. */
+
+ /* FALLTHROUGH */
+ default:
+ if(!CHAR_CASE_COMP(*text, *p))
+ return FALSE;
+ continue;
+ case '?':
+ /* Match anything. */
+ continue;
+ case '*':
+ while(*++p == '*')
+ /* Consecutive stars act just like one. */
+ continue;
+ if(*p == '\0')
+ /* Trailing star matches everything. */
+ return TRUE;
+ while(*text)
+ if((matched = DoCaseMatch(text++, p)) != FALSE)
+ return matched;
+ return ABORT;
+ case '[':
+ reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE;
+ if(reverse)
+ /* Inverted character class. */
+ p++;
+ matched = FALSE;
+ if(p[1] == ']' || p[1] == '-')
+ {
+ if(*++p == *text)
+ matched = TRUE;
+ }
+ for(last = TEXT_CASE_CHAR(*p); *++p && *p != ']';
+ last = TEXT_CASE_CHAR(*p))
+ {
+ /* This next line requires a good C compiler. */
+ if(*p == '-' && p[1] != ']')
+ {
+ p++;
+ if(TEXT_CASE_CHAR(*text) <= TEXT_CASE_CHAR(*p) &&
+ TEXT_CASE_CHAR(*text) >= last)
+ matched = TRUE;
+ }
+ else
+ {
+ if(CHAR_CASE_COMP(*text, *p))
+ matched = TRUE;
+ }
+ }
+ if(matched == reverse)
+ return FALSE;
+ continue;
+ }
+ }
+
+#ifdef MATCH_TAR_PATTERN
+ if (*text == '/')
+ return TRUE;
+#endif /* MATCH_TAR_ATTERN */
+ return *text == '\0';
+}
+
+/*
+** User-level routine. Returns TRUE or FALSE.
+*/
+int arc_wildmat(char *text, char *p)
+{
+#ifdef OPTIMIZE_JUST_STAR
+ if (p[0] == '*' && p[1] == '\0')
+ return TRUE;
+#endif /* OPTIMIZE_JUST_STAR */
+ return DoMatch(text, p) == TRUE;
+}
+
+int arc_case_wildmat(char *text, char *p)
+{
+#ifdef OPTIMIZE_JUST_STAR
+ if (p[0] == '*' && p[1] == '\0')
+ return TRUE;
+#endif /* OPTIMIZE_JUST_STAR */
+ return DoCaseMatch(text, p) == TRUE;
+}
diff --git a/lib/timidity/libarc/arc.h b/lib/timidity/libarc/arc.h
new file mode 100644
index 0000000000..3ca28c26b1
--- /dev/null
+++ b/lib/timidity/libarc/arc.h
@@ -0,0 +1,143 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifndef ___LIBARC_H_
+#define ___LIBARC_H_
+
+/* Archive library */
+
+#include "url.h"
+#include "mblock.h"
+
+#define ARC_LIB_VERSION "2.0.1"
+#define ARC_DEFLATE_LEVEL 6 /* 1:Compress faster .. 9:Compress better */
+#define ARC_ENTRY_HASHSIZE 63
+
+
+
+/*
+ * Interfaces
+ */
+
+extern char **expand_archive_names(int *nfiles_in_out, char **files);
+/* Regist all archive files in `files_in_out', and expand the archive */
+
+extern URL url_arc_open(char *name);
+/* Open input stream from archive. `name' format must be "filename#entry".
+ */
+
+extern void free_archive_files(void);
+/* Call once at the last */
+
+/* utilities */
+extern int skip_gzip_header(URL url);
+extern int parse_gzip_header_bytes(char *gz, long maxparse, int *hdrsiz);
+extern int get_archive_type(char *archive_name);
+extern void *arc_compress(void *buff, long bufsiz,
+ int compress_level, long *compressed_size);
+extern void *arc_decompress(void *buff, long bufsiz, long *decompressed_size);
+extern int arc_case_wildmat(char *text, char *p);
+extern int arc_wildmat(char *text, char *p);
+extern void (* arc_error_handler)(char *error_message);
+
+
+/*
+ * Internal library usage only
+ */
+typedef struct _ArchiveEntryNode
+{
+ struct _ArchiveEntryNode *next; /* next entry */
+ char *name; /* Name of this entry */
+
+ int comptype; /* Compression/Encoding type */
+ long compsize; /* Compressed size */
+ long origsize; /* Uncompressed size */
+ long start; /* Offset start point */
+ void *cache; /* Cached data */
+} ArchiveEntryNode;
+
+typedef struct _ArchiveHandler {
+ int isfile;
+ URL url; /* Input stream */
+ int counter;/* counter to extract the entry*/
+ long pos;
+} ArchiveHandler;
+
+extern ArchiveHandler arc_handler;
+extern ArchiveEntryNode *arc_parse_entry(URL url, int archive_type);
+extern ArchiveEntryNode *new_entry_node(char *name, int len);
+extern ArchiveEntryNode *next_tar_entry(void);
+extern ArchiveEntryNode *next_zip_entry(void);
+extern ArchiveEntryNode *next_lzh_entry(void);
+extern ArchiveEntryNode *next_mime_entry(void);
+extern void free_entry_node(ArchiveEntryNode *entry);
+
+/* Compression/Encoding type */
+enum
+{
+ ARCHIVEC_STORED, /* No compression */
+ ARCHIVEC_PATHNAME, /* Pathname (Contents exists there) */
+ ARCHIVEC_COMPRESSED, /* Compressed */
+ ARCHIVEC_PACKED, /* Packed */
+ ARCHIVEC_DEFLATED, /* Deflate */
+ ARCHIVEC_SHRUNKED, /* Shrunked */
+ ARCHIVEC_REDUCED1, /* Reduced with compression factor 1 */
+ ARCHIVEC_REDUCED2, /* Reduced with compression factor 2 */
+ ARCHIVEC_REDUCED3, /* Reduced with compression factor 3 */
+ ARCHIVEC_REDUCED4, /* Reduced with compression factor 4 */
+ ARCHIVEC_IMPLODED, /* Implode base-tag */
+ ARCHIVEC_IMPLODED_LIT8, /* 8K sliding window (coded) */
+ ARCHIVEC_IMPLODED_LIT4, /* 4K sliding window (coded) */
+ ARCHIVEC_IMPLODED_NOLIT8, /* 8K sliding window (uncoded) */
+ ARCHIVEC_IMPLODED_NOLIT4, /* 4K sliding window (uncoded) */
+ ARCHIVEC_LZHED, /* LZH base-tag */
+ ARCHIVEC_LZHED_LH0, /* -lh0- (ARCHIVE_STORED) */
+ ARCHIVEC_LZHED_LH1, /* -lh1- */
+ ARCHIVEC_LZHED_LH2, /* -lh2- */
+ ARCHIVEC_LZHED_LH3, /* -lh3- */
+ ARCHIVEC_LZHED_LH4, /* -lh4- */
+ ARCHIVEC_LZHED_LH5, /* -lh5- */
+ ARCHIVEC_LZHED_LZS, /* -lzs- */
+ ARCHIVEC_LZHED_LZ5, /* -lz5- */
+ ARCHIVEC_LZHED_LZ4, /* -lz4- (ARCHIVE_STORED) */
+ ARCHIVEC_LZHED_LHD, /* -lhd- (Directory, No compression data) */
+ ARCHIVEC_LZHED_LH6, /* -lh6- */
+ ARCHIVEC_LZHED_LH7, /* -lh7- */
+
+ /* Encode for MIME */
+ ARCHIVEC_UU, /* uu encoded */
+ ARCHIVEC_B64, /* base64 encoded */
+ ARCHIVEC_QS, /* quoted string encoded */
+ ARCHIVEC_HQX /* HQX encoded */
+};
+
+/* archive_type */
+enum
+{
+ ARCHIVE_TAR,
+ ARCHIVE_TGZ,
+ ARCHIVE_ZIP,
+ ARCHIVE_LZH,
+ ARCHIVE_DIR,
+ ARCHIVE_MIME,
+ ARCHIVE_NEWSGROUP
+};
+
+#endif /* ___LIBARC_H_ */
diff --git a/lib/timidity/libarc/arc_lzh.c b/lib/timidity/libarc/arc_lzh.c
new file mode 100644
index 0000000000..097649d0ba
--- /dev/null
+++ b/lib/timidity/libarc/arc_lzh.c
@@ -0,0 +1,552 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include <ctype.h>
+#include "timidity.h"
+#include "arc.h"
+
+#define boolean int
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+#define DELIM ('/')
+#define DELIM2 (0xff)
+#define LZHEADER_STRAGE 4096
+#define FILENAME_LENGTH 1024
+
+#define I_HEADER_SIZE 0
+#define I_HEADER_CHECKSUM 1
+#define I_METHOD 2
+#define I_PACKED_SIZE 7
+#define I_ORIGINAL_SIZE 11
+#define I_LAST_MODIFIED_STAMP 15
+#define I_ATTRIBUTE 19
+#define I_HEADER_LEVEL 20
+#define I_NAME_LENGTH 21
+#define I_NAME 22
+
+#define EXTEND_GENERIC 0
+#define EXTEND_UNIX 'U'
+#define EXTEND_MSDOS 'M'
+#define EXTEND_MACOS 'm'
+#define EXTEND_OS9 '9'
+#define EXTEND_OS2 '2'
+#define EXTEND_OS68K 'K'
+#define EXTEND_OS386 '3' /* OS-9000??? */
+#define EXTEND_HUMAN 'H'
+#define EXTEND_CPM 'C'
+#define EXTEND_FLEX 'F'
+#define EXTEND_RUNSER 'R'
+/* this OS type is not official */
+#define EXTEND_TOWNSOS 'T'
+#define EXTEND_XOSK 'X'
+
+static char *get_ptr;
+#define setup_get(PTR) (get_ptr = (PTR))
+#define get_byte() (*get_ptr++ & 0xff)
+#define skip_byte() get_ptr++
+
+static unsigned short get_word(void)
+{
+ int b0, b1;
+
+ b0 = get_byte();
+ b1 = get_byte();
+ return (b1 << 8) + b0;
+}
+
+static long get_longword(void)
+{
+ long b0, b1, b2, b3;
+
+ b0 = get_byte();
+ b1 = get_byte();
+ b2 = get_byte();
+ b3 = get_byte();
+ return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
+}
+
+static void msdos_to_unix_filename(char *name, int len)
+{
+ int i;
+
+#ifdef MULTIBYTE_CHAR
+ for(i = 0; i < len; i ++)
+ {
+ int c1, c2;
+ c1 = (int)(unsigned char)name[i];
+ c2 = (int)(unsigned char)name[i+1];
+ if(MULTIBYTE_FIRST_P(c1) && MULTIBYTE_SECOND_P(c2))
+ i++;
+ else if(c1 == '\\')
+ name[i] = '/';
+ else if(isupper(c1))
+ name[i] = tolower(c1);
+ }
+#else
+ for(i = 0; i < len; i ++)
+ {
+ int c;
+ c = (int)(unsigned char)name[i];
+ if(c == '\\')
+ name[i] = '/';
+ else if(isupper(c))
+ name[i] = tolower(c);
+ }
+#endif
+}
+
+static void generic_to_unix_filename(char *name, int len)
+{
+ register int i;
+ boolean lower_case_used = FALSE;
+
+#ifdef MULTIBYTE_CHAR
+ for(i = 0; i < len; i ++)
+ {
+ int c1, c2;
+ c1 = (int)(unsigned char)name[i];
+ c2 = (int)(unsigned char)name[i+1];
+ if(MULTIBYTE_FIRST_P(c1) && MULTIBYTE_SECOND_P(c2))
+ i ++;
+ else if(islower(c1))
+ {
+ lower_case_used = TRUE;
+ break;
+ }
+ }
+ for(i = 0; i < len; i ++)
+ {
+ int c1, c2;
+ c1 = (int)(unsigned char)name[i];
+ c2 = (int)(unsigned char)name[i+1];
+ if(MULTIBYTE_FIRST_P(c1) && MULTIBYTE_SECOND_P(c2))
+ i++;
+ else if(c1 == '\\')
+ name[i] = '/';
+ else if(!lower_case_used && isupper(c1))
+ name[i] = tolower(c1);
+ }
+#else
+ for(i = 0; i < len; i ++)
+ {
+ int c;
+ c = (int)(unsigned char)name[i];
+ if(islower(c))
+ {
+ lower_case_used = TRUE;
+ break;
+ }
+ }
+ for(i = 0; i < len; i ++)
+ {
+ int c;
+ c = (int)(unsigned char)name[i];
+ if(c == '\\')
+ name[i] = '/';
+ else if(!lower_case_used && isupper(c))
+ name[i] = tolower(c);
+ }
+#endif
+}
+
+static void macos_to_unix_filename(char *name, int len)
+{
+ register int i;
+
+ for(i = 0; i < len; i ++)
+ {
+ if(name[i] == ':')
+ name[i] = '/';
+ else if(name[i] == '/')
+ name[i] = ':';
+ }
+}
+
+#ifdef MULTIBYTE_CHAR
+#define iskanji(c) (c & 0x80)
+#endif /* MULTIBYTE_CHAR */
+static unsigned char *convdelim(unsigned char *path, unsigned char delim)
+{
+ unsigned char c;
+ unsigned char *p;
+#ifdef MULTIBYTE_CHAR
+ int kflg;
+
+ kflg = 0;
+#endif
+ for(p = path; (c = *p) != 0; p++)
+ {
+#ifdef MULTIBYTE_CHAR
+ if(kflg)
+ {
+ kflg = 0;
+ }
+ else if(iskanji(c))
+ {
+ kflg = 1;
+ }
+ else
+#endif
+ if(c == '\\' || c == DELIM || c == DELIM2)
+ {
+ *p = delim;
+ path = p + 1;
+ }
+ }
+ return path;
+}
+
+ArchiveEntryNode *next_lzh_entry(void)
+{
+ ArchiveEntryNode *entry;
+ URL url;
+ int header_size;
+ char data[LZHEADER_STRAGE];
+ char dirname[FILENAME_LENGTH];
+ char filename[FILENAME_LENGTH];
+ int dir_length, name_length;
+ int i;
+ char *ptr;
+ int header_level;
+ char method_id[5];
+ long compsize, origsize;
+ int extend_type;
+ int hdrsiz;
+ int macbin_check;
+ extern char *lzh_methods[];
+
+ url = arc_handler.url;
+ macbin_check = (arc_handler.counter == 0);
+
+ retry_read:
+ dir_length = 0;
+ name_length = 0;
+#if 0
+ if((header_size = url_getc(url)) == EOF)
+ return NULL;
+ if(header_size == 0)
+ {
+ if(macbin_check)
+ {
+ macbin_check = 0;
+ url_skip(url, 128-1);
+ if(arc_handler.isfile)
+ arc_handler.pos += 128;
+ goto retry_read;
+ }
+ return NULL;
+ }
+
+ macbin_check = 0;
+ if(url_read(url, data + I_HEADER_CHECKSUM,
+ header_size - 1) < header_size - 1)
+ return NULL;
+#else /* a little cleverer lzh check */
+ if(macbin_check){
+/* for(i=0;i<LZHEADER_STRAGE;i++){ */
+ for(i=0;i<1024;i++){
+ if((header_size = url_getc(url)) == EOF)
+ return NULL;
+ *(data + i) = header_size;
+ if(i >= 6){
+ if(*(data + i - 4) == '-'
+ && *(data + i - 3) == 'l'
+ && *(data + i - 2) == 'h'
+ && *(data + i - 0) == '-')
+ {
+ int j;
+ if(arc_handler.isfile)
+ arc_handler.pos += i - 6;
+ for(j = 0; j<= 6; j++)
+ *(data + j) = *(data + i - 6 + j);
+ header_size = (int)(unsigned char)(*(data + i - 6));
+ if(header_size == 0)
+ return NULL;
+ if(url_read(url, data + 7, header_size - 7) < header_size - 7)
+ return NULL;
+ break;
+ }
+ }
+ }
+ if(i >= LZHEADER_STRAGE)
+ return NULL;
+ } else {
+ if((header_size = url_getc(url)) == EOF)
+ return NULL;
+ if(url_read(url, data + I_HEADER_CHECKSUM,
+ header_size - 1) < header_size - 1)
+ return NULL;
+ }
+ macbin_check = 0;
+#endif
+ hdrsiz = header_size;
+ setup_get(data + I_HEADER_LEVEL);
+ header_level = get_byte();
+
+ if(header_level != 2)
+ {
+ if(url_read(url, data + header_size, 2) < 2)
+ return NULL;
+ hdrsiz += 2;
+ }
+
+ setup_get(data + I_HEADER_CHECKSUM);
+ skip_byte(); /* checksum */
+
+ memcpy(method_id, data + I_METHOD, sizeof(method_id));
+
+ setup_get(data + I_PACKED_SIZE);
+ compsize = get_longword();
+ origsize = get_longword();
+ get_longword(); /* last_modified_stamp */
+ skip_byte(); /* attribute */
+
+ if((header_level = get_byte()) != 2)
+ {
+ name_length = get_byte();
+ for(i = 0; i < name_length; i ++)
+ filename[i] =(char)get_byte();
+ filename[name_length] = '\0';
+ }
+
+ if(header_size - name_length >= 24)
+ { /* EXTEND FORMAT */
+ get_word(); /* crc */
+ extend_type = get_byte();
+ }
+ else if(header_size - name_length == 22)
+ { /* Generic with CRC */
+ get_word(); /* crc */
+ extend_type = EXTEND_GENERIC;
+ }
+ else if(header_size - name_length == 20)
+ { /* Generic no CRC */
+ extend_type = EXTEND_GENERIC;
+ }
+ else
+ return NULL;
+
+ if(extend_type == EXTEND_UNIX && header_level == 0)
+ {
+ skip_byte(); /* minor_version */
+ get_longword(); /* unix_last_modified_stamp */
+ get_word(); /* unix_mode */
+ get_word(); /* unix_uid */
+ get_word(); /* unix_gid */
+ goto parse_ok;
+ }
+
+ if(header_level > 0)
+ {
+ /* Extend Header */
+ if(header_level != 2)
+ setup_get(data + header_size);
+ ptr = get_ptr;
+ while((header_size = get_word()) != 0)
+ {
+ if(header_level != 2)
+ {
+ if(data + LZHEADER_STRAGE - get_ptr < header_size)
+ return NULL;
+ if(url_read(url, get_ptr, header_size) < header_size)
+ return NULL;
+ hdrsiz += header_size;
+ }
+
+ switch(get_byte())
+ {
+ case 0:
+ /*
+ * header crc
+ */
+ setup_get(get_ptr + header_size - 3);
+ break;
+ case 1:
+ /*
+ * filename
+ */
+ name_length = header_size - 3;
+ if(name_length >= sizeof(filename) - 1)
+ return NULL;
+ for(i = 0; i < name_length; i++)
+ filename[i] =(char)get_byte ();
+ filename[name_length] = '\0';
+ break;
+ case 2:
+ /*
+ * directory
+ */
+ dir_length = header_size - 3;
+ if(dir_length >= sizeof(dirname) - 1)
+ return NULL;
+ for(i = 0; i < dir_length; i++)
+ dirname[i] = (char)get_byte ();
+ dirname[dir_length] = '\0';
+ convdelim((unsigned char *)dirname, DELIM);
+ break;
+ case 0x40:
+ /*
+ * MS-DOS attribute
+ */
+ if(extend_type == EXTEND_MSDOS ||
+ extend_type == EXTEND_HUMAN ||
+ extend_type == EXTEND_GENERIC)
+ get_word(); /* attribute */
+ break;
+ case 0x50:
+ /*
+ * UNIX permission
+ */
+ if(extend_type == EXTEND_UNIX)
+ get_word(); /* unix_mode */
+ break;
+ case 0x51:
+ /*
+ * UNIX gid and uid
+ */
+ if(extend_type == EXTEND_UNIX)
+ {
+ get_word(); /* unix_gid */
+ get_word(); /* unix_uid */
+ }
+ break;
+ case 0x52:
+ /*
+ * UNIX group name
+ */
+ setup_get(get_ptr + header_size - 3);
+ break;
+ case 0x53:
+ /*
+ * UNIX user name
+ */
+ setup_get(get_ptr + header_size - 3);
+ break;
+ case 0x54:
+ /*
+ * UNIX last modified time
+ */
+ if(extend_type == EXTEND_UNIX)
+ get_longword(); /* unix_last_modified_stamp */
+ break;
+ default:
+ /*
+ * other headers
+ */
+ setup_get(get_ptr + header_size - 3);
+ break;
+ }
+ }
+ if(header_level != 2 && get_ptr - ptr != 2)
+ {
+ compsize -= get_ptr - ptr - 2;
+ header_size += get_ptr - ptr - 2;
+ }
+ }
+
+ if(dir_length)
+ {
+ name_length += dir_length;
+ if(name_length >= sizeof(filename) - 1)
+ return NULL;
+ strcat(dirname, filename);
+ strcpy(filename, dirname);
+ }
+
+ switch(extend_type)
+ {
+ case EXTEND_MSDOS:
+ msdos_to_unix_filename(filename, name_length);
+ case EXTEND_HUMAN:
+ ; /* ignored */
+ break;
+
+#ifdef OSK
+ case EXTEND_OS68K:
+ case EXTEND_XOSK:
+#endif
+ case EXTEND_UNIX:
+ break;
+
+ case EXTEND_MACOS:
+ macos_to_unix_filename(filename, name_length);
+ break;
+
+ default:
+ generic_to_unix_filename(filename, name_length);
+ }
+
+ parse_ok:
+ if(strncmp("-lhd-", method_id, 5) == 0)
+ {
+ if(arc_handler.isfile)
+ arc_handler.pos += hdrsiz;
+ goto retry_read; /* Skip directory entry */
+ }
+
+ for(i = 0; lzh_methods[i]; i++)
+ if(strncmp(method_id, lzh_methods[i], sizeof(method_id)) == 0)
+ break;
+ if(!lzh_methods[i])
+ return NULL;
+ entry = new_entry_node(filename, name_length);
+ if(entry == NULL)
+ return NULL;
+ entry->comptype = i + ARCHIVEC_LZHED + 1;
+ entry->compsize = compsize;
+ entry->origsize = origsize;
+
+ if(arc_handler.isfile)
+ {
+ arc_handler.pos += hdrsiz;
+ entry->start = arc_handler.pos;
+ entry->cache = NULL;
+ url_skip(url, compsize);
+ arc_handler.pos += compsize;
+ }
+ else
+ {
+ long n;
+ entry->start = 0;
+ entry->cache = url_dump(url, compsize, &n);
+ if(n != compsize)
+ {
+ free_entry_node(entry);
+ return NULL;
+ }
+ }
+ return entry;
+}
diff --git a/lib/timidity/libarc/arc_mime.c b/lib/timidity/libarc/arc_mime.c
new file mode 100644
index 0000000000..e101ebcbc7
--- /dev/null
+++ b/lib/timidity/libarc/arc_mime.c
@@ -0,0 +1,647 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "timidity.h"
+#include "mblock.h"
+#include "zip.h"
+#include "arc.h"
+
+extern char *safe_strdup(const char *);
+
+#ifndef MAX_CHECK_LINES
+#define MAX_CHECK_LINES 1024
+#endif /* MAX_CHECK_LINES */
+
+struct StringStackElem
+{
+ struct StringStackElem *next;
+ char str[1]; /* variable length */
+};
+
+struct StringStack
+{
+ struct StringStackElem *elem;
+ MBlockList pool;
+};
+
+static void init_string_stack(struct StringStack *stk);
+static void push_string_stack(struct StringStack *stk, char *str, int len);
+static char *top_string_stack(struct StringStack *stk);
+static void pop_string_stack(struct StringStack *stk);
+static void delete_string_stack(struct StringStack *stk);
+
+struct MIMEHeaderStream
+{
+ URL url;
+ char *field;
+ char *value;
+ char *line;
+ int bufflen;
+ int eof;
+ MBlockList pool;
+};
+
+static void init_mime_stream(struct MIMEHeaderStream *hdr, URL url);
+static int next_mime_header(struct MIMEHeaderStream *hdr);
+static void end_mime_stream(struct MIMEHeaderStream *hdr);
+static int seek_next_boundary(URL url, char *boundary, long *endpoint);
+static int whole_read_line(URL url, char *buff, int bufsiz);
+static void *arc_mime_decode(void *data, long size,
+ int comptype, long *newsize);
+
+ArchiveEntryNode *next_mime_entry(void)
+{
+ ArchiveEntryNode *head, *tail;
+ URL url;
+ int part;
+ struct StringStack boundary;
+ struct MIMEHeaderStream hdr;
+ int c;
+
+ if(arc_handler.counter != 0)
+ return NULL;
+
+ head = tail = NULL;
+ url = arc_handler.url; /* url_seek must be safety */
+
+ init_string_stack(&boundary);
+ url_rewind(url);
+ c = url_getc(url);
+ if(c != '\0')
+ url_rewind(url);
+ else
+ url_skip(url, 128-1); /* skip macbin header */
+
+ part = 1;
+ for(;;)
+ {
+ char *new_boundary, *encoding, *name, *filename;
+ char *p;
+ MBlockList pool;
+ long data_start, data_end, savepoint;
+ int last_check, comptype, arctype;
+ void *part_data;
+ long part_data_size;
+
+ new_boundary = encoding = name = filename = NULL;
+ init_mblock(&pool);
+ init_mime_stream(&hdr, url);
+ while(next_mime_header(&hdr))
+ {
+ if(strncmp(hdr.field, "Content-", 8) != 0)
+ continue;
+ if(strcmp(hdr.field + 8, "Type") == 0)
+ {
+ if((p = strchr(hdr.value, ';')) == NULL)
+ continue;
+ *p++ = '\0';
+ while(*p == ' ')
+ p++;
+ if(strncasecmp(hdr.value, "multipart/mixed", 15) == 0)
+ {
+ /* Content-Type: multipart/mixed; boundary="XXXX" */
+ if(strncasecmp(p, "boundary=", 9) == 0)
+ {
+ p += 9;
+ if(*p == '"')
+ {
+ p++;
+ new_boundary = p;
+ if((p = strchr(p, '"')) == NULL)
+ continue;
+ }
+ else
+ {
+ new_boundary = p;
+ while(*p > '"' && *p < 0x7f)
+ p++;
+ }
+
+ *p = '\0';
+ new_boundary = strdup_mblock(&pool, new_boundary);
+ }
+ }
+ else if(strcasecmp(hdr.value, "multipart/mixed") == 0)
+ {
+ /* Content-Type: XXXX/YYYY; name="ZZZZ" */
+ if(strncasecmp(p, "name=\"", 6) == 0)
+ {
+ p += 6;
+ name = p;
+ if((p = strchr(p, '"')) == NULL)
+ continue;
+ *p = '\0';
+ name = strdup_mblock(&pool, name);
+ }
+ }
+ }
+ else if(strcmp(hdr.field + 8, "Disposition") == 0)
+ {
+ if((p = strchr(hdr.value, ';')) == NULL)
+ continue;
+ *p++ = '\0';
+ while(*p == ' ')
+ p++;
+ if((p = strstr(p, "filename=\"")) == NULL)
+ continue;
+ p += 10;
+ filename = p;
+ if((p = strchr(p, '"')) == NULL)
+ continue;
+ *p = '\0';
+ filename = strdup_mblock(&pool, filename);
+ }
+ else if(strcmp(hdr.field + 8, "Transfer-Encoding") == 0)
+ {
+ /* Content-Transfer-Encoding: X */
+ /* X := X-uuencode, base64, quoted-printable, ... */
+ encoding = strdup_mblock(&pool, hdr.value);
+ }
+ }
+
+ if(hdr.eof)
+ {
+ reuse_mblock(&pool);
+ end_mime_stream(&hdr);
+ delete_string_stack(&boundary);
+ return head;
+ }
+
+ if(filename == NULL)
+ filename = name;
+
+ if(new_boundary)
+ push_string_stack(&boundary, new_boundary, strlen(new_boundary));
+
+ data_start = url_tell(url);
+ last_check = seek_next_boundary(url, top_string_stack(&boundary),
+ &data_end);
+
+ savepoint = url_tell(url);
+
+ /* find data type */
+ comptype = -1;
+ if(encoding != NULL)
+ {
+ if(strcmp("base64", encoding) == 0)
+ comptype = ARCHIVEC_B64;
+ else if(strcmp("quoted-printable", encoding) == 0)
+ comptype = ARCHIVEC_QS;
+ else if(strcmp("X-uuencode", encoding) == 0)
+ {
+ char buff[BUFSIZ];
+ int i;
+
+ comptype = ARCHIVEC_UU;
+ url_seek(url, data_start, SEEK_SET);
+ url_set_readlimit(url, data_end - data_start);
+
+ /* find '^begin \d\d\d \S+' */
+ for(i = 0; i < MAX_CHECK_LINES; i++)
+ {
+ if(whole_read_line(url, buff, sizeof(buff)) == -1)
+ break; /* ?? */
+ if(strncmp(buff, "begin ", 6) == 0)
+ {
+ data_start = url_tell(url);
+ p = strchr(buff + 6, ' ');
+ if(p != NULL)
+ filename = strdup_mblock(&pool, p + 1);
+ break;
+ }
+ }
+ url_set_readlimit(url, -1);
+ }
+ }
+
+ if(comptype == -1)
+ {
+ char buff[BUFSIZ];
+ int i;
+
+ url_seek(url, data_start, SEEK_SET);
+ url_set_readlimit(url, data_end - data_start);
+
+ for(i = 0; i < MAX_CHECK_LINES; i++)
+ {
+ if(whole_read_line(url, buff, sizeof(buff)) == -1)
+ break; /* ?? */
+ if(strncmp(buff, "begin ", 6) == 0)
+ {
+ comptype = ARCHIVEC_UU;
+ data_start = url_tell(url);
+ p = strchr(buff + 6, ' ');
+ if(p != NULL)
+ filename = strdup_mblock(&pool, p + 1);
+ break;
+ }
+ else if((strncmp(buff, "(This file", 10) == 0) ||
+ (strncmp(buff, "(Convert with", 13) == 0))
+ {
+ int c;
+ while((c = url_getc(url)) != EOF)
+ {
+ if(c == ':')
+ {
+ comptype = ARCHIVEC_HQX;
+ data_start = url_tell(url);
+ break;
+ }
+ else if(c == '\n')
+ {
+ if(++i >= MAX_CHECK_LINES)
+ break;
+ }
+ }
+ if(comptype != -1)
+ break;
+ }
+ }
+ url_set_readlimit(url, -1);
+ }
+
+ if(comptype == -1)
+ comptype = ARCHIVEC_STORED;
+
+ if(filename == NULL)
+ {
+ char buff[32];
+ sprintf(buff, "part%d", part);
+ filename = strdup_mblock(&pool, buff);
+ arctype = -1;
+ }
+ else
+ {
+ arctype = get_archive_type(filename);
+ switch(arctype)
+ {
+ case ARCHIVE_TAR:
+ case ARCHIVE_TGZ:
+ case ARCHIVE_ZIP:
+ case ARCHIVE_LZH:
+ break;
+ default:
+ arctype = -1;
+ break;
+ }
+ }
+
+ if(data_start == data_end)
+ {
+ ArchiveEntryNode *entry;
+ entry = new_entry_node(filename, strlen(filename));
+ entry->comptype = ARCHIVEC_STORED;
+ entry->compsize = 0;
+ entry->origsize = 0;
+ entry->start = 0;
+ entry->cache = safe_strdup("");
+ if(head == NULL)
+ head = tail = entry;
+ else
+ tail = tail->next = entry;
+ goto next_entry;
+ }
+
+ url_seek(url, data_start, SEEK_SET);
+ part_data = url_dump(url, data_end - data_start, &part_data_size);
+ part_data = arc_mime_decode(part_data, part_data_size,
+ comptype, &part_data_size);
+ if(part_data == NULL)
+ goto next_entry;
+
+ if(arctype == -1)
+ {
+ int gzmethod, gzhdrsiz, len, gz;
+ ArchiveEntryNode *entry;
+
+ len = strlen(filename);
+ if(len >= 3 && strcasecmp(filename + len - 3, ".gz") == 0)
+ {
+ gz = 1;
+ filename[len - 3] = '\0';
+ }
+ else
+ gz = 0;
+ entry = new_entry_node(filename, strlen(filename));
+
+ if(gz)
+ gzmethod = parse_gzip_header_bytes(part_data, part_data_size,
+ &gzhdrsiz);
+ else
+ gzmethod = -1;
+ if(gzmethod == ARCHIVEC_DEFLATED)
+ {
+ entry->comptype = ARCHIVEC_DEFLATED;
+ entry->compsize = part_data_size - gzhdrsiz;
+ entry->origsize = -1;
+ entry->start = gzhdrsiz;
+ entry->cache = part_data;
+ }
+ else
+ {
+ entry->comptype = ARCHIVEC_DEFLATED;
+ entry->origsize = part_data_size;
+ entry->start = 0;
+ entry->cache = arc_compress(part_data, part_data_size,
+ ARC_DEFLATE_LEVEL, &entry->compsize);
+ free(part_data);
+ if(entry->cache == NULL)
+ {
+ free_entry_node(entry);
+ goto next_entry;
+ }
+ }
+ if(head == NULL)
+ head = tail = entry;
+ else
+ tail = tail->next = entry;
+ }
+ else
+ {
+ URL arcurl;
+ ArchiveEntryNode *entry;
+ ArchiveHandler orig;
+
+ arcurl = url_mem_open(part_data, part_data_size, 1);
+ orig = arc_handler; /* save */
+ entry = arc_parse_entry(arcurl, arctype);
+ arc_handler = orig; /* restore */
+ if(head == NULL)
+ head = tail = entry;
+ else
+ tail = tail->next = entry;
+ while(tail->next)
+ tail = tail->next;
+ }
+
+ next_entry:
+ url_seek(url, savepoint, SEEK_SET);
+ part++;
+ reuse_mblock(&pool);
+ end_mime_stream(&hdr);
+
+ if(last_check)
+ {
+ pop_string_stack(&boundary);
+ if(top_string_stack(&boundary) == NULL)
+ break;
+ }
+ }
+ delete_string_stack(&boundary);
+ return head;
+}
+
+static void init_string_stack(struct StringStack *stk)
+{
+ stk->elem = NULL;
+ init_mblock(&stk->pool);
+}
+
+static void push_string_stack(struct StringStack *stk, char *str, int len)
+{
+ struct StringStackElem *elem;
+
+ elem = (struct StringStackElem *)
+ new_segment(&stk->pool, sizeof(struct StringStackElem) + len + 1);
+ memcpy(elem->str, str, len);
+ elem->str[len] = '\0';
+ elem->next = stk->elem;
+ stk->elem = elem;
+}
+
+static char *top_string_stack(struct StringStack *stk)
+{
+ if(stk->elem == NULL)
+ return NULL;
+ return stk->elem->str;
+}
+
+static void pop_string_stack(struct StringStack *stk)
+{
+ if(stk->elem == NULL)
+ return;
+ stk->elem = stk->elem->next;
+}
+
+static void delete_string_stack(struct StringStack *stk)
+{
+ reuse_mblock(&stk->pool);
+}
+
+static void init_mime_stream(struct MIMEHeaderStream *hdr, URL url)
+{
+ hdr->url = url;
+ hdr->field = hdr->value = hdr->line = NULL;
+ hdr->eof = 0;
+ init_mblock(&hdr->pool);
+}
+
+static int whole_read_line(URL url, char *buff, int bufsiz)
+{
+ int len;
+
+ if(url_gets(url, buff, bufsiz) == NULL)
+ return -1;
+ len = strlen(buff);
+ if(len == 0)
+ return 0;
+ if(buff[len - 1] == '\n')
+ {
+ buff[--len] = '\0';
+ if(len > 0 && buff[len - 1] == '\r')
+ buff[--len] = '\0';
+ }
+ else
+ {
+ /* skip line */
+ int c;
+ do
+ {
+ c = url_getc(url);
+ } while(c != EOF && c != '\n');
+ }
+
+ return len;
+}
+
+static int next_mime_header(struct MIMEHeaderStream *hdr)
+{
+ int len, c, n;
+ char *p;
+
+ if(hdr->eof)
+ return 0;
+
+ if(hdr->line == NULL)
+ {
+ hdr->line = (char *)new_segment(&hdr->pool, MIN_MBLOCK_SIZE);
+ len = whole_read_line(hdr->url, hdr->line, MIN_MBLOCK_SIZE);
+ if(len <= 0)
+ {
+ if(len == -1)
+ hdr->eof = 1;
+ return 0;
+ }
+ hdr->field = (char *)new_segment(&hdr->pool, MIN_MBLOCK_SIZE);
+ hdr->bufflen = 0;
+ }
+
+ if((hdr->bufflen = strlen(hdr->line)) == 0)
+ return 0;
+
+ memcpy(hdr->field, hdr->line, hdr->bufflen);
+ hdr->field[hdr->bufflen] = '\0';
+
+ for(;;)
+ {
+ len = whole_read_line(hdr->url, hdr->line, MIN_MBLOCK_SIZE);
+ if(len <= 0)
+ {
+ if(len == -1)
+ hdr->eof = 1;
+ break;
+ }
+ c = *hdr->line;
+ if(c == '>' || ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))
+ break;
+ if(c != ' ' && c != '\t')
+ return 0; /* ?? */
+
+ n = MIN_MBLOCK_SIZE - 1 - hdr->bufflen;
+ if(n > 0)
+ {
+ int i;
+
+ if(len > n)
+ len = n;
+
+ /* s/\t/ /g; */
+ p = hdr->line;
+ for(i = 0; i < len; i++)
+ if(p[i] == '\t')
+ p[i] = ' ';
+
+ memcpy(hdr->field + hdr->bufflen, p, len);
+ hdr->bufflen += len;
+ hdr->field[hdr->bufflen] = '\0';
+ }
+ }
+ p = hdr->field;
+ while(*p && *p != ':')
+ p++;
+ if(!*p)
+ return 0;
+ *p++ = '\0';
+ while(*p && *p == ' ')
+ p++;
+ hdr->value = p;
+ return 1;
+}
+
+static void end_mime_stream(struct MIMEHeaderStream *hdr)
+{
+ reuse_mblock(&hdr->pool);
+}
+
+static int seek_next_boundary(URL url, char *boundary, long *endpoint)
+{
+ MBlockList pool;
+ char *buff;
+ int blen, ret;
+
+ if(boundary == NULL)
+ {
+ url_seek(url, 0, SEEK_END);
+ *endpoint = url_tell(url);
+ return 0;
+ }
+
+ init_mblock(&pool);
+ buff = (char *)new_segment(&pool, MIN_MBLOCK_SIZE);
+ blen = strlen(boundary);
+ ret = 0;
+ for(;;)
+ {
+ int len;
+
+ *endpoint = url_tell(url);
+ if((len = whole_read_line(url, buff, MIN_MBLOCK_SIZE)) < 0)
+ break;
+ if(len < blen + 2)
+ continue;
+
+ if(buff[0] == '-' && buff[1] == '-' &&
+ strncmp(buff + 2, boundary, blen) == 0)
+ {
+ if(buff[blen + 2] == '-' && buff[blen + 3] == '-')
+ ret = 1;
+ break;
+ }
+ }
+ reuse_mblock(&pool);
+ return ret;
+}
+
+static void *arc_mime_decode(void *data, long size,
+ int comptype, long *newsize)
+{
+ URL url;
+
+ if(comptype == ARCHIVEC_STORED)
+ return data;
+
+ if(data == NULL)
+ return NULL;
+
+ if((url = url_mem_open(data, size, 1)) == NULL)
+ return NULL;
+
+ switch(comptype)
+ {
+ case ARCHIVEC_UU: /* uu encoded */
+ url = url_uudecode_open(url, 1);
+ break;
+ case ARCHIVEC_B64: /* base64 encoded */
+ url = url_b64decode_open(url, 1);
+ break;
+ case ARCHIVEC_QS: /* quoted string encoded */
+ url = url_hqxdecode_open(url, 1, 1);
+ break;
+ case ARCHIVEC_HQX: /* HQX encoded */
+ url = url_qsdecode_open(url, 1);
+ break;
+ default:
+ url_close(url);
+ return NULL;
+ }
+ data = url_dump(url, -1, newsize);
+ url_close(url);
+ return data;
+}
diff --git a/lib/timidity/libarc/arc_tar.c b/lib/timidity/libarc/arc_tar.c
new file mode 100644
index 0000000000..e2d64e9ebc
--- /dev/null
+++ b/lib/timidity/libarc/arc_tar.c
@@ -0,0 +1,181 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "timidity.h"
+#include "mblock.h"
+#include "zip.h"
+#include "arc.h"
+
+#define TARBLKSIZ 512
+#define TARHDRSIZ 512
+
+static long octal_value(char *s, int len);
+static int tar_checksum(char *hdr);
+
+ArchiveEntryNode *next_tar_entry(void)
+{
+ char hdr[TARHDRSIZ];
+ long size, sizeb;
+ ArchiveEntryNode *entry;
+ URL url;
+ int flen;
+ int macbin_check;
+
+ url = arc_handler.url;
+ macbin_check = (arc_handler.counter == 0);
+
+ retry_read:
+ if(!macbin_check)
+ {
+ if(url_read(url, hdr, TARHDRSIZ) != TARHDRSIZ)
+ return NULL;
+ }
+ else
+ {
+ int c = url_getc(url);
+ if(c == 0)
+ {
+ url_skip(url, 127);
+ if(arc_handler.isfile)
+ arc_handler.pos += 128;
+ if(url_read(url, hdr, TARHDRSIZ) != TARHDRSIZ)
+ return NULL;
+ }
+ else
+ {
+ hdr[0] = c;
+ if(url_read(url, hdr+1, TARHDRSIZ-1) != TARHDRSIZ-1)
+ return NULL;
+ }
+ }
+
+ macbin_check = 0;
+
+ if(hdr[0] == '\0')
+ return NULL;
+ if(!tar_checksum(hdr))
+ return NULL;
+ size = octal_value(hdr + 124, 12);
+ flen = strlen(hdr);
+ if(size == 0 && flen > 0 && hdr[flen - 1] == '/')
+ {
+ if(arc_handler.isfile)
+ arc_handler.pos += TARHDRSIZ;
+ goto retry_read;
+ }
+
+ entry = new_entry_node(hdr, flen);
+ if(entry == NULL)
+ return NULL;
+ sizeb = (((size) + (TARBLKSIZ-1)) & ~(TARBLKSIZ-1));
+
+ if(arc_handler.isfile)
+ {
+ arc_handler.pos += TARHDRSIZ;
+ entry->comptype = ARCHIVEC_STORED;
+ entry->compsize = entry->origsize = size;
+ entry->start = arc_handler.pos;
+ url_skip(url, sizeb);
+ arc_handler.pos += sizeb;
+ }
+ else
+ {
+ void *data;
+ long n;
+
+ data = url_dump(url, size, &n);
+ if(size != n)
+ {
+ if(data != NULL)
+ free(data);
+ free_entry_node(entry);
+ return NULL;
+ }
+ entry->cache = arc_compress(data, size, ARC_DEFLATE_LEVEL,
+ &entry->compsize);
+ free(data);
+ entry->comptype = ARCHIVEC_DEFLATED;
+ entry->origsize = size;
+ entry->start = 0;
+ url_skip(url, sizeb - size);
+ }
+
+ return entry;
+}
+
+static long octal_value(char *s, int len)
+{
+ long val;
+
+ while(len > 0 && !isdigit((int)(unsigned char)*s))
+ {
+ s++;
+ len--;
+ }
+
+ val = 0;
+ while(len > 0 && isdigit((int)(unsigned char)*s))
+ {
+ val = ((val<<3) | (*s - '0'));
+ s++;
+ len--;
+ }
+ return val;
+}
+
+static int tar_checksum(char *hdr)
+{
+ int i;
+
+ long recorded_sum;
+ long unsigned_sum; /* the POSIX one :-) */
+ long signed_sum; /* the Sun one :-( */
+
+ recorded_sum = octal_value(hdr + 148, 8);
+ unsigned_sum = 0;
+ signed_sum = 0;
+ for(i = 0; i < TARBLKSIZ; i++)
+ {
+ unsigned_sum += 0xFF & hdr[i];
+ signed_sum += hdr[i];
+ }
+
+ /* Adjust checksum to count the "chksum" field as blanks. */
+ for(i = 0; i < 8; i++)
+ {
+ unsigned_sum -= 0xFF & hdr[148 + i];
+ signed_sum -= hdr[i];
+ }
+ unsigned_sum += ' ' * 8;
+ signed_sum += ' ' * 8;
+
+ return unsigned_sum == recorded_sum || signed_sum == recorded_sum;
+}
diff --git a/lib/timidity/libarc/arc_zip.c b/lib/timidity/libarc/arc_zip.c
new file mode 100644
index 0000000000..55daa467be
--- /dev/null
+++ b/lib/timidity/libarc/arc_zip.c
@@ -0,0 +1,236 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#include "timidity.h"
+#include "arc.h"
+
+#define LOCSIG 0x04034b50
+#define EXTLOCSIG 0x08074b50L
+
+static unsigned short get_short(char *s)
+{
+ unsigned char *p = (unsigned char *)s;
+ return ((unsigned short)p[0] |
+ (unsigned short)p[1]<<8);
+}
+
+static unsigned long get_long(char *s)
+{
+ unsigned char *p = (unsigned char *)s;
+ return ((unsigned long)p[0] |
+ (unsigned long)p[1]<<8 |
+ (unsigned long)p[2]<<16 |
+ (unsigned long)p[3]<<24);
+}
+
+ArchiveEntryNode *next_zip_entry(void)
+{
+ unsigned long magic;
+ unsigned short flen, elen, hdrsiz;
+ URL url;
+ long compsize, origsize;
+ char buff[BUFSIZ];
+ ArchiveEntryNode *entry;
+ int method;
+ unsigned short flags;
+ int macbin_check;
+
+ url = arc_handler.url;
+ macbin_check = (arc_handler.counter == 0);
+
+ retry_read:
+ if(url_read(url, buff, 4) != 4)
+ return NULL;
+
+ hdrsiz = 4;
+
+ magic = get_long(buff);
+ if(magic == EXTLOCSIG)
+ {
+ /* ignored */
+ if(url_read(url, buff, 20) != 20)
+ return NULL;
+ magic = get_long(buff + 16);
+ hdrsiz += 20;
+ }
+ else if(macbin_check && buff[0] == '0')
+ {
+ macbin_check = 0;
+ url_skip(url, 128-4);
+ if(arc_handler.isfile)
+ arc_handler.pos += 128;
+ goto retry_read;
+ }
+
+ if(magic != LOCSIG)
+ return NULL;
+
+ /* Version needed to extract */
+ url_skip(url, 2);
+ hdrsiz += 2;
+
+ /* General purpose bit flag */
+ if(url_read(url, buff, 2) != 2)
+ return NULL;
+ flags = get_short(buff);
+ hdrsiz += 2;
+
+ /* Compression method */
+ if(url_read(url, buff, 2) != 2)
+ return NULL;
+ method = get_short(buff);
+ hdrsiz += 2;
+
+ switch(method)
+ {
+ case 0: /* The file is stored (no compression) */
+ method = ARCHIVEC_STORED;
+ break;
+ case 1: /* The file is Shrunk */
+ method = ARCHIVEC_SHRUNKED;
+ break;
+ case 2: /* The file is Reduced with compression factor 1 */
+ method = ARCHIVEC_REDUCED1;
+ break;
+ case 3: /* The file is Reduced with compression factor 2 */
+ method = ARCHIVEC_REDUCED2;
+ break;
+ case 4: /* The file is Reduced with compression factor 3 */
+ method = ARCHIVEC_REDUCED3;
+ break;
+ case 5: /* The file is Reduced with compression factor 4 */
+ method = ARCHIVEC_REDUCED4;
+ break;
+ case 6: /* The file is Imploded */
+ if(flags & 4)
+ {
+ if(flags & 2)
+ method = ARCHIVEC_IMPLODED_LIT8;
+ else
+ method = ARCHIVEC_IMPLODED_LIT4;
+ }
+ else if(flags & 2)
+ method = ARCHIVEC_IMPLODED_NOLIT8;
+ else
+ method = ARCHIVEC_IMPLODED_NOLIT4;
+ break;
+ case 7: /* Reserved for Tokenizing compression algorithm */
+ method = -1;
+ break;
+ case 8: /* The file is Deflated */
+ method = ARCHIVEC_DEFLATED;
+ break;
+ default:
+ return NULL;
+ }
+
+ /* Last mod file time */
+ url_skip(url, 2);
+ hdrsiz += 2;
+
+ /* Last mod file date */
+ url_skip(url, 2);
+ hdrsiz += 2;
+
+ /* CRC-32 */
+ url_skip(url, 4);
+ hdrsiz += 4;
+
+ /* Compressed size */
+ if(url_read(url, buff, 4) != 4)
+ return NULL;
+ hdrsiz += 4;
+ compsize = (long)get_long(buff);
+
+ /* Uncompressed size */
+ if(url_read(url, buff, 4) != 4)
+ return NULL;
+ hdrsiz += 4;
+ origsize = (long)get_long(buff);
+
+ /* Filename length */
+ if(url_read(url, buff, 2) != 2)
+ return NULL;
+ hdrsiz += 2;
+ flen = get_short(buff);
+ if(flen >= sizeof(buff)-1)
+ return NULL;
+
+ /* Extra field length */
+ if(url_read(url, buff, 2) != 2)
+ return NULL;
+ hdrsiz += 2;
+ elen = get_short(buff);
+
+ /* filename */
+ if(url_read(url, buff, flen) != flen)
+ return NULL;
+ hdrsiz += flen;
+ buff[flen] = '\0';
+
+ if(compsize == 0 && flen > 0 &&
+ (buff[flen - 1] == '/' || buff[flen - 1] == '\\'))
+ {
+ url_skip(url, elen);
+ hdrsiz += elen;
+ if(arc_handler.isfile)
+ arc_handler.pos += hdrsiz;
+ goto retry_read;
+ }
+
+ entry = new_entry_node(buff, flen);
+ if(entry == NULL)
+ return NULL;
+
+ entry->comptype = method;
+ entry->origsize = origsize;
+ entry->compsize = compsize;
+
+ /* Extra field */
+ url_skip(url, elen);
+ hdrsiz += elen;
+
+ if(arc_handler.isfile)
+ {
+ arc_handler.pos += hdrsiz;
+ entry->start = arc_handler.pos;
+ entry->cache = NULL;
+ url_skip(url, compsize);
+ arc_handler.pos += compsize;
+ }
+ else
+ {
+ long n;
+ entry->start = 0;
+ entry->cache = url_dump(url, compsize, &n);
+ if(n != compsize)
+ {
+ free_entry_node(entry);
+ return NULL;
+ }
+ }
+
+ return entry;
+}
diff --git a/lib/timidity/libarc/deflate.c b/lib/timidity/libarc/deflate.c
new file mode 100644
index 0000000000..b21424e066
--- /dev/null
+++ b/lib/timidity/libarc/deflate.c
@@ -0,0 +1,1937 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/*
+ * PURPOSE
+ *
+ * Identify new text as repetitions of old text within a fixed-
+ * length sliding window trailing behind the new text.
+ *
+ * DISCUSSION
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many info-zippers for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * APPNOTE.TXT documentation file in PKZIP 1.93a distribution.
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ * INTERFACE
+ *
+ * void lm_init (void)
+ * Initialize the "longest match" routines for a new file
+ *
+ * ulg deflate (void)
+ * Processes a new input file and return its compressed length. Sets
+ * the compressed length, crc, deflate flags and internal file
+ * attributes.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include <ctype.h>
+
+#define FULL_SEARCH
+/* #define UNALIGNED_OK */
+/* #define DEBUG */
+#include "timidity.h"
+#include "common.h"
+#include "mblock.h"
+#include "zip.h"
+
+#define local static
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define BITS 16
+
+/* Compile with MEDIUM_MEM to reduce the memory requirements or
+ * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the
+ * entire input file can be held in memory (not possible on 16 bit systems).
+ * Warning: defining these symbols affects HASH_BITS (see below) and thus
+ * affects the compression ratio. The compressed output
+ * is still correct, and might even be smaller in some cases.
+ */
+#ifdef SMALL_MEM
+# define LIT_BUFSIZE 0x2000
+# define HASH_BITS 13 /* Number of bits used to hash strings */
+#else
+#ifdef MEDIUM_MEM
+# define LIT_BUFSIZE 0x4000
+# define HASH_BITS 14
+#else
+# define LIT_BUFSIZE 0x8000
+# define HASH_BITS 15
+/* For portability to 16 bit machines, do not use values above 15. */
+#endif
+#endif
+
+#if LIT_BUFSIZE > INBUFSIZ
+ error cannot overlay l_buf and inbuf
+#endif
+#if (WSIZE<<1) > (1<<BITS)
+ error: cannot overlay window with tab_suffix and prev with tab_prefix0
+#endif
+#if HASH_BITS > BITS-1
+ error: cannot overlay head with tab_prefix1
+#endif
+
+#define DIST_BUFSIZE LIT_BUFSIZE
+#define HASH_SIZE (unsigned)(1<<HASH_BITS)
+#define HASH_MASK (HASH_SIZE-1)
+#define WMASK (WSIZE-1)
+/* HASH_SIZE and WSIZE must be powers of two */
+
+#define NIL 0 /* Tail of hash chains */
+#define EQUAL 0 /* result of memcmp for equal strings */
+
+#define TOO_FAR 4096
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+#define MAX_BITS 15 /* All codes must not exceed MAX_BITS bits */
+#define MAX_BL_BITS 7 /* Bit length codes must not exceed MAX_BL_BITS bits */
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+#define LITERALS 256 /* number of literal bytes 0..255 */
+#define END_BLOCK 256 /* end of block literal code */
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+#define D_CODES 30 /* number of distance codes */
+#define BL_CODES 19 /* number of codes used to transfer the bit lengths */
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+#define HEAP_SIZE (2*L_CODES+1) /* maximum heap size */
+
+#define H_SHIFT ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
+/* Number of bits by which ins_h and del_h must be shifted at each
+ * input step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * H_SHIFT * MIN_MATCH >= HASH_BITS
+ */
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} ct_data;
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct tree_desc {
+ ct_data near *dyn_tree; /* the dynamic tree */
+ ct_data near *static_tree; /* corresponding static tree or NULL */
+ int near *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+ int max_code; /* largest code with non zero frequency */
+} tree_desc;
+
+local int near extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {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};
+local int near extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {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};
+local int near extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local uch near bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+local struct
+{
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+} configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0}, /* store only */
+/* 1 */ {4, 4, 8, 4}, /* maximum speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8},
+/* 3 */ {4, 6, 32, 32},
+
+/* 4 */ {4, 4, 16, 16}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32},
+/* 6 */ {8, 16, 128, 128},
+/* 7 */ {8, 32, 128, 256},
+/* 8 */ {32, 128, 258, 1024},
+/* 9 */ {32, 258, 258, 4096}}; /* maximum compression */
+
+struct deflate_buff_queue
+{
+ struct deflate_buff_queue *next;
+ unsigned len;
+ uch *ptr;
+};
+local struct deflate_buff_queue *free_queue = NULL;
+
+local void reuse_queue(struct deflate_buff_queue *p)
+{
+ p->next = free_queue;
+ free_queue = p;
+}
+local struct deflate_buff_queue *new_queue(void)
+{
+ struct deflate_buff_queue *p;
+
+ if(free_queue)
+ {
+ p = free_queue;
+ free_queue = free_queue->next;
+ }
+ else
+ p = (struct deflate_buff_queue *)
+ safe_malloc(sizeof(struct deflate_buff_queue) + OUTBUFSIZ);
+ p->next = NULL;
+ p->len = 0;
+ p->ptr = (uch *)p + sizeof(struct deflate_buff_queue);
+
+ return p;
+}
+
+struct _DeflateHandler
+{
+ void *user_val;
+ long (* read_func)(char *buf, long size, void *user_val);
+
+ int initflag;
+ struct deflate_buff_queue *qhead;
+ struct deflate_buff_queue *qtail;
+ uch outbuf[OUTBUFSIZ];
+ unsigned outcnt, outoff;
+ int complete;
+
+#define window_size ((ulg)2*WSIZE)
+ uch window[window_size];
+ ush d_buf[DIST_BUFSIZE]; /* buffer for distances */
+ uch l_buf[INBUFSIZ + INBUF_EXTRA]; /* buffer for literals or lengths */
+ ush prev[1L<<BITS];
+ unsigned short bi_buf;
+ int bi_valid;
+
+ long block_start;
+/* window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ unsigned ins_h; /* hash index of string to be inserted */
+
+ unsigned hash_head; /* head of hash chain */
+ unsigned prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ unsigned match_length; /* length of best match */
+ unsigned int near prev_length;
+/* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ unsigned near strstart; /* start of string to insert */
+ unsigned near match_start; /* start of matching string */
+ int eofile; /* flag set at end of input file */
+ unsigned lookahead; /* number of valid bytes ahead in window */
+
+ unsigned near max_chain_length;
+/* To speed up deflation, hash chains are never searched beyond this length.
+ * A higher limit improves compression ratio but degrades the speed.
+ */
+
+ unsigned int max_lazy_match;
+/* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+
+ int compr_level; /* compression level (1..9) */
+
+ unsigned near good_match;
+/* Use a faster search when the previous match is longer than this */
+
+#ifndef FULL_SEARCH
+ int near nice_match; /* Stop searching when current match exceeds this */
+#endif
+
+ ct_data near dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ ct_data near dyn_dtree[2*D_CODES+1]; /* distance tree */
+ ct_data near static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see ct_init
+ * below).
+ */
+
+ ct_data near static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+ ct_data near bl_tree[2*BL_CODES+1];/* Huffman tree for the bit lengths */
+
+ tree_desc near l_desc;
+ tree_desc near d_desc;
+ tree_desc near bl_desc;
+
+ ush near bl_count[MAX_BITS+1];
+/* number of codes at each bit length for an optimal tree */
+
+ int near heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch near depth[2*L_CODES+1];
+/* Depth of each subtree used as tie breaker for trees of equal frequency */
+
+ uch length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+ uch dist_code[512];
+/* distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+ int near base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+ int near base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+ uch near flag_buf[(LIT_BUFSIZE/8)];
+/* flag_buf is a bit array distinguishing literals from lengths in
+ * l_buf, thus indicating the presence or absence of a distance.
+ */
+
+ unsigned last_lit; /* running index in l_buf */
+ unsigned last_dist; /* running index in d_buf */
+ unsigned last_flags;/* running index in flag_buf */
+ uch flags; /* current flags not yet saved in flag_buf */
+ uch flag_bit; /* current bit used in flags */
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+};
+
+local void lm_init(DeflateHandler);
+local int longest_match(DeflateHandler,unsigned cur_match);
+local void fill_window(DeflateHandler);
+local void deflate_fast(DeflateHandler);
+local void deflate_better(DeflateHandler);
+local long qcopy(DeflateHandler encoder, char *buff, long buff_size);
+local void ct_init(DeflateHandler);
+local void init_block(DeflateHandler);
+local void pqdownheap(DeflateHandler,ct_data near *, int);
+local void gen_bitlen(DeflateHandler,tree_desc near *);
+local void gen_codes(DeflateHandler,ct_data near *, int);
+local void build_tree(DeflateHandler,tree_desc near *);
+local void scan_tree(DeflateHandler,ct_data near *, int);
+local void send_tree(DeflateHandler,ct_data near *, int);
+local int build_bl_tree(DeflateHandler);
+local void send_all_trees(DeflateHandler,int,int,int);
+local void flush_block(DeflateHandler,int);
+local int ct_tally(DeflateHandler,int,int);
+local void compress_block(DeflateHandler,ct_data near *, ct_data near *);
+local void send_bits(DeflateHandler,int,int);
+local unsigned bi_reverse(unsigned, int);
+local void bi_windup(DeflateHandler);
+local void qoutbuf(DeflateHandler);
+
+#ifdef DEBUG
+local void error(char *m)
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#define Assert(cond,msg) {if(!(cond)) error(msg);}
+local int verbose = 0; /* verbose */
+local void check_match (DeflateHandler,unsigned, unsigned, int);
+#else
+#define Assert(cond,msg)
+#endif
+
+#ifndef MAX
+#define MAX(a,b) (a >= b ? a : b)
+#endif /* MAX */
+
+#define head(i) ((encoder->prev+WSIZE)[i])
+
+/* put_byte is used for the compressed output, put_ubyte for the
+ * uncompressed output. However unlzw() uses window for its
+ * suffix table instead of its output buffer, so it does not use put_ubyte
+ * (to be cleaned up).
+ */
+#define put_byte(c) {encoder->outbuf[encoder->outoff + encoder->outcnt++] = \
+ (uch)(c); if(encoder->outoff + encoder->outcnt == OUTBUFSIZ) \
+ qoutbuf(encoder);}
+
+/* Output a 16 bit value, lsb first */
+#define put_short(w) \
+{ if(encoder->outoff + encoder->outcnt < OUTBUFSIZ - 2) { \
+ encoder->outbuf[encoder->outoff+encoder->outcnt++] = (uch) ((w) & 0xff); \
+ encoder->outbuf[encoder->outoff+encoder->outcnt++] = (uch) ((ush)(w) >> 8); \
+ } else { put_byte((uch)((w) & 0xff)); put_byte((uch)((ush)(w) >> 8)); }}
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
+
+/* ===========================================================================
+ * Insert string s in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of s are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#define INSERT_STRING(s, match_head) \
+ (UPDATE_HASH(encoder->ins_h, encoder->window[(s) + MIN_MATCH-1]), \
+ encoder->prev[(s) & WMASK] =match_head = head(encoder->ins_h), \
+ head(encoder->ins_h) = (s))
+
+#define SEND_CODE(c, tree) send_bits(encoder, (tree)[c].Code, (tree)[c].Len)
+/* Send a code of the given tree. c and tree must not have side effects */
+
+#define D_CODE(dist) ((dist)<256 ? encoder->dist_code[dist] : encoder->dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ */
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define SMALLER(tree, n, m) \
+ ((tree)[n].Freq < (tree)[m].Freq || \
+ ((tree)[n].Freq == (tree)[m].Freq && encoder->depth[n] <= encoder->depth[m]))
+
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new file
+ */
+local void lm_init(DeflateHandler encoder)
+{
+ register unsigned j;
+
+ /* Initialize the hash table. */
+#if defined(MAXSEG_64K) && HASH_BITS == 15
+ for(j = 0; j < HASH_SIZE; j++) head(j) = NIL;
+#else
+ memset((char*)&head(0), 0, HASH_SIZE*sizeof(head(0)));
+#endif
+ /* prev will be initialized on the fly */
+
+ /* Set the default configuration parameters:
+ */
+ encoder->max_lazy_match = configuration_table[encoder->compr_level].max_lazy;
+ encoder->good_match = configuration_table[encoder->compr_level].good_length;
+#ifndef FULL_SEARCH
+ encoder->nice_match = configuration_table[encoder->compr_level].nice_length;
+#endif
+ encoder->max_chain_length = configuration_table[encoder->compr_level].max_chain;
+
+ encoder->strstart = 0;
+ encoder->block_start = 0L;
+
+ encoder->lookahead =
+ encoder->read_func((char*)encoder->window,
+ (long)(sizeof(int)<=2 ? (unsigned)WSIZE : 2*WSIZE),
+ encoder->user_val);
+
+ if(encoder->lookahead == 0 || encoder->lookahead == (unsigned)EOF) {
+ encoder->eofile = 1;
+ encoder->lookahead = 0;
+ return;
+ }
+ encoder->eofile = 0;
+ /* Make sure that we always have enough lookahead. This is important
+ * if input comes from a device such as a tty.
+ */
+ while(encoder->lookahead < MIN_LOOKAHEAD && !encoder->eofile)
+ fill_window(encoder);
+
+ encoder->ins_h = 0;
+ for(j=0; j<MIN_MATCH-1; j++)
+ UPDATE_HASH(encoder->ins_h, encoder->window[j]);
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
+ * not important since only literal bytes will be emitted.
+ */
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+local int longest_match(DeflateHandler encoder, unsigned cur_match)
+{
+ unsigned chain_length = encoder->max_chain_length;
+ /* max hash chain length */
+
+ register uch *scan = encoder->window + encoder->strstart;
+ /* current string */
+
+ register uch *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = encoder->prev_length; /* best match length so far */
+
+ unsigned limit = (encoder->strstart > (unsigned)MAX_DIST ?
+ encoder->strstart - (unsigned)MAX_DIST : NIL);
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+
+#if HASH_BITS < 8 || MAX_MATCH != 258
+ error: Code too clever
+#endif
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register uch *strend = encoder->window + encoder->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ush*)scan;
+ register ush scan_end = *(ush*)(scan+best_len-1);
+#else
+ register uch *strend = encoder->window + encoder->strstart + MAX_MATCH;
+ register uch scan_end1 = scan[best_len-1];
+ register uch scan_end = scan[best_len];
+#endif
+
+ /* Do not waste too much time if we already have a good match: */
+ if(encoder->prev_length >= encoder->good_match) {
+ chain_length >>= 2;
+ }
+ Assert(encoder->strstart <= window_size-MIN_LOOKAHEAD, "insufficient lookahead");
+
+ do {
+ Assert(cur_match < encoder->strstart, "no future");
+ match = encoder->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2:
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if(*(ush*)(match+best_len-1) != scan_end ||
+ *(ush*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ scan++, match++;
+ do {
+ } while(*(ush*)(scan+=2) == *(ush*)(match+=2) &&
+ *(ush*)(scan+=2) == *(ush*)(match+=2) &&
+ *(ush*)(scan+=2) == *(ush*)(match+=2) &&
+ *(ush*)(scan+=2) == *(ush*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= encoder->window+(unsigned)(window_size-1), "wild scan");
+ if(*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if(match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while(*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if(len > best_len) {
+ encoder->match_start = cur_match;
+ best_len = len;
+#ifdef FULL_SEARCH
+ if(len >= MAX_MATCH) break;
+#else
+ if(len >= encoder->nice_match) break;
+#endif /* FULL_SEARCH */
+
+
+#ifdef UNALIGNED_OK
+ scan_end = *(ush*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while((cur_match = encoder->prev[cur_match & WMASK]) > limit
+ && --chain_length != 0);
+
+ return best_len;
+}
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(DeflateHandler encoder,
+ unsigned start, unsigned match, int length)
+{
+ /* check that the match is indeed a match */
+ if(memcmp((char*)encoder->window + match,
+ (char*)encoder->window + start, length) != EQUAL) {
+ fprintf(stderr,
+ " start %d, match %d, length %d\n",
+ start, match, length);
+ error("invalid match");
+ }
+ if(verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(encoder->window[start++], stderr); } while(--length != 0);
+ }
+}
+#else
+# define check_match(encoder, start, match, length)
+#endif
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead, and sets eofile if end of input file.
+ * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
+ * OUT assertions: at least one byte has been read, or eofile is set;
+ * file reads are performed for at least two bytes (required for the
+ * translate_eol option).
+ */
+local void fill_window(DeflateHandler encoder)
+{
+ register unsigned n, m;
+ unsigned more = (unsigned)(window_size - (ulg)encoder->lookahead - (ulg)encoder->strstart);
+ /* Amount of free space at the end of the window. */
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if(more == (unsigned)EOF) {
+ /* Very unlikely, but possible on 16 bit machine if strstart == 0
+ * and lookahead == 1 (input done one byte at time)
+ */
+ more--;
+ } else if(encoder->strstart >= WSIZE+MAX_DIST) {
+ /* By the IN assertion, the window is not empty so we can't confuse
+ * more == 0 with more == 64K on a 16 bit machine.
+ */
+ Assert(window_size == (ulg)2*WSIZE, "no sliding with BIG_MEM");
+
+ memcpy((char*)encoder->window, (char*)encoder->window+WSIZE, (unsigned)WSIZE);
+ encoder->match_start -= WSIZE;
+ encoder->strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */
+ encoder->block_start -= (long) WSIZE;
+
+ for(n = 0; n < HASH_SIZE; n++) {
+ m = head(n);
+ head(n) = (ush)(m >= WSIZE ? m-WSIZE : NIL);
+ }
+ for(n = 0; n < WSIZE; n++) {
+ m = encoder->prev[n];
+ encoder->prev[n] = (ush)(m >= WSIZE ? m-WSIZE : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ }
+ more += WSIZE;
+ }
+ /* At this point, more >= 2 */
+ if(!encoder->eofile) {
+ n = encoder->read_func((char*)encoder->window+encoder->strstart
+ + encoder->lookahead,
+ (long)more,
+ encoder->user_val);
+ if(n == 0 || n == (unsigned)EOF) {
+ encoder->eofile = 1;
+ } else {
+ encoder->lookahead += n;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Processes a new input file and return its compressed length. This
+ * function does not perform lazy evaluationof matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local void deflate_fast(DeflateHandler encoder)
+{
+/*
+ encoder->prev_length = MIN_MATCH-1;
+ encoder->match_length = 0;
+*/
+ while(encoder->lookahead != 0 && encoder->qhead == NULL) {
+ int flush; /* set if current block must be flushed */
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ INSERT_STRING(encoder->strstart, encoder->hash_head);
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if(encoder->hash_head != NIL &&
+ encoder->strstart - encoder->hash_head <= MAX_DIST) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ encoder->match_length = longest_match(encoder, encoder->hash_head);
+ /* longest_match() sets match_start */
+ if(encoder->match_length > encoder->lookahead)
+ encoder->match_length = encoder->lookahead;
+ }
+ if(encoder->match_length >= MIN_MATCH) {
+ check_match(encoder, encoder->strstart,
+ encoder->match_start, encoder->match_length);
+
+ flush = ct_tally(encoder, encoder->strstart - encoder->match_start,
+ encoder->match_length - MIN_MATCH);
+
+ encoder->lookahead -= encoder->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+ if(encoder->match_length <= encoder->max_lazy_match) {
+ encoder->match_length--; /* string at strstart already in hash table */
+ do {
+ encoder->strstart++;
+ INSERT_STRING(encoder->strstart, encoder->hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
+ * these bytes are garbage, but it does not matter since
+ * the next lookahead bytes will be emitted as literals.
+ */
+ } while(--encoder->match_length != 0);
+ encoder->strstart++;
+ } else {
+ encoder->strstart += encoder->match_length;
+ encoder->match_length = 0;
+ encoder->ins_h = encoder->window[encoder->strstart];
+ UPDATE_HASH(encoder->ins_h,
+ encoder->window[encoder->strstart + 1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c",encoder->window[encoder->strstart]));
+ flush = ct_tally (encoder, 0, encoder->window[encoder->strstart]);
+ encoder->lookahead--;
+ encoder->strstart++;
+ }
+ if(flush)
+ {
+ flush_block(encoder, 0);
+ encoder->block_start = (long)encoder->strstart;
+ }
+
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ while(encoder->lookahead < MIN_LOOKAHEAD && !encoder->eofile)
+ fill_window(encoder);
+ }
+}
+
+local void deflate_better(DeflateHandler encoder) {
+ /* Process the input block. */
+ while(encoder->lookahead != 0 && encoder->qhead == NULL) {
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ INSERT_STRING(encoder->strstart, encoder->hash_head);
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ encoder->prev_length = encoder->match_length;
+ encoder->prev_match = encoder->match_start;
+ encoder->match_length = MIN_MATCH-1;
+
+ if(encoder->hash_head != NIL &&
+ encoder->prev_length < encoder->max_lazy_match &&
+ encoder->strstart - encoder->hash_head <= MAX_DIST) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ encoder->match_length = longest_match(encoder, encoder->hash_head);
+ /* longest_match() sets match_start */
+ if(encoder->match_length > encoder->lookahead)
+ encoder->match_length = encoder->lookahead;
+
+ /* Ignore a length 3 match if it is too distant: */
+ if(encoder->match_length == MIN_MATCH &&
+ encoder->strstart - encoder->match_start > TOO_FAR){
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ encoder->match_length--;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if(encoder->prev_length >= MIN_MATCH &&
+ encoder->match_length <= encoder->prev_length) {
+ int flush; /* set if current block must be flushed */
+
+ check_match(encoder, encoder->strstart-1,
+ encoder->prev_match, encoder->prev_length);
+
+ flush = ct_tally(encoder, encoder->strstart-1-encoder->prev_match,
+ encoder->prev_length - MIN_MATCH);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted.
+ */
+ encoder->lookahead -= encoder->prev_length-1;
+ encoder->prev_length -= 2;
+ do {
+ encoder->strstart++;
+ INSERT_STRING(encoder->strstart, encoder->hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
+ * these bytes are garbage, but it does not matter since the
+ * next lookahead bytes will always be emitted as literals.
+ */
+ } while(--encoder->prev_length != 0);
+ encoder->match_available = 0;
+ encoder->match_length = MIN_MATCH-1;
+ encoder->strstart++;
+ if(flush) {
+ flush_block(encoder, 0);
+ encoder->block_start = (long)encoder->strstart;
+ }
+
+ } else if(encoder->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c",encoder->window[encoder->strstart-1]));
+ if(ct_tally (encoder, 0, encoder->window[encoder->strstart-1])) {
+ flush_block(encoder, 0);
+ encoder->block_start = (long)encoder->strstart;
+ }
+ encoder->strstart++;
+ encoder->lookahead--;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ encoder->match_available = 1;
+ encoder->strstart++;
+ encoder->lookahead--;
+ }
+
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ while(encoder->lookahead < MIN_LOOKAHEAD && !encoder->eofile)
+ fill_window(encoder);
+ }
+}
+
+/*ARGSUSED*/
+static long default_read_func(char *buf, long size, void *v)
+{
+ return (long)fread(buf, 1, size, stdin);
+}
+
+DeflateHandler open_deflate_handler(
+ long (* read_func)(char *buf, long size, void *user_val),
+ void *user_val,
+ int level)
+{
+ DeflateHandler encoder;
+
+ if(level < 1 || level > 9)
+ return NULL; /* error("bad compression level"); */
+
+ encoder = (DeflateHandler)safe_malloc(sizeof(struct _DeflateHandler));
+ if(encoder == NULL)
+ return NULL;
+ memset(encoder, 0, sizeof(struct _DeflateHandler));
+ encoder->compr_level = level;
+ if(read_func == NULL)
+ encoder->read_func = default_read_func;
+ else
+ encoder->read_func = read_func;
+ encoder->user_val = user_val;
+
+ return encoder;
+}
+
+void close_deflate_handler(DeflateHandler encoder)
+{
+ free(encoder);
+}
+
+local void init_deflate(DeflateHandler encoder)
+{
+ if(encoder->eofile)
+ return;
+ encoder->bi_buf = 0;
+ encoder->bi_valid = 0;
+ ct_init(encoder);
+ lm_init(encoder);
+
+ encoder->qhead = NULL;
+ encoder->outcnt = 0;
+
+ if(encoder->compr_level <= 3)
+ {
+ encoder->prev_length = MIN_MATCH - 1;
+ encoder->match_length = 0;
+ }
+ else
+ {
+ encoder->match_length = MIN_MATCH - 1;
+ encoder->match_available = 0;
+ }
+
+ encoder->complete = 0;
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+long zip_deflate(DeflateHandler encoder, char *buff, long buff_size)
+{
+ long n;
+
+ if(!encoder->initflag)
+ {
+ init_deflate(encoder);
+ encoder->initflag = 1;
+ if(encoder->lookahead == 0) { /* empty */
+ encoder->complete = 1;
+ return 0;
+ }
+ }
+
+ if((n = qcopy(encoder, buff, buff_size)) == buff_size)
+ return buff_size;
+
+ if(encoder->complete)
+ return n;
+
+ if(encoder->compr_level <= 3) /* optimized for speed */
+ deflate_fast(encoder);
+ else
+ deflate_better(encoder);
+ if(encoder->lookahead == 0)
+ {
+ if(encoder->match_available)
+ ct_tally(encoder, 0, encoder->window[encoder->strstart - 1]);
+ flush_block(encoder, 1);
+ encoder->complete = 1;
+ }
+ return n + qcopy(encoder, buff + n, buff_size - n);
+}
+
+local long qcopy(DeflateHandler encoder, char *buff, long buff_size)
+{
+ struct deflate_buff_queue *q;
+ long n, i;
+
+ n = 0;
+ q = encoder->qhead;
+ while(q != NULL && n < buff_size)
+ {
+ i = buff_size - n;
+ if(i > q->len)
+ i = q->len;
+ memcpy(buff + n, q->ptr, i);
+ q->ptr += i;
+ q->len -= i;
+ n += i;
+
+ if(q->len == 0)
+ {
+ struct deflate_buff_queue *p;
+ p = q;
+ q = q->next;
+ reuse_queue(p);
+ }
+ }
+ encoder->qhead = q;
+ if(n == buff_size)
+ return n;
+
+ if(encoder->outoff < encoder->outcnt)
+ {
+ i = buff_size - n;
+ if(i > encoder->outcnt - encoder->outoff)
+ i = encoder->outcnt - encoder->outoff;
+ memcpy(buff + n, encoder->outbuf + encoder->outoff, i);
+ encoder->outoff += i;
+ n += i;
+ if(encoder->outcnt == encoder->outoff)
+ encoder->outcnt = encoder->outoff = 0;
+ }
+ return n;
+}
+
+
+/* ===========================================================================
+ * Allocate the match buffer, initialize the various tables and save the
+ * location of the internal file attribute (ascii/binary) and method
+ * (DEFLATE/STORE).
+ */
+local void ct_init(DeflateHandler encoder)
+{
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+
+ if(encoder->static_dtree[0].Len != 0) return; /* ct_init already called */
+
+ encoder->l_desc.dyn_tree = encoder->dyn_ltree;
+ encoder->l_desc.static_tree = encoder->static_ltree;
+ encoder->l_desc.extra_bits = extra_lbits;
+ encoder->l_desc.extra_base = LITERALS + 1;
+ encoder->l_desc.elems = L_CODES;
+ encoder->l_desc.max_length = MAX_BITS;
+ encoder->l_desc.max_code = 0;
+
+ encoder->d_desc.dyn_tree = encoder->dyn_dtree;
+ encoder->d_desc.static_tree = encoder->static_dtree;
+ encoder->d_desc.extra_bits = extra_dbits;
+ encoder->d_desc.extra_base = 0;
+ encoder->d_desc.elems = D_CODES;
+ encoder->d_desc.max_length = MAX_BITS;
+ encoder->d_desc.max_code = 0;
+
+ encoder->bl_desc.dyn_tree = encoder->bl_tree;
+ encoder->bl_desc.static_tree = NULL;
+ encoder->bl_desc.extra_bits = extra_blbits;
+ encoder->bl_desc.extra_base = 0;
+ encoder->bl_desc.elems = BL_CODES;
+ encoder->bl_desc.max_length = MAX_BL_BITS;
+ encoder->bl_desc.max_code = 0;
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for(code = 0; code < LENGTH_CODES-1; code++) {
+ encoder->base_length[code] = length;
+ for(n = 0; n < (1<<extra_lbits[code]); n++) {
+ encoder->length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "ct_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ encoder->length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for(code = 0 ; code < 16; code++) {
+ encoder->base_dist[code] = dist;
+ for(n = 0; n < (1<<extra_dbits[code]); n++) {
+ encoder->dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "ct_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for( ; code < D_CODES; code++) {
+ encoder->base_dist[code] = dist << 7;
+ for(n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ encoder->dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "ct_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for(bits = 0; bits <= MAX_BITS; bits++) encoder->bl_count[bits] = 0;
+ n = 0;
+ while(n <= 143) encoder->static_ltree[n++].Len = 8, encoder->bl_count[8]++;
+ while(n <= 255) encoder->static_ltree[n++].Len = 9, encoder->bl_count[9]++;
+ while(n <= 279) encoder->static_ltree[n++].Len = 7, encoder->bl_count[7]++;
+ while(n <= 287) encoder->static_ltree[n++].Len = 8, encoder->bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes(encoder, (ct_data near *)encoder->static_ltree, L_CODES+1);
+
+ /* The static distance tree is trivial: */
+ for(n = 0; n < D_CODES; n++) {
+ encoder->static_dtree[n].Len = 5;
+ encoder->static_dtree[n].Code = bi_reverse(n, 5);
+ }
+
+ /* Initialize the first block of the first file: */
+ init_block(encoder);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(DeflateHandler encoder)
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for(n = 0; n < L_CODES; n++) encoder->dyn_ltree[n].Freq = 0;
+ for(n = 0; n < D_CODES; n++) encoder->dyn_dtree[n].Freq = 0;
+ for(n = 0; n < BL_CODES; n++) encoder->bl_tree[n].Freq = 0;
+
+ encoder->dyn_ltree[END_BLOCK].Freq = 1;
+ encoder->opt_len = encoder->static_len = 0L;
+ encoder->last_lit = encoder->last_dist = encoder->last_flags = 0;
+ encoder->flags = 0;
+ encoder->flag_bit = 1;
+}
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(
+ DeflateHandler encoder,
+ ct_data near *tree, /* the tree to restore */
+ int k) /* node to move down */
+{
+ int v = encoder->heap[k];
+ int j = k << 1; /* left son of k */
+ while(j <= encoder->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if(j < encoder->heap_len &&
+ SMALLER(tree, encoder->heap[j+1], encoder->heap[j]))
+ j++;
+
+ /* Exit if v is smaller than both sons */
+ if(SMALLER(tree, v, encoder->heap[j]))
+ break;
+
+ /* Exchange v with the smallest son */
+ encoder->heap[k] = encoder->heap[j];
+ k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ encoder->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(
+ DeflateHandler encoder,
+ tree_desc near *desc) /* the tree descriptor */
+{
+ ct_data near *tree = desc->dyn_tree;
+ int near *extra = desc->extra_bits;
+ int base = desc->extra_base;
+ int max_code = desc->max_code;
+ int max_length = desc->max_length;
+ ct_data near *stree = desc->static_tree;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for(bits = 0; bits <= MAX_BITS; bits++)
+ encoder->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[encoder->heap[encoder->heap_max]].Len = 0; /* root of the heap */
+
+ for(h = encoder->heap_max+1; h < HEAP_SIZE; h++) {
+ n = encoder->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if(bits > max_length)
+ bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if(n > max_code)
+ continue; /* not a leaf node */
+
+ encoder->bl_count[bits]++;
+ xbits = 0;
+ if(n >= base)
+ xbits = extra[n-base];
+ f = tree[n].Freq;
+ encoder->opt_len += (ulg)f * (bits + xbits);
+ if(stree)
+ encoder->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if(overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while(encoder->bl_count[bits] == 0) bits--;
+ encoder->bl_count[bits]--; /* move one leaf down the tree */
+ encoder->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ encoder->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while(overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for(bits = max_length; bits != 0; bits--) {
+ n = encoder->bl_count[bits];
+ while(n != 0) {
+ m = encoder->heap[--h];
+ if(m > max_code) continue;
+ if(tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ encoder->opt_len +=
+ ((long)bits-(long)tree[m].Len)*(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes(
+ DeflateHandler encoder,
+ ct_data near *tree, /* the tree to decorate */
+ int max_code) /* largest code with non zero frequency */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for(bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + encoder->bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + encoder->bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for(n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if(len == 0)
+ continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracec(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(
+ DeflateHandler encoder,
+ tree_desc near *desc) /* the tree descriptor */
+{
+ ct_data near *tree = desc->dyn_tree;
+ ct_data near *stree = desc->static_tree;
+ int elems = desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node = elems; /* next internal node of the tree */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ encoder->heap_len = 0;
+ encoder->heap_max = HEAP_SIZE;
+
+ for(n = 0; n < elems; n++) {
+ if(tree[n].Freq != 0) {
+ encoder->heap[++encoder->heap_len] = max_code = n;
+ encoder->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while(encoder->heap_len < 2) {
+ int new = encoder->heap[++encoder->heap_len] =
+ (max_code < 2 ? ++max_code : 0);
+ tree[new].Freq = 1;
+ encoder->depth[new] = 0;
+ encoder->opt_len--;
+ if(stree)
+ encoder->static_len -= stree[new].Len;
+ /* new is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for(n = encoder->heap_len/2; n >= 1; n--)
+ pqdownheap(encoder, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ do {
+ n = encoder->heap[SMALLEST];
+ encoder->heap[SMALLEST] = encoder->heap[encoder->heap_len--];
+ pqdownheap(encoder, tree, SMALLEST);
+
+ m = encoder->heap[SMALLEST]; /* m = node of next least frequency */
+
+ /* keep the nodes sorted by frequency */
+ encoder->heap[--encoder->heap_max] = n;
+ encoder->heap[--encoder->heap_max] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ encoder->depth[node] =
+ (uch)(MAX(encoder->depth[n], encoder->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+
+ /* and insert the new node in the heap */
+ encoder->heap[SMALLEST] = node++;
+ pqdownheap(encoder, tree, SMALLEST);
+
+ } while(encoder->heap_len >= 2);
+
+ encoder->heap[--encoder->heap_max] = encoder->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(encoder, (tree_desc near *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes (encoder, (ct_data near *)tree, max_code);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree. Updates opt_len to take into account the repeat
+ * counts. (The contribution of the bit length codes will be added later
+ * during the construction of bl_tree.)
+ */
+local void scan_tree(
+ DeflateHandler encoder,
+ ct_data near *tree, /* the tree to be scanned */
+ int max_code) /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if(nextlen == 0)
+ max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for(n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if(++count < max_count && curlen == nextlen) {
+ continue;
+ } else if(count < min_count) {
+ encoder->bl_tree[curlen].Freq += count;
+ } else if(curlen != 0) {
+ if(curlen != prevlen)
+ encoder->bl_tree[curlen].Freq++;
+ encoder->bl_tree[REP_3_6].Freq++;
+ } else if(count <= 10) {
+ encoder->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ encoder->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if(nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if(curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree(
+ DeflateHandler encoder,
+ ct_data near *tree, /* the tree to be scanned */
+ int max_code) /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if(nextlen == 0) max_count = 138, min_count = 3;
+
+ for(n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if(++count < max_count && curlen == nextlen) {
+ continue;
+ } else if(count < min_count) {
+ do { SEND_CODE(curlen, encoder->bl_tree); } while(--count != 0);
+
+ } else if(curlen != 0) {
+ if(curlen != prevlen) {
+ SEND_CODE(curlen, encoder->bl_tree);
+ count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ SEND_CODE(REP_3_6, encoder->bl_tree);
+ send_bits(encoder, count-3, 2);
+
+ } else if(count <= 10) {
+ SEND_CODE(REPZ_3_10, encoder->bl_tree);
+ send_bits(encoder, count-3, 3);
+
+ } else {
+ SEND_CODE(REPZ_11_138, encoder->bl_tree);
+ send_bits(encoder, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if(nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if(curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(DeflateHandler encoder)
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(encoder,
+ (ct_data near *)encoder->dyn_ltree, encoder->l_desc.max_code);
+ scan_tree(encoder,
+ (ct_data near *)encoder->dyn_dtree, encoder->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(encoder, (tree_desc near *)(&encoder->bl_desc));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for(max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if(encoder->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ encoder->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ encoder->opt_len, encoder->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(
+ DeflateHandler encoder,
+ int lcodes, int dcodes, int blcodes) /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(encoder, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(encoder, dcodes-1, 5);
+ send_bits(encoder, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for(rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(encoder, encoder->bl_tree[bl_order[rank]].Len, 3);
+ }
+
+ /* send the literal tree */
+ send_tree(encoder, (ct_data near *)encoder->dyn_ltree,lcodes-1);
+
+ /* send the distance tree */
+ send_tree(encoder, (ct_data near *)encoder->dyn_dtree,dcodes-1);
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+local void flush_block(
+ DeflateHandler encoder,
+ int eof) /* true if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex; /* index of last bit length code of non zero freq */
+ ulg stored_len; /* length of input block */
+
+ stored_len = (ulg)(encoder->strstart - encoder->block_start);
+ encoder->flag_buf[encoder->last_flags] = encoder->flags; /* Save the flags for the last 8 items */
+
+ /* Construct the literal and distance trees */
+ build_tree(encoder, (tree_desc near *)(&encoder->l_desc));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld",
+ encoder->opt_len, encoder->static_len));
+
+ build_tree(encoder, (tree_desc near *)(&encoder->d_desc));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld",
+ encoder->opt_len, encoder->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(encoder);
+
+ /* Determine the best encoding. Compute first the block length in bytes */
+ opt_lenb = (encoder->opt_len +3+7)>>3;
+ static_lenb = (encoder->static_len+3+7)>>3;
+
+ Trace((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
+ opt_lenb, encoder->opt_len,
+ static_lenb, encoder->static_len, stored_len,
+ encoder->last_lit, encoder->last_dist));
+
+ if(static_lenb <= opt_lenb)
+ opt_lenb = static_lenb;
+ if(stored_len + 4 <= opt_lenb /* 4: two words for the lengths */
+ && encoder->block_start >= 0L) {
+ unsigned int i;
+ uch *p;
+
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ send_bits(encoder, (STORED_BLOCK<<1)+eof, 3); /* send block type */
+ bi_windup(encoder); /* align on byte boundary */
+ put_short((ush)stored_len);
+ put_short((ush)~stored_len);
+
+ /* copy block */
+ p = &encoder->window[(unsigned)encoder->block_start];
+ for(i = 0; i < stored_len; i++)
+ put_byte(p[i]);
+ } else if(static_lenb == opt_lenb) {
+ send_bits(encoder, (STATIC_TREES<<1)+eof, 3);
+ compress_block(encoder,
+ (ct_data near *)encoder->static_ltree,
+ (ct_data near *)encoder->static_dtree);
+ } else {
+ send_bits(encoder, (DYN_TREES<<1)+eof, 3);
+ send_all_trees(encoder,
+ encoder->l_desc.max_code+1,
+ encoder->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(encoder,
+ (ct_data near *)encoder->dyn_ltree,
+ (ct_data near *)encoder->dyn_dtree);
+ }
+
+ init_block(encoder);
+
+ if(eof)
+ bi_windup(encoder);
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+local int ct_tally(
+ DeflateHandler encoder,
+ int dist, /* distance of matched string */
+ int lc) /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ encoder->l_buf[encoder->last_lit++] = (uch)lc;
+ if(dist == 0) {
+ /* lc is the unmatched char */
+ encoder->dyn_ltree[lc].Freq++;
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)D_CODE(dist) < (ush)D_CODES, "ct_tally: bad match");
+
+ encoder->dyn_ltree[encoder->length_code[lc]+LITERALS+1].Freq++;
+ encoder->dyn_dtree[D_CODE(dist)].Freq++;
+
+ encoder->d_buf[encoder->last_dist++] = (ush)dist;
+ encoder->flags |= encoder->flag_bit;
+ }
+ encoder->flag_bit <<= 1;
+
+ /* Output the flags if they fill a byte: */
+ if((encoder->last_lit & 7) == 0) {
+ encoder->flag_buf[encoder->last_flags++] = encoder->flags;
+ encoder->flags = 0;
+ encoder->flag_bit = 1;
+ }
+ /* Try to guess if it is profitable to stop the current block here */
+ if(encoder->compr_level > 2 && (encoder->last_lit & 0xfff) == 0) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)encoder->last_lit*8L;
+ ulg in_length = (ulg)encoder->strstart - encoder->block_start;
+ int dcode;
+
+ for(dcode = 0; dcode < D_CODES; dcode++) {
+ out_length +=
+ (ulg)encoder->dyn_dtree[dcode].Freq *
+ (5L + extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Trace((stderr,"\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
+ encoder->last_lit, encoder->last_dist, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if(encoder->last_dist < encoder->last_lit/2 &&
+ out_length < in_length/2)
+ return 1;
+ }
+ return (encoder->last_lit == LIT_BUFSIZE-1 ||
+ encoder->last_dist == DIST_BUFSIZE);
+ /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(
+ DeflateHandler encoder,
+ ct_data near *ltree, /* literal tree */
+ ct_data near *dtree) /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned dx = 0; /* running index in d_buf */
+ unsigned fx = 0; /* running index in flag_buf */
+ uch flag = 0; /* current flags */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if(encoder->last_lit != 0) do {
+ if((lx & 7) == 0)
+ flag = encoder->flag_buf[fx++];
+ lc = encoder->l_buf[lx++];
+ if((flag & 1) == 0) {
+ SEND_CODE(lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = encoder->length_code[lc];
+ SEND_CODE(code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if(extra != 0) {
+ lc -= encoder->base_length[code];
+ send_bits(encoder, lc, extra); /* send the extra length bits */
+ }
+ dist = encoder->d_buf[dx++];
+ /* Here, dist is the match distance - 1 */
+ code = D_CODE(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ SEND_CODE(code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if(extra != 0) {
+ dist -= encoder->base_dist[code];
+ send_bits(encoder, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+ flag >>= 1;
+ } while(lx < encoder->last_lit);
+
+ SEND_CODE(END_BLOCK, ltree);
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#define Buf_size (8 * sizeof(ush)) /* bit size of bi_buf */
+local void send_bits(
+ DeflateHandler encoder,
+ int value, /* value to send */
+ int length) /* number of bits */
+{
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if(encoder->bi_valid > Buf_size - length) {
+ encoder->bi_buf |= (value << encoder->bi_valid);
+ put_short(encoder->bi_buf);
+ encoder->bi_buf = (ush)value >> (Buf_size - encoder->bi_valid);
+ encoder->bi_valid += length - Buf_size;
+ } else {
+ encoder->bi_buf |= value << encoder->bi_valid;
+ encoder->bi_valid += length;
+ }
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(
+ unsigned code, /* the value to invert */
+ int len) /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while(--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Write out any remaining bits in an incomplete byte.
+ */
+local void bi_windup(DeflateHandler encoder)
+{
+ if(encoder->bi_valid > 8) {
+ put_short(encoder->bi_buf);
+ } else if(encoder->bi_valid > 0) {
+ put_byte(encoder->bi_buf);
+ }
+ encoder->bi_buf = 0;
+ encoder->bi_valid = 0;
+}
+
+local void qoutbuf(DeflateHandler encoder)
+{
+ if(encoder->outcnt != 0)
+ {
+ struct deflate_buff_queue *q;
+ q = new_queue();
+ if(encoder->qhead == NULL)
+ encoder->qhead = encoder->qtail = q;
+ else
+ encoder->qtail = encoder->qtail->next = q;
+ q->len = encoder->outcnt - encoder->outoff;
+ memcpy(q->ptr, encoder->outbuf + encoder->outoff, q->len);
+ encoder->outcnt = encoder->outoff = 0;
+ }
+}
diff --git a/lib/timidity/libarc/explode.c b/lib/timidity/libarc/explode.c
new file mode 100644
index 0000000000..39c63ba0e9
--- /dev/null
+++ b/lib/timidity/libarc/explode.c
@@ -0,0 +1,1052 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+/* explode.c -- put in the public domain by Mark Adler
+ version c15, 6 July 1996 */
+
+
+/* You can do whatever you like with this source file, though I would
+ prefer that if you modify it and redistribute it that you include
+ comments to that effect with your name and the date. Thank you.
+
+ History:
+ vers date who what
+ ---- --------- -------------- ------------------------------------
+ c1 30 Mar 92 M. Adler explode that uses huft_build from inflate
+ (this gives over a 70% speed improvement
+ over the original unimplode.c, which
+ decoded a bit at a time)
+ c2 4 Apr 92 M. Adler fixed bug for file sizes a multiple of 32k.
+ c3 10 Apr 92 M. Adler added a little memory tracking if DEBUG
+ c4 11 Apr 92 M. Adler added NOMEMCPY do kill use of memcpy()
+ c5 21 Apr 92 M. Adler added the WSIZE #define to allow reducing
+ the 32K window size for specialized
+ applications.
+ c6 31 May 92 M. Adler added typecasts to eliminate some warnings
+ c7 27 Jun 92 G. Roelofs added more typecasts.
+ c8 17 Oct 92 G. Roelofs changed ULONG/UWORD/byte to ulg/ush/uch.
+ c9 19 Jul 93 J. Bush added more typecasts (to return values);
+ made l[256] array static for Amiga.
+ c10 8 Oct 93 G. Roelofs added used_csize for diagnostics; added
+ buf and unshrink arguments to flush();
+ undef'd various macros at end for Turbo C;
+ removed NEXTBYTE macro (now in unzip.h)
+ and bytebuf variable (not used); changed
+ memset() to memzero().
+ c11 9 Jan 94 M. Adler fixed incorrect used_csize calculation.
+ c12 9 Apr 94 G. Roelofs fixed split comments on preprocessor lines
+ to avoid bug in Encore compiler.
+ c13 25 Aug 94 M. Adler fixed distance-length comment (orig c9 fix)
+ c14 22 Nov 95 S. Maxwell removed unnecessary "static" on auto array
+ c15 6 Jul 96 W. Haidinger added ulg typecasts to flush() calls
+ */
+
+
+/*
+ Explode imploded (PKZIP method 6 compressed) data. This compression
+ method searches for as much of the current string of bytes (up to a length
+ of ~320) in the previous 4K or 8K bytes. If it doesn't find any matches
+ (of at least length 2 or 3), it codes the next byte. Otherwise, it codes
+ the length of the matched string and its distance backwards from the
+ current position. Single bytes ("literals") are preceded by a one (a
+ single bit) and are either uncoded (the eight bits go directly into the
+ compressed stream for a total of nine bits) or Huffman coded with a
+ supplied literal code tree. If literals are coded, then the minimum match
+ length is three, otherwise it is two.
+
+ There are therefore four kinds of imploded streams: 8K search with coded
+ literals (min match = 3), 4K search with coded literals (min match = 3),
+ 8K with uncoded literals (min match = 2), and 4K with uncoded literals
+ (min match = 2). The kind of stream is identified in two bits of a
+ general purpose bit flag that is outside of the compressed stream.
+
+ Distance-length pairs for matched strings are preceded by a zero bit (to
+ distinguish them from literals) and are always coded. The distance comes
+ first and is either the low six (4K) or low seven (8K) bits of the
+ distance (uncoded), followed by the high six bits of the distance coded.
+ Then the length is six bits coded (0..63 + min match length), and if the
+ maximum such length is coded, then it's followed by another eight bits
+ (uncoded) to be added to the coded length. This gives a match length
+ range of 2..320 or 3..321 bytes.
+
+ The literal, length, and distance codes are all represented in a slightly
+ compressed form themselves. What is sent are the lengths of the codes for
+ each value, which is sufficient to construct the codes. Each byte of the
+ code representation is the code length (the low four bits representing
+ 1..16), and the number of values sequentially with that length (the high
+ four bits also representing 1..16). There are 256 literal code values (if
+ literals are coded), 64 length code values, and 64 distance code values,
+ in that order at the beginning of the compressed stream. Each set of code
+ values is preceded (redundantly) with a byte indicating how many bytes are
+ in the code description that follows, in the range 1..256.
+
+ The codes themselves are decoded using tables made by huft_build() from
+ the bit lengths. That routine and its comments are in the inflate.c
+ module.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "timidity.h"
+#include "mblock.h"
+#include "explode.h"
+#include "zip.h"
+
+struct _ExplodeHandler
+{
+ void *user_val;
+ long (* read_func)(char *buf, long size, void *user_val);
+ int method;
+
+ int initflag;
+ unsigned insize; /* valid bytes in inbuf */
+ unsigned inptr; /* index of next byte to be processed in inbuf */
+ uch inbuf[INBUFSIZ];
+
+ ulg bit_buf; /* bit buffer */
+ ulg bit_len; /* bits in bit buffer */
+
+ uch slide[WSIZE];
+ struct huft *tb; /* literal, length, and distance tables */
+ struct huft *tl;
+ struct huft *td;
+ int bb; /* number of bits decoded by those */
+ int bl;
+ int bd;
+
+ unsigned u, n, d, w;
+ long s; /* original size */
+ long csize; /* compressed size */
+ unsigned l[256]; /* bit lengths for codes */
+
+ MBlockList pool;
+
+ int eof;
+};
+
+/* routines here */
+static int get_tree(ExplodeHandler decoder, unsigned *l, unsigned n);
+static int fill_inbuf(ExplodeHandler decoder);
+static long explode_lit8(ExplodeHandler decoder, char *buff, long size);
+static long explode_lit4(ExplodeHandler decoder, char *buff, long size);
+static long explode_nolit8(ExplodeHandler decoder,char *buff, long size);
+static long explode_nolit4(ExplodeHandler decoder,char *buff, long size);
+
+
+/* The implode algorithm uses a sliding 4K or 8K byte window on the
+ uncompressed stream to find repeated byte strings. This is implemented
+ here as a circular buffer. The index is updated simply by incrementing
+ and then and'ing with 0x0fff (4K-1) or 0x1fff (8K-1). Here, the 32K
+ buffer of inflate is used, and it works just as well to always have
+ a 32K circular buffer, so the index is anded with 0x7fff. This is
+ done to allow the window to also be used as the output buffer. */
+/* This must be supplied in an external module useable like "uch slide[8192];"
+ or "uch *slide;", where the latter would be malloc'ed. In unzip, slide[]
+ is actually a 32K area for use by inflate, which uses a 32K sliding window.
+ */
+
+
+/* Tables for length and distance */
+static ush cplen2[] =
+ {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65};
+static ush cplen3[] =
+ {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66};
+static ush extra[] =
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 8};
+static ush cpdist4[] =
+ {1, 65, 129, 193, 257, 321, 385, 449, 513, 577, 641, 705,
+ 769, 833, 897, 961, 1025, 1089, 1153, 1217, 1281, 1345, 1409, 1473,
+ 1537, 1601, 1665, 1729, 1793, 1857, 1921, 1985, 2049, 2113, 2177,
+ 2241, 2305, 2369, 2433, 2497, 2561, 2625, 2689, 2753, 2817, 2881,
+ 2945, 3009, 3073, 3137, 3201, 3265, 3329, 3393, 3457, 3521, 3585,
+ 3649, 3713, 3777, 3841, 3905, 3969, 4033};
+static ush cpdist8[] =
+ {1, 129, 257, 385, 513, 641, 769, 897, 1025, 1153, 1281,
+ 1409, 1537, 1665, 1793, 1921, 2049, 2177, 2305, 2433, 2561, 2689,
+ 2817, 2945, 3073, 3201, 3329, 3457, 3585, 3713, 3841, 3969, 4097,
+ 4225, 4353, 4481, 4609, 4737, 4865, 4993, 5121, 5249, 5377, 5505,
+ 5633, 5761, 5889, 6017, 6145, 6273, 6401, 6529, 6657, 6785, 6913,
+ 7041, 7169, 7297, 7425, 7553, 7681, 7809, 7937, 8065};
+
+
+/* Macros for inflate() bit peeking and grabbing.
+ The usage is:
+
+ NEEDBITS(j)
+ x = GETBITS(j)
+ DUMPBITS(j)
+
+ where NEEDBITS makes sure that b has at least j bits in it, and
+ DUMPBITS removes the bits from b. The macros use the variable k
+ for the number of bits in b. Normally, b and k are register
+ variables for speed.
+ */
+
+#define NEXTBYTE (decoder->inptr < decoder->insize ? decoder->inbuf[decoder->inptr++] : fill_inbuf(decoder))
+#define MASK_BITS(n) ((((ulg)1)<<(n))-1)
+#define NEEDBITS(n) {while(decoder->bit_len<(n)){decoder->bit_buf|=((ulg)NEXTBYTE)<<decoder->bit_len;decoder->bit_len+=8;}}
+#define GETBITS(n) ((ulg)decoder->bit_buf & MASK_BITS(n))
+#define IGETBITS(n) ((~((ulg)decoder->bit_buf)) & MASK_BITS(n))
+#define DUMPBITS(n) {decoder->bit_buf>>=(n);decoder->bit_len-=(n);}
+
+
+/*ARGSUSED*/
+static long default_read_func(char *buf, long size, void *v)
+{
+ return (long)fread(buf, 1, size, stdin);
+}
+
+ExplodeHandler open_explode_handler(
+ long (* read_func)(char *buf, long size, void *user_val),
+ int method,
+ long compsize, long origsize,
+ void *user_val)
+{
+ ExplodeHandler decoder;
+
+ decoder = (ExplodeHandler)malloc(sizeof(struct _ExplodeHandler));
+ if(decoder == NULL)
+ return NULL;
+ memset(decoder, 0, sizeof(struct _ExplodeHandler));
+
+ decoder->user_val = user_val;
+ if(read_func == NULL)
+ decoder->read_func = default_read_func;
+ else
+ decoder->read_func = read_func;
+ decoder->insize = 0;
+ decoder->method = method;
+ decoder->bit_buf = 0;
+ decoder->bit_len = 0;
+
+ decoder->u = 1;
+ decoder->n = 0;
+ decoder->d = 0;
+ decoder->w = 0;
+ decoder->s = origsize;
+
+ decoder->csize = compsize;
+ decoder->eof = 0;
+ decoder->initflag = 0;
+ init_mblock(&decoder->pool);
+
+ /* Tune base table sizes. Note: I thought that to truly optimize speed,
+ I would have to select different bl, bd, and bb values for different
+ compressed file sizes. I was suprised to find out the the values of
+ 7, 7, and 9 worked best over a very wide range of sizes, except that
+ bd = 8 worked marginally better for large compressed sizes. */
+ decoder->bl = 7;
+#if 0
+ decoder->bd = (G.csize + G.incnt) > 200000L ? 8 : 7;
+#else
+ decoder->bd = (compsize > 200000L ? 8 : 7);
+#endif
+
+ return decoder;
+}
+
+static int explode_start(ExplodeHandler decoder)
+{
+ int method;
+
+ method = decoder->method;
+
+ /* With literal tree--minimum match length is 3 */
+ if(method == EXPLODE_LIT8 || method == EXPLODE_LIT4)
+ {
+ decoder->bb = 9; /* base table size for literals */
+ if(get_tree(decoder, decoder->l, 256) != 0)
+ return 1;
+
+ if(huft_build(decoder->l, 256, 256, NULL, NULL,
+ &decoder->tb, &decoder->bb, &decoder->pool) != 0)
+ return 1;
+
+ if(get_tree(decoder, decoder->l, 64) != 0)
+ return 1;
+
+ if(huft_build(decoder->l, 64, 0, cplen3, extra,
+ &decoder->tl, &decoder->bl, &decoder->pool) != 0)
+ return 1;
+
+ if(get_tree(decoder, decoder->l, 64) != 0)
+ return 1;
+
+ if(method == EXPLODE_LIT8)
+ {
+ if(huft_build(decoder->l, 64, 0, cpdist8, extra,
+ &decoder->td, &decoder->bd, &decoder->pool) != 0)
+ return 1;
+ }
+ else
+ {
+ if(huft_build(decoder->l, 64, 0, cpdist4, extra,
+ &decoder->td, &decoder->bd, &decoder->pool) != 0)
+ return 1;
+ }
+ }
+ else /* EXPLODE_NOLIT8 or EXPLODE_NOLIT4 */
+ {
+ if(get_tree(decoder, decoder->l, 64) != 0)
+ return 1;
+
+ if(huft_build(decoder->l, 64, 0, cplen2, extra,
+ &decoder->tl, &decoder->bl, &decoder->pool) != 0)
+ return 1;
+
+ if(get_tree(decoder, decoder->l, 64) != 0)
+ return 1;
+
+ if(method == EXPLODE_NOLIT8)
+ {
+ if(huft_build(decoder->l, 64, 0, cpdist8, extra,
+ &decoder->td, &decoder->bd, &decoder->pool) != 0)
+ return 1;
+ }
+ else
+ {
+ if(huft_build(decoder->l, 64, 0, cpdist4, extra,
+ &decoder->td, &decoder->bd, &decoder->pool) != 0)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+void close_explode_handler(ExplodeHandler decoder)
+{
+ free(decoder);
+}
+
+
+static int get_tree(
+ ExplodeHandler decoder,
+ unsigned *l, /* bit lengths */
+ unsigned n) /* number expected */
+/* Get the bit lengths for a code representation from the compressed
+ stream. If get_tree() returns 4, then there is an error in the data.
+ Otherwise zero is returned. */
+{
+ unsigned i; /* bytes remaining in list */
+ unsigned k; /* lengths entered */
+ unsigned j; /* number of codes */
+ unsigned b; /* bit length for those codes */
+
+ /* get bit lengths */
+ i = NEXTBYTE + 1; /* length/count pairs to read */
+ k = 0; /* next code */
+ do {
+ b = ((j = NEXTBYTE) & 0xf) + 1; /* bits in code (1..16) */
+ j = ((j & 0xf0) >> 4) + 1; /* codes with those bits (1..16) */
+ if (k + j > n)
+ return 4; /* don't overflow l[] */
+ do {
+ l[k++] = b;
+ } while (--j);
+ } while (--i);
+
+ return k != n ? 4 : 0; /* should have read n of them */
+}
+
+
+
+static long explode_lit8(ExplodeHandler decoder, char *buff, long size)
+/* Decompress the imploded data using coded literals and an 8K sliding
+ window. */
+{
+ long s; /* bytes to decompress */
+ register unsigned e; /* table entry flag/number of extra bits */
+ unsigned n, d; /* length and index for copy */
+ unsigned w; /* current window position */
+ struct huft *t; /* pointer to table entry */
+ unsigned u; /* true if unflushed */
+ long j;
+ struct huft *tb, *tl, *td; /* literal, length, and distance tables */
+ int bb, bl, bd; /* number of bits decoded by those */
+
+ tb = decoder->tb;
+ tl = decoder->tl;
+ td = decoder->td;
+ bb = decoder->bb;
+ bl = decoder->bl;
+ bd = decoder->bd;
+
+ /* explode the coded data */
+ s = decoder->s;
+ w = decoder->w;
+ u = decoder->u;
+ j = 0;
+
+ while(s > 0) /* do until ucsize bytes uncompressed */
+ {
+ NEEDBITS(1);
+ if(decoder->bit_buf & 1) /* then literal--decode it */
+ {
+ DUMPBITS(1);
+ s--;
+ NEEDBITS((unsigned)bb); /* get coded literal */
+ t = tb + IGETBITS(bb);
+ e = t->e;
+ while(e > 16)
+ {
+ if(e == 99)
+ return -1;
+ DUMPBITS(t->b);
+ e -= 16;
+ NEEDBITS(e);
+ t = t->v.t + IGETBITS(e);
+ e = t->e;
+ }
+ DUMPBITS(t->b);
+ buff[j++] = decoder->slide[w++] = (uch)t->v.n;
+ if(w == WSIZE)
+ w = u = 0;
+ if(j == size)
+ {
+ decoder->u = u;
+ decoder->w = w;
+ decoder->s = s;
+ return size;
+ }
+ }
+ else /* else distance/length */
+ {
+ DUMPBITS(1);
+ NEEDBITS(7); /* get distance low bits */
+ d = GETBITS(7);
+ DUMPBITS(7);
+ NEEDBITS((unsigned)bd); /* get coded distance high bits */
+ t = td + IGETBITS(bd);
+ e = t->e;
+ while(e > 16)
+ {
+ if(e == 99)
+ return -1;
+ DUMPBITS(t->b);
+ e -= 16;
+ NEEDBITS(e);
+ t = t->v.t + IGETBITS(e);
+ e = t->e;
+ }
+ DUMPBITS(t->b);
+ d = w - d - t->v.n; /* construct offset */
+ NEEDBITS((unsigned)bl); /* get coded length */
+ t = tl + IGETBITS(bl);
+ e = t->e;
+ while(e > 16)
+ {
+ if(e == 99)
+ return -1;
+ DUMPBITS(t->b);
+ e -= 16;
+ NEEDBITS(e);
+ t = t->v.t + IGETBITS(e);
+ e = t->e;
+ }
+ DUMPBITS(t->b);
+ n = t->v.n;
+ if(e) /* get length extra bits */
+ {
+ NEEDBITS(8);
+ n += GETBITS(8);
+ DUMPBITS(8);
+ }
+
+ /* do the copy */
+ s -= n;
+ while(n > 0 && j < size)
+ {
+ n--;
+ d &= WSIZE - 1;
+ w &= WSIZE - 1;
+ if(u && w <= d)
+ {
+ buff[j++] = 0;
+ w++;
+ d++;
+ }
+ else
+ buff[j++] = decoder->slide[w++] = decoder->slide[d++];
+ if(w == WSIZE)
+ w = u = 0;
+ }
+ if(j == size)
+ {
+ decoder->u = u;
+ decoder->n = n;
+ decoder->d = d;
+ decoder->w = w;
+ decoder->s = s;
+ return size;
+ }
+ decoder->n = 0;
+ }
+ }
+
+ decoder->n = 0;
+ decoder->w = 0;
+ decoder->eof = 1;
+ return j;
+}
+
+
+
+static long explode_lit4(ExplodeHandler decoder, char *buff, long size)
+/* Decompress the imploded data using coded literals and a 4K sliding
+ window. */
+{
+ long s; /* bytes to decompress */
+ register unsigned e; /* table entry flag/number of extra bits */
+ unsigned n, d; /* length and index for copy */
+ unsigned w; /* current window position */
+ struct huft *t; /* pointer to table entry */
+ unsigned u; /* true if unflushed */
+ long j;
+ struct huft *tb, *tl, *td; /* literal, length, and distance tables */
+ int bb, bl, bd; /* number of bits decoded by those */
+
+ tb = decoder->tb;
+ tl = decoder->tl;
+ td = decoder->td;
+ bb = decoder->bb;
+ bl = decoder->bl;
+ bd = decoder->bd;
+
+ /* explode the coded data */
+ s = decoder->s;
+ w = decoder->w;
+ u = decoder->u;
+ j = 0;
+
+ while(s > 0) /* do until ucsize bytes uncompressed */
+ {
+ NEEDBITS(1);
+ if(decoder->bit_buf & 1) /* then literal--decode it */
+ {
+ DUMPBITS(1);
+ s--;
+ NEEDBITS((unsigned)bb); /* get coded literal */
+ t = tb + IGETBITS(bb);
+ e = t->e;
+ while(e > 16)
+ {
+ if(e == 99)
+ return -1;
+ DUMPBITS(t->b);
+ e -= 16;
+ NEEDBITS(e);
+ t = t->v.t + IGETBITS(e);
+ }
+ DUMPBITS(t->b);
+ buff[j++] = decoder->slide[w++] = (uch)t->v.n;
+ if(w == WSIZE)
+ w = u = 0;
+ if(j == size)
+ {
+ decoder->u = u;
+ decoder->w = w;
+ decoder->s = s;
+ return size;
+ }
+ }
+ else /* else distance/length */
+ {
+ DUMPBITS(1);
+ NEEDBITS(6); /* get distance low bits */
+ d = GETBITS(6);
+ DUMPBITS(6);
+ NEEDBITS((unsigned)bd); /* get coded distance high bits */
+ t = td + IGETBITS(bd);
+ e = t->e;
+ while(e > 16)
+ {
+ if(e == 99)
+ return -1;
+ DUMPBITS(t->b);
+ e -= 16;
+ NEEDBITS(e);
+ t = t->v.t + IGETBITS(e);
+ e = t->e;
+ }
+ DUMPBITS(t->b);
+ d = w - d - t->v.n; /* construct offset */
+ NEEDBITS((unsigned)bl); /* get coded length */
+ t = tl + IGETBITS(bl);
+ e = t->e;
+ while(e > 16)
+ {
+ if(e == 99)
+ return -1;
+ DUMPBITS(t->b);
+ e -= 16;
+ NEEDBITS(e);
+ t = t->v.t + IGETBITS(e);
+ e = t->e;
+ }
+ DUMPBITS(t->b);
+ n = t->v.n;
+ if(e) /* get length extra bits */
+ {
+ NEEDBITS(8);
+ n += GETBITS(8);
+ DUMPBITS(8);
+ }
+
+ /* do the copy */
+ s -= n;
+ while(n > 0 && j < size)
+ {
+ n--;
+ d &= WSIZE - 1;
+ w &= WSIZE - 1;
+ if(u && w <= d)
+ {
+ buff[j++] = 0;
+ w++;
+ d++;
+ }
+ else
+ buff[j++] = decoder->slide[w++] = decoder->slide[d++];
+ if(w == WSIZE)
+ w = u = 0;
+ }
+ if(j == size)
+ {
+ decoder->u = u;
+ decoder->n = n;
+ decoder->d = d;
+ decoder->w = w;
+ decoder->s = s;
+ return size;
+ }
+ decoder->n = 0;
+ }
+ }
+
+ decoder->n = 0;
+ decoder->w = 0;
+ decoder->eof = 1;
+ return j;
+}
+
+
+
+static long explode_nolit8(ExplodeHandler decoder, char *buff, long size)
+/* Decompress the imploded data using uncoded literals and an 8K sliding
+ window. */
+{
+ long s; /* bytes to decompress */
+ register unsigned e; /* table entry flag/number of extra bits */
+ unsigned n, d; /* length and index for copy */
+ unsigned w; /* current window position */
+ struct huft *t; /* pointer to table entry */
+ unsigned u; /* true if unflushed */
+ long j;
+ struct huft *tl, *td; /* length and distance decoder tables */
+ int bl, bd; /* number of bits decoded by tl[] and td[] */
+
+ tl = decoder->tl;
+ td = decoder->td;
+ bl = decoder->bl;
+ bd = decoder->bd;
+
+ /* explode the coded data */
+#if 0
+ b = k = w = 0; /* initialize bit buffer, window */
+ u = 1; /* buffer unflushed */
+ ml = mask_bits[bl]; /* precompute masks for speed */
+ md = mask_bits[bd];
+ s = G.ucsize;
+#endif
+
+ s = decoder->s;
+ w = decoder->w;
+ u = decoder->u;
+ j = 0;
+
+ while(s > 0) /* do until ucsize bytes uncompressed */
+ {
+ NEEDBITS(1);
+ if(decoder->bit_buf & 1) /* then literal--get eight bits */
+ {
+ DUMPBITS(1);
+ s--;
+ NEEDBITS(8);
+ buff[j++] = decoder->slide[w++] = (uch)decoder->bit_buf;;
+ DUMPBITS(8);
+ if(w == WSIZE)
+ w = u = 0;
+ if(j == size)
+ {
+ decoder->u = u;
+ decoder->w = w;
+ decoder->s = s;
+ return size;
+ }
+ }
+ else /* else distance/length */
+ {
+ DUMPBITS(1);
+ NEEDBITS(7); /* get distance low bits */
+ d = GETBITS(7);
+ DUMPBITS(7);
+ NEEDBITS((unsigned)bd); /* get coded distance high bits */
+ t = td + IGETBITS(bd);
+ e = t->e;
+ while(e > 16)
+ {
+ if(e == 99)
+ return -1;
+ DUMPBITS(t->b);
+ e -= 16;
+ NEEDBITS(e);
+ t = t->v.t + IGETBITS(e);
+ e = t->e;
+ }
+ DUMPBITS(t->b);
+ d = w - d - t->v.n; /* construct offset */
+ NEEDBITS((unsigned)bl); /* get coded length */
+ t = tl + IGETBITS(bl);
+ e = t->e;
+ while(e > 16)
+ {
+ if(e == 99)
+ return -1;
+ DUMPBITS(t->b);
+ e -= 16;
+ NEEDBITS(e);
+ t = t->v.t + IGETBITS(e);
+ e = t->e;
+ }
+ DUMPBITS(t->b);
+ n = t->v.n;
+ if(e) /* get length extra bits */
+ {
+ NEEDBITS(8);
+ n += GETBITS(8);
+ DUMPBITS(8);
+ }
+
+ /* do the copy */
+ s -= n;
+ while(n > 0 && j < size)
+ {
+ n--;
+ d &= WSIZE - 1;
+ w &= WSIZE - 1;
+ if(u && w <= d)
+ {
+ buff[j++] = 0;
+ w++;
+ d++;
+ }
+ else
+ buff[j++] = decoder->slide[w++] = decoder->slide[d++];
+ if(w == WSIZE)
+ w = u = 0;
+ }
+ if(j == size)
+ {
+ decoder->u = u;
+ decoder->n = n;
+ decoder->d = d;
+ decoder->w = w;
+ decoder->s = s;
+ return size;
+ }
+ decoder->n = 0;
+ }
+ }
+
+ decoder->n = 0;
+ decoder->w = 0;
+ decoder->eof = 1;
+ return j;
+}
+
+
+
+static long explode_nolit4(ExplodeHandler decoder, char *buff, long size)
+/* Decompress the imploded data using uncoded literals and a 4K sliding
+ window. */
+{
+ long s; /* bytes to decompress */
+ register unsigned e; /* table entry flag/number of extra bits */
+ unsigned n, d; /* length and index for copy */
+ unsigned w; /* current window position */
+ struct huft *t; /* pointer to table entry */
+ unsigned u; /* true if unflushed */
+ long j;
+ struct huft *tl, *td; /* length and distance decoder tables */
+ int bl, bd; /* number of bits decoded by tl[] and td[] */
+
+ tl = decoder->tl;
+ td = decoder->td;
+ bl = decoder->bl;
+ bd = decoder->bd;
+
+ /* explode the coded data */
+#if 0
+ b = k = w = 0; /* initialize bit buffer, window */
+ u = 1; /* buffer unflushed */
+ ml = mask_bits[bl]; /* precompute masks for speed */
+ md = mask_bits[bd];
+ s = G.ucsize;
+#endif
+ s = decoder->s;
+ w = decoder->w;
+ u = decoder->u;
+ j = 0;
+
+ while(s > 0) /* do until ucsize bytes uncompressed */
+ {
+ NEEDBITS(1);
+ if(decoder->bit_buf & 1) /* then literal--get eight bits */
+ {
+ DUMPBITS(1);
+ s--;
+ NEEDBITS(8);
+ buff[j++] = decoder->slide[w++] = (uch)decoder->bit_buf;
+ DUMPBITS(8);
+ if(w == WSIZE)
+ w = u = 0;
+ if(j == size)
+ {
+ decoder->u = u;
+ decoder->w = w;
+ decoder->s = s;
+ return size;
+ }
+ }
+ else /* else distance/length */
+ {
+ DUMPBITS(1);
+ NEEDBITS(6); /* get distance low bits */
+#if 0
+ d = (unsigned)b & 0x3f;
+#else
+ d = GETBITS(6);
+#endif
+ DUMPBITS(6);
+ NEEDBITS((unsigned)bd); /* get coded distance high bits */
+ t = td + IGETBITS(bd);
+ e = t->e;
+ while(e > 16)
+ {
+ if(e == 99)
+ return -1;
+ DUMPBITS(t->b);
+ e -= 16;
+ NEEDBITS(e);
+ t = t->v.t + IGETBITS(e);
+ e = t->e;
+ }
+ DUMPBITS(t->b);
+ d = w - d - t->v.n; /* construct offset */
+ NEEDBITS((unsigned)bl); /* get coded length */
+ /*t =*/ t = tl + IGETBITS(bl);
+ e = t->e;
+ while(e > 16)
+ {
+ if(e == 99)
+ return -1;
+ DUMPBITS(t->b);
+ e -= 16;
+ NEEDBITS(e);
+ t = t->v.t + IGETBITS(e);
+ e = t->e;
+ }
+ DUMPBITS(t->b);
+ n = t->v.n;
+ if(e) /* get length extra bits */
+ {
+ NEEDBITS(8);
+ n += GETBITS(8);
+ DUMPBITS(8);
+ }
+
+ /* do the copy */
+ s -= n;
+ while(n > 0 && j < size)
+ {
+ n--;
+ d &= WSIZE - 1;
+ w &= WSIZE - 1;
+ if(u && w <= d)
+ {
+ buff[j++] = 0;
+ w++;
+ d++;
+ }
+ else
+ buff[j++] = decoder->slide[w++] = decoder->slide[d++];
+ if(w == WSIZE)
+ w = u = 0;
+ }
+ if(j == size)
+ {
+ decoder->u = u;
+ decoder->n = n;
+ decoder->d = d;
+ decoder->w = w;
+ decoder->s = s;
+ return size;
+ }
+ decoder->n = 0;
+ }
+ }
+
+ decoder->n = 0;
+ decoder->w = 0;
+ decoder->eof = 1;
+ return j;
+}
+
+
+
+long explode(ExplodeHandler decoder, char *buff, long size)
+/* Explode an imploded compressed stream. Based on the general purpose
+ bit flag, decide on coded or uncoded literals, and an 8K or 4K sliding
+ window. Construct the literal (if any), length, and distance codes and
+ the tables needed to decode them (using huft_build() from inflate.c),
+ and call the appropriate routine for the type of data in the remainder
+ of the stream. The four routines are nearly identical, differing only
+ in whether the literal is decoded or simply read in, and in how many
+ bits are read in, uncoded, for the low distance bits. */
+{
+ long j, i;
+
+ if(size <= 0)
+ return size;
+
+ if(!decoder->initflag)
+ {
+ decoder->initflag = 1;
+ if(explode_start(decoder) != 0)
+ return 0;
+ }
+
+ j = 0;
+ while(j < size)
+ {
+ if(decoder->n > 0) /* do the copy */
+ {
+ unsigned u, n, w, d;
+
+ u = decoder->u;
+ n = decoder->n;
+ d = decoder->d;
+ w = decoder->w;
+ while(n > 0 && j < size)
+ {
+ n--;
+ d &= WSIZE - 1;
+ w &= WSIZE - 1;
+ if(u && w <= d)
+ {
+ buff[j++] = 0;
+ w++;
+ d++;
+ }
+ else
+ buff[j++] = decoder->slide[w++] = decoder->slide[d++];
+ if(w == WSIZE)
+ w = u = 0;
+ }
+
+ decoder->u = u;
+ decoder->n = n;
+ decoder->d = d;
+ decoder->w = w;
+ if(j == size)
+ return size;
+ }
+
+ /* decoder->n == 0 */
+ if(decoder->eof)
+ return j;
+
+ switch(decoder->method)
+ {
+ case EXPLODE_LIT8:
+ i = explode_lit8(decoder, buff + j, size - j);
+ break;
+ case EXPLODE_LIT4:
+ i = explode_lit4(decoder, buff + j, size - j);
+ break;
+ case EXPLODE_NOLIT8:
+ i = explode_nolit8(decoder, buff + j, size - j);
+ break;
+ case EXPLODE_NOLIT4:
+ i = explode_nolit4(decoder, buff + j, size - j);
+ break;
+ default:
+ i = -1;
+ break;
+ }
+ if(i == -1)
+ return -1;
+ j += i;
+ }
+ return j;
+}
+
+
+
+static int fill_inbuf(ExplodeHandler decoder)
+{
+ int len;
+
+ /* Read as much as possible */
+ decoder->insize = 0;
+ errno = 0;
+ do {
+ len = decoder->read_func((char*)decoder->inbuf + decoder->insize,
+ (long)(INBUFSIZ - decoder->insize),
+ decoder->user_val);
+ if(len == 0 || len == EOF) break;
+ decoder->insize += len;
+ } while(decoder->insize < INBUFSIZ);
+
+ if(decoder->insize == 0)
+ return EOF;
+ decoder->inptr = 1;
+ return decoder->inbuf[0];
+}
+
diff --git a/lib/timidity/libarc/explode.h b/lib/timidity/libarc/explode.h
new file mode 100644
index 0000000000..9ea76f3cf1
--- /dev/null
+++ b/lib/timidity/libarc/explode.h
@@ -0,0 +1,47 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifndef ___EXPLODE_H_
+#define ___EXPLODE_H_
+
+typedef struct _ExplodeHandler *ExplodeHandler;
+
+enum explode_method_t
+{
+ EXPLODE_LIT8,
+ EXPLODE_LIT4,
+ EXPLODE_NOLIT8,
+ EXPLODE_NOLIT4
+};
+
+extern ExplodeHandler open_explode_handler(
+ long (* read_func)(char *buf, long size, void *user_val),
+ int method,
+ long compsize, long origsize,
+ void *user_val);
+
+extern long explode(ExplodeHandler decoder,
+ char *decode_buff,
+ long decode_buff_size);
+
+extern void close_explode_handler(ExplodeHandler decoder);
+
+
+#endif /* ___EXPLODE_H_ */
diff --git a/lib/timidity/libarc/inflate.c b/lib/timidity/libarc/inflate.c
new file mode 100644
index 0000000000..8231a7fcf0
--- /dev/null
+++ b/lib/timidity/libarc/inflate.c
@@ -0,0 +1,1045 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+/* inflate.c -- Not copyrighted 1992 by Mark Adler
+ version c10p1, 10 January 1993 */
+
+/* You can do whatever you like with this source file, though I would
+ prefer that if you modify it and redistribute it that you include
+ comments to that effect with your name and the date. Thank you.
+ [The history has been moved to the file ChangeLog.]
+ */
+
+/*
+ Inflate deflated (PKZIP's method 8 compressed) data. The compression
+ method searches for as much of the current string of bytes (up to a
+ length of 258) in the previous 32K bytes. If it doesn't find any
+ matches (of at least length 3), it codes the next byte. Otherwise, it
+ codes the length of the matched string and its distance backwards from
+ the current position. There is a single Huffman code that codes both
+ single bytes (called "literals") and match lengths. A second Huffman
+ code codes the distance information, which follows a length code. Each
+ length or distance code actually represents a base value and a number
+ of "extra" (sometimes zero) bits to get to add to the base value. At
+ the end of each deflated block is a special end-of-block (EOB) literal/
+ length code. The decoding process is basically: get a literal/length
+ code; if EOB then done; if a literal, emit the decoded byte; if a
+ length then get the distance and emit the referred-to bytes from the
+ sliding window of previously emitted data.
+
+ There are (currently) three kinds of inflate blocks: stored, fixed, and
+ dynamic. The compressor outputs a chunk of data at a time and decides
+ which method to use on a chunk-by-chunk basis. A chunk might typically
+ be 32K to 64K, uncompressed. If the chunk is uncompressible, then the
+ "stored" method is used. In this case, the bytes are simply stored as
+ is, eight bits per byte, with none of the above coding. The bytes are
+ preceded by a count, since there is no longer an EOB code.
+
+ If the data are compressible, then either the fixed or dynamic methods
+ are used. In the dynamic method, the compressed data are preceded by
+ an encoding of the literal/length and distance Huffman codes that are
+ to be used to decode this block. The representation is itself Huffman
+ coded, and so is preceded by a description of that code. These code
+ descriptions take up a little space, and so for small blocks, there is
+ a predefined set of codes, called the fixed codes. The fixed method is
+ used if the block ends up smaller that way (usually for quite small
+ chunks); otherwise the dynamic method is used. In the latter case, the
+ codes are customized to the probabilities in the current block and so
+ can code it much better than the pre-determined fixed codes can.
+
+ The Huffman codes themselves are decoded using a multi-level table
+ lookup, in order to maximize the speed of decoding plus the speed of
+ building the decoding tables. See the comments below that precede the
+ lbits and dbits tuning parameters.
+ */
+
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarily, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "timidity.h"
+#include "mblock.h"
+#include "zip.h"
+#define local static
+
+/* Save to local */
+#define BITS_SAVE \
+ ulg bit_buf = decoder->bit_buf; \
+ ulg bit_len = decoder->bit_len;
+
+/* Restore to decoder */
+#define BITS_RESTORE \
+ decoder->bit_buf = bit_buf; \
+ decoder->bit_len = bit_len;
+
+#define MASK_BITS(n) ((((ulg)1)<<(n))-1)
+#define GET_BYTE() (decoder->inptr < decoder->insize ? decoder->inbuf[decoder->inptr++] : fill_inbuf(decoder))
+#define NEEDBITS(n) {while(bit_len<(n)){bit_buf|=((ulg)GET_BYTE())<<bit_len;bit_len+=8;}}
+#define GETBITS(n) (bit_buf & MASK_BITS(n))
+#define DUMPBITS(n) {bit_buf>>=(n);bit_len-=(n);}
+
+/* variables */
+struct _InflateHandler
+{
+ void *user_val;
+ long (* read_func)(char *buf, long size, void *user_val);
+
+ uch slide[2L * WSIZE];
+ uch inbuf[INBUFSIZ + INBUF_EXTRA];
+ unsigned wp; /* current position in slide */
+ unsigned insize; /* valid bytes in inbuf */
+ unsigned inptr; /* index of next byte to be processed in inbuf */
+ struct huft *fixed_tl; /* inflate static */
+ struct huft *fixed_td; /* inflate static */
+ int fixed_bl, fixed_bd; /* inflate static */
+ ulg bit_buf; /* bit buffer */
+ ulg bit_len; /* bits in bit buffer */
+ int method;
+ int eof;
+ unsigned copy_leng;
+ unsigned copy_dist;
+ struct huft *tl, *td; /* literal/length and distance decoder tables */
+ int bl, bd; /* number of bits decoded by tl[] and td[] */
+ MBlockList pool; /* memory buffer for tl, td */
+};
+
+/* Function prototypes */
+local int fill_inbuf(InflateHandler);
+local int huft_free(struct huft *);
+local long inflate_codes(InflateHandler, char *, long);
+local long inflate_stored(InflateHandler, char *, long);
+local long inflate_fixed(InflateHandler, char *, long);
+local long inflate_dynamic(InflateHandler, char *, long);
+local void inflate_start(InflateHandler);
+
+/* The inflate algorithm uses a sliding 32K byte window on the uncompressed
+ stream to find repeated byte strings. This is implemented here as a
+ circular buffer. The index is updated simply by incrementing and then
+ and'ing with 0x7fff (32K-1). */
+/* It is left to other modules to supply the 32K area. It is assumed
+ to be usable as if it were declared "uch slide[32768];" or as just
+ "uch *slide;" and then malloc'ed in the latter case. The definition
+ must be in unzip.h, included above. */
+
+#define lbits 9 /* bits in base literal/length lookup table */
+#define dbits 6 /* bits in base distance lookup table */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local ush cplens[] = { /* Copy lengths for literal codes 257..285 */
+ 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. */
+local ush cplext[] = { /* Extra bits for literal codes 257..285 */
+ 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 */
+local ush cpdist[] = { /* Copy offsets for distance codes 0..29 */
+ 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};
+local ush cpdext[] = { /* Extra bits for distance codes */
+ 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};
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ are not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+/* 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 */
+
+int huft_build(
+ unsigned *b, /* code lengths in bits (all assumed <= BMAX) */
+ unsigned n, /* number of codes (assumed <= N_MAX) */
+ unsigned s, /* number of simple-valued codes (0..s-1) */
+ ush *d, /* list of base values for non-simple codes */
+ ush *e, /* list of extra bits for non-simple codes */
+ struct huft **t, /* result: starting table */
+ int *m, /* maximum lookup bits, returns actual */
+ MBlockList *pool) /* memory pool */
+/* 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.
+ The code with value 256 is special, and the tables are constructed
+ so that no bits beyond that code are fetched when that code is
+ decoded. */
+{
+ unsigned a; /* counter for codes of length k */
+ unsigned c[BMAX+1]; /* bit length count table */
+ unsigned el; /* length of EOB code (value 256) */
+ 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 lx[BMAX+1]; /* memory for l[-1..BMAX-1] */
+ int *l = lx+1; /* stack of bits per table */
+ register unsigned *p; /* pointer into c[], b[], or v[] */
+ register struct huft *q; /* points to current table */
+ struct huft r; /* table entry for structure assignment */
+ struct huft *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 */
+ el = n > 256 ? b[256] : BMAX; /* set length of EOB code, if any */
+ memset(c, 0, sizeof(c));
+ p = b;
+ i = n;
+ do
+ {
+ Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" :
+ "0x%x %d\n"), n-i, *p));
+ 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 = (struct huft *)NULL;
+ *m = 0;
+ return 0;
+ }
+
+ /* Find minimum and maximum length, bound *m by those */
+ for(j = 1; j <= BMAX; j++)
+ if(c[j])
+ break;
+ k = j; /* minimum code length */
+ if((unsigned)*m < j)
+ *m = j;
+ for(i = BMAX; i; i--)
+ if(c[i])
+ break;
+ g = i; /* maximum code length */
+ if((unsigned)*m > i)
+ *m = i;
+
+ /* 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 */
+ memset(v, 0, sizeof(v));
+ p = b;
+ i = 0;
+ do
+ {
+ if((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while(++i < n);
+ n = x[g]; /* set n to length of v */
+
+ /* 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[-1] = 0; /* no bits decoded yet */
+ u[0] = (struct huft *)NULL; /* just to keep compilers happy */
+ q = (struct huft *)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[h++]; /* add bits already decoded */
+
+ /* compute minimum size table less than or equal to *m bits */
+ z = (z = g - w) > (unsigned)*m ? *m : z; /* upper limit */
+ 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 */
+ }
+ }
+ if((unsigned)w + j > el && (unsigned)w < el)
+ j = el - w; /* make EOB code end at table */
+ z = 1 << j; /* table entries for j-bit table */
+ l[h] = j; /* set table size in stack */
+
+ /* allocate and link in new table */
+ if(pool == NULL)
+ q = (struct huft *)malloc((z + 1)*sizeof(struct huft));
+ else
+ q = (struct huft *)
+ new_segment(pool, (z + 1)*sizeof(struct huft));
+ if(q == NULL)
+ {
+ if(h && pool == NULL)
+ huft_free(u[0]);
+ return 3; /* not enough memory */
+ }
+
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->v.t)) = (struct huft *)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 = (uch)l[h-1]; /* bits to dump before this table */
+ r.e = (uch)(16 + j);/* bits in this table */
+ r.v.t = q; /* pointer to this table */
+ j = (i & ((1 << w) - 1)) >> (w - l[h-1]);
+ u[h-1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.b = (uch)(k - w);
+ if(p >= v + n)
+ r.e = 99; /* out of values--invalid code */
+ else if(*p < s)
+ {
+ r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
+ r.v.n = (ush)*p++; /* simple code is just the value */
+ }
+ else
+ {
+ r.e = (uch)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])
+ w -= l[--h]; /* don't need to update q */
+ }
+ }
+
+ /* return actual size of base table */
+ *m = l[0];
+
+ /* Return true (1) if we were given an incomplete table */
+ return y != 0 && g != 1;
+}
+
+local int huft_free(struct huft *t)
+/* 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. */
+{
+ register struct huft *p, *q;
+
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ p = t;
+ while(p != (struct huft *)NULL)
+ {
+ q = (--p)->v.t;
+ free((char*)p);
+ p = q;
+ }
+ return 0;
+}
+
+local long inflate_codes(InflateHandler decoder, char *buff, long size)
+/* inflate (decompress) the codes in a deflated (compressed) block.
+ Return an error code or zero if it all goes ok. */
+{
+ register unsigned e;/* table entry flag/number of extra bits */
+ struct huft *t; /* pointer to table entry */
+ int n;
+ struct huft *tl, *td;/* literal/length and distance decoder tables */
+ int bl, bd; /* number of bits decoded by tl[] and td[] */
+ unsigned l, w, d;
+ uch *slide;
+
+ BITS_SAVE;
+
+ if(size == 0)
+ return 0;
+
+ slide = decoder->slide;
+ tl = decoder->tl;
+ td = decoder->td;
+ bl = decoder->bl;
+ bd = decoder->bd;
+
+#ifdef DEBUG
+ if(decoder->copy_leng != 0)
+ {
+ fprintf(stderr, "What ? (decoder->copy_leng = %d)\n",
+ decoder->copy_leng);
+ abort();
+ }
+#endif /* DEBUG */
+ w = decoder->wp;
+
+ /* inflate the coded data */
+ n = 0;
+ for(;;) /* do until end of block */
+ {
+ NEEDBITS((unsigned)bl);
+ t = tl + GETBITS(bl);
+ e = t->e;
+ while(e > 16)
+ {
+ if(e == 99)
+ return -1;
+ DUMPBITS(t->b);
+ e -= 16;
+ NEEDBITS(e);
+ t = t->v.t + GETBITS(e);
+ e = t->e;
+ }
+ DUMPBITS(t->b);
+
+ if(e == 16) /* then it's a literal */
+ {
+ w &= WSIZE - 1;
+ buff[n++] = slide[w++] = (uch)t->v.n;
+ if(n == size)
+ {
+ decoder->wp = w;
+ BITS_RESTORE;
+ return size;
+ }
+ continue;
+ }
+
+ /* exit if end of block */
+ if(e == 15)
+ break;
+
+ /* it's an EOB or a length */
+
+ /* get length of block to copy */
+ NEEDBITS(e);
+ l = t->v.n + GETBITS(e);
+ DUMPBITS(e);
+
+ /* decode distance of block to copy */
+ NEEDBITS((unsigned)bd);
+ t = td + GETBITS(bd);
+ e = t->e;
+ while(e > 16)
+ {
+ if(e == 99)
+ return -1;
+ DUMPBITS(t->b);
+ e -= 16;
+ NEEDBITS(e);
+ t = t->v.t + GETBITS(e);
+ e = t->e;
+ }
+ DUMPBITS(t->b);
+ NEEDBITS(e);
+ d = w - t->v.n - GETBITS(e);
+ DUMPBITS(e);
+
+ /* do the copy */
+ while(l > 0 && n < size)
+ {
+ l--;
+ d &= WSIZE - 1;
+ w &= WSIZE - 1;
+ buff[n++] = slide[w++] = slide[d++];
+ }
+
+ if(n == size)
+ {
+ decoder->copy_leng = l;
+ decoder->wp = w;
+ decoder->copy_dist = d;
+ BITS_RESTORE;
+ return n;
+ }
+ }
+
+ decoder->wp = w;
+ decoder->method = -1; /* done */
+ BITS_RESTORE;
+ return n;
+}
+
+local long inflate_stored(InflateHandler decoder, char *buff, long size)
+/* "decompress" an inflated type 0 (stored) block. */
+{
+ unsigned n, l, w;
+ BITS_SAVE;
+
+ /* go to byte boundary */
+ n = bit_len & 7;
+ DUMPBITS(n);
+
+ /* get the length and its complement */
+ NEEDBITS(16);
+ n = GETBITS(16);
+ DUMPBITS(16);
+ NEEDBITS(16);
+ if(n != (unsigned)((~bit_buf) & 0xffff))
+ {
+ BITS_RESTORE;
+ return -1; /* error in compressed data */
+ }
+ DUMPBITS(16);
+
+ /* read and output the compressed data */
+ decoder->copy_leng = n;
+
+ n = 0;
+ l = decoder->copy_leng;
+ w = decoder->wp;
+ while(l > 0 && n < size)
+ {
+ l--;
+ w &= WSIZE - 1;
+ NEEDBITS(8);
+ buff[n++] = decoder->slide[w++] = (uch)GETBITS(8);
+ DUMPBITS(8);
+ }
+ if(l == 0)
+ decoder->method = -1; /* done */
+ decoder->copy_leng = l;
+ decoder->wp = w;
+ BITS_RESTORE;
+ return (long)n;
+}
+
+local long inflate_fixed(InflateHandler decoder, char *buff, long size)
+/* 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. */
+{
+ /* if first time, set up tables for fixed blocks */
+ if(decoder->fixed_tl == NULL)
+ {
+ int i; /* temporary variable */
+ unsigned l[288]; /* length list for huft_build */
+
+ /* 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;
+ decoder->fixed_bl = 7;
+ if((i = huft_build(l, 288, 257, cplens, cplext,
+ &decoder->fixed_tl, &decoder->fixed_bl, NULL))
+ != 0)
+ {
+ decoder->fixed_tl = NULL;
+ return -1;
+ }
+
+ /* distance table */
+ for(i = 0; i < 30; i++) /* make an incomplete code set */
+ l[i] = 5;
+ decoder->fixed_bd = 5;
+ if((i = huft_build(l, 30, 0, cpdist, cpdext,
+ &decoder->fixed_td, &decoder->fixed_bd, NULL)) > 1)
+ {
+ huft_free(decoder->fixed_tl);
+ decoder->fixed_tl = NULL;
+ return -1;
+ }
+ }
+
+ decoder->tl = decoder->fixed_tl;
+ decoder->td = decoder->fixed_td;
+ decoder->bl = decoder->fixed_bl;
+ decoder->bd = decoder->fixed_bd;
+ return inflate_codes(decoder, buff, size);
+}
+
+local long inflate_dynamic(InflateHandler decoder, char *buff, long size)
+/* decompress an inflated type 2 (dynamic Huffman codes) block. */
+{
+ int i; /* temporary variables */
+ unsigned j;
+ unsigned l; /* last length */
+ unsigned n; /* number of lengths to get */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int 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 */
+#ifdef PKZIP_BUG_WORKAROUND
+ unsigned ll[288+32];/* literal/length and distance code lengths */
+#else
+ unsigned ll[286+30];/* literal/length and distance code lengths */
+#endif
+ static unsigned border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+ BITS_SAVE;
+
+ reuse_mblock(&decoder->pool);
+
+ /* read in table lengths */
+ NEEDBITS(5);
+ nl = 257 + GETBITS(5); /* number of literal/length codes */
+ DUMPBITS(5);
+ NEEDBITS(5);
+ nd = 1 + GETBITS(5); /* number of distance codes */
+ DUMPBITS(5);
+ NEEDBITS(4);
+ nb = 4 + GETBITS(4); /* number of bit length codes */
+ DUMPBITS(4);
+#ifdef PKZIP_BUG_WORKAROUND
+ if(nl > 288 || nd > 32)
+#else
+ if(nl > 286 || nd > 30)
+#endif
+ {
+ BITS_RESTORE;
+ return -1; /* bad lengths */
+ }
+
+ /* read in bit-length-code lengths */
+ for(j = 0; j < nb; j++)
+ {
+ NEEDBITS(3);
+ ll[border[j]] = GETBITS(3);
+ DUMPBITS(3);
+ }
+ for(; j < 19; j++)
+ ll[border[j]] = 0;
+
+ /* build decoding table for trees--single level, 7 bit lookup */
+ bl = 7;
+ if((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl, &decoder->pool)) != 0)
+ {
+ reuse_mblock(&decoder->pool);
+ BITS_RESTORE;
+ return -1; /* incomplete code set */
+ }
+
+ /* read in literal and distance code lengths */
+ n = nl + nd;
+ i = l = 0;
+ while((unsigned)i < n)
+ {
+ NEEDBITS((unsigned)bl);
+ j = (td = tl + (GETBITS(bl)))->b;
+ DUMPBITS(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 */
+ {
+ NEEDBITS(2);
+ j = 3 + GETBITS(2);
+ DUMPBITS(2);
+ if((unsigned)i + j > n)
+ {
+ BITS_RESTORE;
+ return -1;
+ }
+ while(j--)
+ ll[i++] = l;
+ }
+ else if(j == 17) /* 3 to 10 zero length codes */
+ {
+ NEEDBITS(3);
+ j = 3 + GETBITS(3);
+ DUMPBITS(3);
+ if((unsigned)i + j > n)
+ {
+ BITS_RESTORE;
+ return -1;
+ }
+ while(j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ else /* j == 18: 11 to 138 zero length codes */
+ {
+ NEEDBITS(7);
+ j = 11 + GETBITS(7);
+ DUMPBITS(7);
+ if((unsigned)i + j > n)
+ {
+ BITS_RESTORE;
+ return -1;
+ }
+ while(j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ }
+
+ BITS_RESTORE;
+
+ /* free decoding table for trees */
+ reuse_mblock(&decoder->pool);
+
+ /* build the decoding tables for literal/length and distance codes */
+ bl = lbits;
+ i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl, &decoder->pool);
+ if(bl == 0) /* no literals or lengths */
+ i = 1;
+ if(i)
+ {
+ if(i == 1)
+ fprintf(stderr, " incomplete literal tree\n");
+ reuse_mblock(&decoder->pool);
+ return -1; /* incomplete code set */
+ }
+ bd = dbits;
+ i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd, &decoder->pool);
+ if(bd == 0 && nl > 257) /* lengths but no distances */
+ {
+ fprintf(stderr, " incomplete distance tree\n");
+ reuse_mblock(&decoder->pool);
+ return -1;
+ }
+
+ if(i == 1) {
+#ifdef PKZIP_BUG_WORKAROUND
+ i = 0;
+#else
+ fprintf(stderr, " incomplete distance tree\n");
+#endif
+ }
+ if(i)
+ {
+ reuse_mblock(&decoder->pool);
+ return -1;
+ }
+
+ /* decompress until an end-of-block code */
+ decoder->tl = tl;
+ decoder->td = td;
+ decoder->bl = bl;
+ decoder->bd = bd;
+
+ i = inflate_codes(decoder, buff, size);
+
+ if(i == -1) /* error */
+ {
+ reuse_mblock(&decoder->pool);
+ return -1;
+ }
+
+ /* free the decoding tables, return */
+ return i;
+}
+
+local void inflate_start(InflateHandler decoder)
+/* initialize window, bit buffer */
+{
+ decoder->wp = 0;
+ decoder->bit_buf = 0;
+ decoder->bit_len = 0;
+ decoder->insize = decoder->inptr = 0;
+ decoder->fixed_td = decoder->fixed_tl = NULL;
+ decoder->method = -1;
+ decoder->eof = 0;
+ decoder->copy_leng = decoder->copy_dist = 0;
+ decoder->tl = NULL;
+
+ init_mblock(&decoder->pool);
+}
+
+/*ARGSUSED*/
+static long default_read_func(char *buf, long size, void *v)
+{
+ return (long)fread(buf, 1, size, stdin);
+}
+
+InflateHandler open_inflate_handler(
+ long (* read_func)(char *buf, long size, void *user_val),
+ void *user_val)
+{
+ InflateHandler decoder;
+
+ decoder = (InflateHandler)
+ malloc(sizeof(struct _InflateHandler));
+ inflate_start(decoder);
+ decoder->user_val = user_val;
+ if(read_func == NULL)
+ decoder->read_func = default_read_func;
+ else
+ decoder->read_func = read_func;
+ return decoder;
+}
+
+void close_inflate_handler(InflateHandler decoder)
+{
+ if(decoder->fixed_tl != NULL)
+ {
+ huft_free(decoder->fixed_td);
+ huft_free(decoder->fixed_tl);
+ decoder->fixed_td = decoder->fixed_tl = NULL;
+ }
+ reuse_mblock(&decoder->pool);
+ free(decoder);
+}
+
+/* decompress an inflated entry */
+long zip_inflate(
+ InflateHandler decoder,
+ char *buff,
+ long size)
+{
+ long n, i;
+
+ n = 0;
+ while(n < size)
+ {
+ if(decoder->eof && decoder->method == -1)
+ return n;
+
+ if(decoder->copy_leng > 0)
+ {
+ unsigned l, w, d;
+
+ l = decoder->copy_leng;
+ w = decoder->wp;
+ if(decoder->method != STORED_BLOCK)
+ {
+ /* STATIC_TREES or DYN_TREES */
+ d = decoder->copy_dist;
+ while(l > 0 && n < size)
+ {
+ l--;
+ d &= WSIZE - 1;
+ w &= WSIZE - 1;
+ buff[n++] = decoder->slide[w++] = decoder->slide[d++];
+ }
+ decoder->copy_dist = d;
+ }
+ else /* STATIC_TREES or DYN_TREES */
+ {
+ BITS_SAVE;
+ while(l > 0 && n < size)
+ {
+ l--;
+ w &= WSIZE - 1;
+ NEEDBITS(8);
+ buff[n++] = decoder->slide[w++] = (uch)GETBITS(8);
+ DUMPBITS(8);
+ }
+ BITS_RESTORE;
+ if(l == 0)
+ decoder->method = -1; /* done */
+ }
+ decoder->copy_leng = l;
+ decoder->wp = w;
+ if(n == size)
+ return n;
+ }
+
+ if(decoder->method == -1)
+ {
+ BITS_SAVE;
+ if(decoder->eof)
+ {
+ BITS_RESTORE;
+ break;
+ }
+ /* read in last block bit */
+ NEEDBITS(1);
+ if(GETBITS(1))
+ decoder->eof = 1;
+ DUMPBITS(1);
+
+ /* read in block type */
+ NEEDBITS(2);
+ decoder->method = (int)GETBITS(2);
+ DUMPBITS(2);
+ decoder->tl = NULL;
+ decoder->copy_leng = 0;
+ BITS_RESTORE;
+ }
+
+ switch(decoder->method)
+ {
+ case STORED_BLOCK:
+ i = inflate_stored(decoder, buff + n, size - n);
+ break;
+
+ case STATIC_TREES:
+ if(decoder->tl != NULL)
+ i = inflate_codes(decoder, buff + n, size - n);
+ else
+ i = inflate_fixed(decoder, buff + n, size - n);
+ break;
+
+ case DYN_TREES:
+ if(decoder->tl != NULL)
+ i = inflate_codes(decoder, buff + n, size - n);
+ else
+ i = inflate_dynamic(decoder, buff + n, size - n);
+ break;
+
+ default: /* error */
+ i = -1;
+ break;
+ }
+
+ if(i == -1)
+ {
+ if(decoder->eof)
+ return 0;
+ return -1; /* error */
+ }
+ n += i;
+ }
+ return n;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty.
+ */
+local int fill_inbuf(InflateHandler decoder)
+{
+ int len;
+
+ /* Read as much as possible */
+ decoder->insize = 0;
+ errno = 0;
+ do {
+ len = decoder->read_func((char*)decoder->inbuf + decoder->insize,
+ (long)(INBUFSIZ - decoder->insize),
+ decoder->user_val);
+ if(len == 0 || len == EOF) break;
+ decoder->insize += len;
+ } while(decoder->insize < INBUFSIZ);
+
+ if(decoder->insize == 0)
+ return EOF;
+ decoder->inptr = 1;
+ return decoder->inbuf[0];
+}
diff --git a/lib/timidity/libarc/unlzh.c b/lib/timidity/libarc/unlzh.c
new file mode 100644
index 0000000000..4534e771d2
--- /dev/null
+++ b/lib/timidity/libarc/unlzh.c
@@ -0,0 +1,1209 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "timidity.h"
+#include "unlzh.h"
+
+#ifndef UCHAR_MAX
+#define UCHAR_MAX 255 /* max value for an unsigned char */
+#endif
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+#define MAX_DICBIT 15
+#define MAXMATCH 256 /* formerly F (not more than UCHAR_MAX + 1) */
+#define THRESHOLD 3 /* choose optimal value */
+
+#define NC (UCHAR_MAX + MAXMATCH + 2 - THRESHOLD)
+ /* alphabet = {0, 1, 2, ..., NC - 1} */
+#define CBIT 9 /* $\lfloor \log_2 NC \rfloor + 1$ */
+#define USHRT_BIT 16 /* (CHAR_BIT * sizeof(ushort)) */
+#define NP (MAX_DICBIT + 1)
+#define NT (USHRT_BIT + 3)
+#define PBIT 4 /* smallest integer such that (1 << PBIT) > NP */
+#define TBIT 5 /* smallest integer such that (1 << TBIT) > NT */
+#define NPT 0x80
+#define N1 286 /* alphabet size */
+#define N2 (2 * N1 - 1) /* # of nodes in Huffman tree */
+#define EXTRABITS 8
+ /* >= log2(F-THRESHOLD+258-N1) */
+#define BUFBITS 16 /* >= log2(MAXBUF) */
+#define LENFIELD 4 /* bit size of length field for tree output */
+#define SNP (8 * 1024 / 64)
+#define SNP2 (SNP * 2 - 1)
+#define N_CHAR (256 + 60 - THRESHOLD + 1)
+#define TREESIZE_C (N_CHAR * 2)
+#define TREESIZE_P (128 * 2)
+#define TREESIZE (TREESIZE_C + TREESIZE_P)
+#define ROOT_C 0
+#define ROOT_P TREESIZE_C
+#define MAGIC0 18
+#define MAGIC5 19
+#define INBUFSIZ BUFSIZ
+
+struct _UNLZHHandler
+{
+ void *user_val;
+ long (* read_func)(char *buff, long buff_size, void *user_val);
+ int method;
+
+ unsigned char inbuf[INBUFSIZ];
+ int inbuf_size;
+ int inbuf_cnt;
+ int initflag;
+
+ int cpylen;
+ int cpypos;
+ unsigned long origsize;
+ unsigned long compsize;
+ void (* decode_s)(UNLZHHandler decoder);
+ unsigned short (* decode_c)(UNLZHHandler decoder);
+ unsigned short (* decode_p)(UNLZHHandler decoder);
+ int dicbit;
+ unsigned short maxmatch;
+ unsigned long count;
+ unsigned short loc;
+ unsigned char text[1L<<MAX_DICBIT];
+ unsigned short bitbuf;
+ unsigned char subbitbuf, bitcount;
+ unsigned short left[2 * NC - 1], right[2 * NC - 1];
+ unsigned char c_len[NC], pt_len[NPT];
+ unsigned short c_table[4096], pt_table[256];
+ unsigned short blocksize;
+ unsigned int n_max;
+ short child [TREESIZE],
+ parent[TREESIZE],
+ block [TREESIZE],
+ edge [TREESIZE],
+ stock [TREESIZE],
+ node [TREESIZE / 2];
+ unsigned short freq[TREESIZE];
+ unsigned short total_p;
+ int avail, n1;
+ int most_p, nn;
+ unsigned long nextcount;
+ unsigned int snp;
+ int flag, flagcnt, matchpos;
+ int offset;
+ unsigned int pbit;
+};
+
+static unsigned short decode_c_cpy(UNLZHHandler decoder);
+static unsigned short decode_p_cpy(UNLZHHandler decoder);
+static void decode_start_cpy(UNLZHHandler decoder);
+static void read_pt_len(UNLZHHandler decoder,
+ short k, short nbit, short i_special);
+static void read_c_len(UNLZHHandler decoder);
+static unsigned short decode_c_st1(UNLZHHandler decoder);
+static unsigned short decode_p_st1(UNLZHHandler decoder);
+static void decode_start_st1(UNLZHHandler decoder);
+static void start_c_dyn(UNLZHHandler decoder);
+static void start_p_dyn(UNLZHHandler decoder);
+static void decode_start_dyn(UNLZHHandler decoder);
+static void reconst(UNLZHHandler decoder, int start, int end);
+static int swap_inc(UNLZHHandler decoder, int p);
+static void update_c(UNLZHHandler decoder, int p);
+static void update_p(UNLZHHandler decoder, int p);
+static void make_new_node(UNLZHHandler decoder, int p);
+static unsigned short decode_c_dyn(UNLZHHandler decoder);
+static unsigned short decode_p_dyn(UNLZHHandler decoder);
+static void decode_start_st0(UNLZHHandler decoder);
+static void ready_made(UNLZHHandler decoder, int method);
+static void read_tree_c(UNLZHHandler decoder);
+static void read_tree_p(UNLZHHandler decoder);
+static void decode_start_fix(UNLZHHandler decoder);
+static unsigned short decode_c_st0(UNLZHHandler decoder);
+static unsigned short decode_p_st0(UNLZHHandler decoder);
+static unsigned short decode_c_lzs(UNLZHHandler decoder);
+static unsigned short decode_p_lzs(UNLZHHandler decoder);
+static void decode_start_lzs(UNLZHHandler decoder);
+static unsigned short decode_c_lz5(UNLZHHandler decoder);
+static unsigned short decode_p_lz5(UNLZHHandler decoder);
+static void decode_start_lz5(UNLZHHandler decoder);
+static int make_table(UNLZHHandler decoder,
+ int nchar, unsigned char bitlen[],
+ int tablebits, unsigned short table[]);
+static int fill_inbuf(UNLZHHandler decoder);
+static void fillbuf(UNLZHHandler decoder, unsigned char n);
+static unsigned short getbits(UNLZHHandler decoder, unsigned char n);
+static void init_getbits(UNLZHHandler decoder);
+
+#define NEXTBYTE (decoder->inbuf_cnt < decoder->inbuf_size ? (int)decoder->inbuf[decoder->inbuf_cnt++] : fill_inbuf(decoder))
+
+static struct
+{
+ char *id;
+ int dicbit;
+ void (*decode_s)(UNLZHHandler decoder);
+ unsigned short (*decode_c)(UNLZHHandler decoder);
+ unsigned short (*decode_p)(UNLZHHandler decoder);
+} method_table[] =
+{
+/* No compression */
+ {"-lh0-", 0, decode_start_cpy, decode_c_cpy, decode_p_cpy},
+
+/* 4k sliding dictionary(max 60 bytes)
+ + dynamic Huffman + fixed encoding of position */
+ {"-lh1-", 12, decode_start_fix, decode_c_dyn, decode_p_st0},
+
+/* 8k sliding dictionary(max 256 bytes) + dynamic Huffman */
+ {"-lh2-", 13, decode_start_dyn, decode_c_dyn, decode_p_dyn},
+
+/* 8k sliding dictionary(max 256 bytes) + static Huffman */
+ {"-lh3-", 13, decode_start_st0, decode_c_st0, decode_p_st0},
+
+/* 4k sliding dictionary(max 256 bytes)
+ + static Huffman + improved encoding of position and trees */
+ {"-lh4-", 12, decode_start_st1, decode_c_st1, decode_p_st1},
+
+/* 8k sliding dictionary(max 256 bytes)
+ + static Huffman + improved encoding of position and trees */
+ {"-lh5-", 13, decode_start_st1, decode_c_st1, decode_p_st1},
+
+/* 2k sliding dictionary(max 17 bytes) */
+ {"-lzs-", 11, decode_start_lzs, decode_c_lzs, decode_p_lzs},
+
+/* No compression */
+ {"-lz5-", 12, decode_start_lz5, decode_c_lz5, decode_p_lz5},
+
+/* 4k sliding dictionary(max 17 bytes) */
+ {"-lz4-", 0, decode_start_cpy, decode_c_cpy, decode_p_cpy},
+
+/* Directory */
+ {"-lhd-", 0, NULL, NULL, NULL},
+
+/* 32k sliding dictionary + static Huffman */
+ {"-lh6-", 15, decode_start_st1, decode_c_st1, decode_p_st1},
+
+#if 0 /* not supported */
+/* 64k sliding dictionary + static Huffman */
+ {"-lh7-", 16, decode_start_st1, decode_c_st1, decode_p_st1},
+#endif
+ {NULL, 0, NULL, NULL}
+};
+
+char *lzh_methods[] =
+{
+ "-lh0-", "-lh1-", "-lh2-", "-lh3-", "-lh4-", "-lh5-",
+ "-lzs-", "-lz5-", "-lz4-", "-lhd-", "-lh6-", "-lh7-", NULL
+};
+
+/*ARGSUSED*/
+static long default_read_func(char *buf, long size, void *v)
+{
+ return (long)fread(buf, 1, size, stdin);
+}
+
+UNLZHHandler open_unlzh_handler(long (* read_func)(char *, long, void *),
+ const char *method,
+ long compsize, long origsize, void *user_val)
+{
+ UNLZHHandler decoder;
+ int i;
+
+ for(i = 0; method_table[i].id != NULL; i++)
+ if(!strcmp(method_table[i].id, method))
+ break;
+ if(method_table[i].id == NULL)
+ return NULL; /* Invalid method */
+
+ if((decoder = (UNLZHHandler)malloc(sizeof(struct _UNLZHHandler))) == NULL)
+ return NULL;
+ memset(decoder, 0, sizeof(struct _UNLZHHandler));
+
+ if(strcmp(method, "-lhd-") == 0)
+ origsize = 0;
+
+ decoder->method = i;
+ decoder->dicbit = method_table[i].dicbit;
+ decoder->decode_s = method_table[i].decode_s;
+ decoder->decode_c = method_table[i].decode_c;
+ decoder->decode_p = method_table[i].decode_p;
+ decoder->compsize = compsize;
+ decoder->origsize = origsize;
+ decoder->user_val = user_val;
+ decoder->cpylen = 0;
+ decoder->cpypos = 0;
+ decoder->offset = (decoder->method == 6) ? 0x100 - 2 : 0x100 - 3;
+ decoder->count = 0;
+ decoder->loc = 0;
+ decoder->initflag = 0;
+
+ if(read_func == NULL)
+ decoder->read_func = default_read_func;
+ else
+ decoder->read_func = read_func;
+
+ return decoder;
+}
+
+void close_unlzh_handler(UNLZHHandler decoder)
+{
+ free(decoder);
+}
+
+long unlzh(UNLZHHandler decoder, char *buff, long buff_size)
+{
+ long n;
+ unsigned short dicsiz1;
+ int offset;
+ int cpylen, cpypos, loc;
+ unsigned char *text;
+ unsigned long origsize;
+
+ if((origsize = decoder->origsize) == 0 || buff_size <= 0)
+ return 0;
+
+ if(!decoder->initflag)
+ {
+ decoder->initflag = 1;
+ decoder->decode_s(decoder);
+ }
+
+ dicsiz1 = (1 << decoder->dicbit) - 1;
+ n = 0;
+ text = decoder->text;
+
+ if(decoder->cpylen > 0)
+ {
+ cpylen = decoder->cpylen;
+ cpypos = decoder->cpypos;
+ loc = decoder->loc;
+ while(cpylen > 0 && n < buff_size)
+ {
+ buff[n++] = text[loc++] = text[cpypos++];
+ loc &= dicsiz1;
+ cpypos &= dicsiz1;
+ cpylen--;
+ }
+ decoder->cpylen = cpylen;
+ decoder->cpypos = cpypos;
+ decoder->loc = loc;
+ }
+
+ if(n == buff_size)
+ return buff_size;
+
+ offset = decoder->offset;
+ while(decoder->count < origsize && n < buff_size)
+ {
+ int c;
+
+ c = decoder->decode_c(decoder);
+ if(c <= UCHAR_MAX)
+ {
+ buff[n++] = decoder->text[decoder->loc++] = c;
+ decoder->loc &= dicsiz1;
+ decoder->count++;
+ }
+ else
+ {
+ int i, j, k, m;
+
+ j = c - offset;
+ i = (decoder->loc - decoder->decode_p(decoder) - 1) & dicsiz1;
+ decoder->count += j;
+ loc = decoder->loc;
+ m = buff_size - n;
+ if(m > j)
+ m = j;
+ for(k = 0; k < m; k++)
+ {
+ buff[n++] = text[loc++] = text[i++];
+ loc &= dicsiz1;
+ i &= dicsiz1;
+ }
+ decoder->loc = loc;
+ if(k < j)
+ {
+ decoder->cpylen = j - k;
+ decoder->cpypos = i;
+ break;
+ }
+ }
+ }
+
+ return n;
+}
+
+static unsigned short decode_c_cpy(UNLZHHandler decoder)
+{
+ int c;
+
+ if((c = NEXTBYTE) == EOF)
+ return 0;
+ return (unsigned short)c;
+}
+
+/*ARGSUSED*/
+static unsigned short decode_p_cpy(UNLZHHandler decoder)
+{
+ return 0;
+}
+
+static void decode_start_cpy(UNLZHHandler decoder)
+{
+ init_getbits(decoder);
+}
+
+static void read_pt_len(UNLZHHandler decoder,
+ short k, short nbit, short i_special)
+{
+ short i, c, n;
+
+ n = getbits(decoder, nbit);
+ if(n == 0)
+ {
+ c = getbits(decoder, nbit);
+ for(i = 0; i < k; i++)
+ decoder->pt_len[i] = 0;
+ for(i = 0; i < 256; i++)
+ decoder->pt_table[i] = c;
+ }
+ else
+ {
+ i = 0;
+ while(i < n)
+ {
+ c = decoder->bitbuf >> (16 - 3);
+ if (c == 7)
+ {
+ unsigned short mask = 1 << (16 - 4);
+ while(mask & decoder->bitbuf)
+ {
+ mask >>= 1;
+ c++;
+ }
+ }
+ fillbuf(decoder, (c < 7) ? 3 : c - 3);
+ decoder->pt_len[i++] = c;
+ if(i == i_special)
+ {
+ c = getbits(decoder, 2);
+ while(--c >= 0)
+ decoder->pt_len[i++] = 0;
+ }
+ }
+ while(i < k)
+ decoder->pt_len[i++] = 0;
+ make_table(decoder, k, decoder->pt_len, 8, decoder->pt_table);
+ }
+}
+
+static void read_c_len(UNLZHHandler decoder)
+{
+ short i, c, n;
+
+ n = getbits(decoder, CBIT);
+ if(n == 0)
+ {
+ c = getbits(decoder, CBIT);
+ for(i = 0; i < NC; i++)
+ decoder->c_len[i] = 0;
+ for(i = 0; i < 4096; i++)
+ decoder->c_table[i] = c;
+ }
+ else
+ {
+ i = 0;
+ while(i < n)
+ {
+ c = decoder->pt_table[decoder->bitbuf >> (16 - 8)];
+ if(c >= NT)
+ {
+ unsigned short mask = 1 << (16 - 9);
+ do
+ {
+ if(decoder->bitbuf & mask)
+ c = decoder->right[c];
+ else
+ c = decoder->left[c];
+ mask >>= 1;
+ } while(c >= NT);
+ }
+ fillbuf(decoder, decoder->pt_len[c]);
+ if(c <= 2)
+ {
+ if(c == 0)
+ c = 1;
+ else if(c == 1)
+ c = getbits(decoder, 4) + 3;
+ else
+ c = getbits(decoder, CBIT) + 20;
+ while(--c >= 0)
+ decoder->c_len[i++] = 0;
+ }
+ else
+ decoder->c_len[i++] = c - 2;
+ }
+ while(i < NC)
+ decoder->c_len[i++] = 0;
+ make_table(decoder, NC, decoder->c_len, 12, decoder->c_table);
+ }
+}
+
+static unsigned short decode_c_st1(UNLZHHandler decoder)
+{
+ unsigned short j, mask;
+
+ if(decoder->blocksize == 0)
+ {
+ decoder->blocksize = getbits(decoder, 16);
+ read_pt_len(decoder, NT, TBIT, 3);
+ read_c_len(decoder);
+ read_pt_len(decoder, decoder->snp, decoder->pbit, -1);
+ }
+ decoder->blocksize--;
+ j = decoder->c_table[decoder->bitbuf >> 4];
+ if(j < NC)
+ fillbuf(decoder, decoder->c_len[j]);
+ else
+ {
+ fillbuf(decoder, 12);
+ mask = 1 << (16 - 1);
+ do
+ {
+ if(decoder->bitbuf & mask)
+ j = decoder->right[j];
+ else
+ j = decoder->left[j];
+ mask >>= 1;
+ } while(j >= NC);
+ fillbuf(decoder, decoder->c_len[j] - 12);
+ }
+ return j;
+}
+
+static unsigned short decode_p_st1(UNLZHHandler decoder)
+{
+ unsigned short j, mask;
+ unsigned int np = decoder->snp;
+
+ j = decoder->pt_table[decoder->bitbuf >> (16 - 8)];
+ if(j < np)
+ fillbuf(decoder, decoder->pt_len[j]);
+ else
+ {
+ fillbuf(decoder, 8);
+ mask = 1 << (16 - 1);
+ do
+ {
+ if(decoder->bitbuf & mask)
+ j = decoder->right[j];
+ else
+ j = decoder->left[j];
+ mask >>= 1;
+ } while(j >= np);
+ fillbuf(decoder, decoder->pt_len[j] - 8);
+ }
+ if(j != 0)
+ j = (1 << (j - 1)) + getbits(decoder, j - 1);
+ return j;
+}
+
+
+static void decode_start_st1(UNLZHHandler decoder)
+{
+ if(decoder->dicbit <= (MAX_DICBIT - 2)) {
+ decoder->snp = 14;
+ decoder->pbit = 4;
+ } else {
+ decoder->snp = 16;
+ decoder->pbit = 5;
+ }
+
+ init_getbits(decoder);
+ decoder->blocksize = 0;
+}
+
+static void start_c_dyn(UNLZHHandler decoder)
+{
+ int i, j, f;
+
+ decoder->n1 = (decoder->n_max >= 256 + decoder->maxmatch - THRESHOLD + 1)
+ ? 512 : decoder->n_max - 1;
+ for(i = 0; i < TREESIZE_C; i++)
+ {
+ decoder->stock[i] = i;
+ decoder->block[i] = 0;
+ }
+ for(i = 0, j = decoder->n_max * 2 - 2; i < decoder->n_max; i++, j--)
+ {
+ decoder->freq[j] = 1;
+ decoder->child[j] = ~i;
+ decoder->node[i] = j;
+ decoder->block[j] = 1;
+ }
+ decoder->avail = 2;
+ decoder->edge[1] = decoder->n_max - 1;
+ i = decoder->n_max * 2 - 2;
+ while(j >= 0)
+ {
+ f = decoder->freq[j] = decoder->freq[i] + decoder->freq[i - 1];
+ decoder->child[j] = i;
+ decoder->parent[i] = decoder->parent[i - 1] = j;
+ if(f == decoder->freq[j + 1])
+ {
+ decoder->edge[decoder->block[j] = decoder->block[j + 1]] = j;
+ }
+ else
+ {
+ decoder->edge[decoder->block[j] =
+ decoder->stock[decoder->avail++]] = j;
+ }
+ i -= 2;
+ j--;
+ }
+}
+
+static void start_p_dyn(UNLZHHandler decoder)
+{
+ decoder->freq[ROOT_P] = 1;
+ decoder->child[ROOT_P] = ~(N_CHAR);
+ decoder->node[N_CHAR] = ROOT_P;
+ decoder->edge[decoder->block[ROOT_P] =
+ decoder->stock[decoder->avail++]] = ROOT_P;
+ decoder->most_p = ROOT_P;
+ decoder->total_p = 0;
+ decoder->nn = 1 << decoder->dicbit;
+ decoder->nextcount = 64;
+}
+
+static void decode_start_dyn(UNLZHHandler decoder)
+{
+ decoder->n_max = 286;
+ decoder->maxmatch = MAXMATCH;
+ init_getbits(decoder);
+ start_c_dyn(decoder);
+ start_p_dyn(decoder);
+}
+
+static void reconst(UNLZHHandler decoder, int start, int end)
+{
+ int i, j, k, l, b;
+ unsigned int f, g;
+
+ b = 0;
+ for(i = j = start; i < end; i++)
+ {
+ if((k = decoder->child[i]) < 0)
+ {
+ decoder->freq[j] = (decoder->freq[i] + 1) / 2;
+ decoder->child[j] = k;
+ j++;
+ }
+ if(decoder->edge[b = decoder->block[i]] == i)
+ {
+ decoder->stock[--decoder->avail] = b;
+ }
+ }
+ j--;
+ i = end - 1;
+ l = end - 2;
+ while(i >= start)
+ {
+ while (i >= l)
+ {
+ decoder->freq[i] = decoder->freq[j];
+ decoder->child[i] = decoder->child[j];
+ i--;
+ j--;
+ }
+ f = decoder->freq[l] + decoder->freq[l + 1];
+ for(k = start; f < decoder->freq[k]; k++)
+ ;
+ while(j >= k)
+ {
+ decoder->freq[i] = decoder->freq[j];
+ decoder->child[i] = decoder->child[j];
+ i--;
+ j--;
+ }
+ decoder->freq[i] = f;
+ decoder->child[i] = l + 1;
+ i--;
+ l -= 2;
+ }
+ f = 0;
+ for(i = start; i < end; i++)
+ {
+ if((j = decoder->child[i]) < 0)
+ decoder->node[~j] = i;
+ else
+ decoder->parent[j] = decoder->parent[j - 1] = i;
+ if((g = decoder->freq[i]) == f)
+ {
+ decoder->block[i] = b;
+ }
+ else
+ {
+ decoder->edge[b = decoder->block[i]
+ = decoder->stock[decoder->avail++]] = i;
+ f = g;
+ }
+ }
+}
+
+static int swap_inc(UNLZHHandler decoder, int p)
+{
+ int b, q, r, s;
+
+ b = decoder->block[p];
+ if((q = decoder->edge[b]) != p)
+ { /* swap for leader */
+ r = decoder->child[p];
+ s = decoder->child[q];
+ decoder->child[p] = s;
+ decoder->child[q] = r;
+ if(r >= 0)
+ decoder->parent[r] = decoder->parent[r - 1] = q;
+ else
+ decoder->node[~r] = q;
+ if(s >= 0)
+ decoder->parent[s] = decoder->parent[s - 1] = p;
+ else
+ decoder->node[~s] = p;
+ p = q;
+ goto Adjust;
+ }
+ else if(b == decoder->block[p + 1])
+ {
+ Adjust:
+ decoder->edge[b]++;
+ if(++decoder->freq[p] == decoder->freq[p - 1])
+ {
+ decoder->block[p] = decoder->block[p - 1];
+ }
+ else
+ {
+ decoder->edge[decoder->block[p] =
+ decoder->stock[decoder->avail++]] = p; /* create block */
+ }
+ }
+ else if (++decoder->freq[p] == decoder->freq[p - 1])
+ {
+ decoder->stock[--decoder->avail] = b; /* delete block */
+ decoder->block[p] = decoder->block[p - 1];
+ }
+ return decoder->parent[p];
+}
+
+static void update_c(UNLZHHandler decoder, int p)
+{
+ int q;
+
+ if(decoder->freq[ROOT_C] == 0x8000)
+ {
+ reconst(decoder, 0, decoder->n_max * 2 - 1);
+ }
+ decoder->freq[ROOT_C]++;
+ q = decoder->node[p];
+ do
+ {
+ q = swap_inc(decoder, q);
+ } while(q != ROOT_C);
+}
+
+static void update_p(UNLZHHandler decoder, int p)
+{
+ int q;
+
+ if(decoder->total_p == 0x8000)
+ {
+ reconst(decoder, ROOT_P, decoder->most_p + 1);
+ decoder->total_p = decoder->freq[ROOT_P];
+ decoder->freq[ROOT_P] = 0xffff;
+ }
+ q = decoder->node[p + N_CHAR];
+ while(q != ROOT_P)
+ {
+ q = swap_inc(decoder, q);
+ }
+ decoder->total_p++;
+}
+
+static void make_new_node(UNLZHHandler decoder, int p)
+{
+ int q, r;
+
+ r = decoder->most_p + 1;
+ q = r + 1;
+ decoder->node[~(decoder->child[r] = decoder->child[decoder->most_p])] = r;
+ decoder->child[q] = ~(p + N_CHAR);
+ decoder->child[decoder->most_p] = q;
+ decoder->freq[r] = decoder->freq[decoder->most_p];
+ decoder->freq[q] = 0;
+ decoder->block[r] = decoder->block[decoder->most_p];
+ if(decoder->most_p == ROOT_P)
+ {
+ decoder->freq[ROOT_P] = 0xffff;
+ decoder->edge[decoder->block[ROOT_P]]++;
+ }
+ decoder->parent[r] = decoder->parent[q] = decoder->most_p;
+ decoder->edge[decoder->block[q] = decoder->stock[decoder->avail++]]
+ = decoder->node[p + N_CHAR] = decoder->most_p = q;
+ update_p(decoder, p);
+}
+
+static unsigned short decode_c_dyn(UNLZHHandler decoder)
+{
+ int c;
+ short buf, cnt;
+
+ c = decoder->child[ROOT_C];
+ buf = decoder->bitbuf;
+ cnt = 0;
+ do
+ {
+ c = decoder->child[c - (buf < 0)];
+ buf <<= 1;
+ if(++cnt == 16)
+ {
+ fillbuf(decoder, 16);
+ buf = decoder->bitbuf;
+ cnt = 0;
+ }
+ }while (c > 0);
+ fillbuf(decoder, cnt);
+ c = ~c;
+ update_c(decoder, c);
+ if(c == decoder->n1)
+ c += getbits(decoder, 8);
+ return c;
+}
+
+static unsigned short decode_p_dyn(UNLZHHandler decoder)
+{
+ int c;
+ short buf, cnt;
+
+ while(decoder->count > decoder->nextcount)
+ {
+ make_new_node(decoder, (int)(decoder->nextcount / 64));
+ if((decoder->nextcount += 64) >= decoder->nn)
+ decoder->nextcount = 0xffffffff;
+ }
+ c = decoder->child[ROOT_P];
+ buf = decoder->bitbuf;
+ cnt = 0;
+ while(c > 0)
+ {
+ c = decoder->child[c - (buf < 0)];
+ buf <<= 1;
+ if(++cnt == 16)
+ {
+ fillbuf(decoder, 16);
+ buf = decoder->bitbuf;
+ cnt = 0;
+ }
+ }
+ fillbuf(decoder, cnt);
+ c = (~c) - N_CHAR;
+ update_p(decoder, c);
+
+ return (c << 6) + getbits(decoder, 6);
+}
+
+static void decode_start_st0(UNLZHHandler decoder)
+{
+ decoder->n_max = 286;
+ decoder->maxmatch = MAXMATCH;
+ init_getbits(decoder);
+ decoder->snp = 1 << (MAX_DICBIT - 6);
+ decoder->blocksize = 0;
+}
+
+static int fixed[2][16] = {
+ {3, 0x01, 0x04, 0x0c, 0x18, 0x30, 0}, /* old compatible */
+ {2, 0x01, 0x01, 0x03, 0x06, 0x0D, 0x1F, 0x4E, 0} /* 8K buf */
+};
+
+static void ready_made(UNLZHHandler decoder, int method)
+{
+ int i, j;
+ unsigned int code, weight;
+ int *tbl;
+
+ tbl = fixed[method];
+ j = *tbl++;
+ weight = 1 << (16 - j);
+ code = 0;
+ for(i = 0; i < decoder->snp; i++)
+ {
+ while(*tbl == i)
+ {
+ j++;
+ tbl++;
+ weight >>= 1;
+ }
+ decoder->pt_len[i] = j;
+ code += weight;
+ }
+}
+
+static void read_tree_c(UNLZHHandler decoder) /* read tree from file */
+{
+ int i, c;
+
+ i = 0;
+ while(i < N1)
+ {
+ if(getbits(decoder, 1))
+ decoder->c_len[i] = getbits(decoder, LENFIELD) + 1;
+ else
+ decoder->c_len[i] = 0;
+ if(++i == 3 && decoder->c_len[0] == 1 &&
+ decoder->c_len[1] == 1 && decoder->c_len[2] == 1)
+ {
+ c = getbits(decoder, CBIT);
+ for(i = 0; i < N1; i++)
+ decoder->c_len[i] = 0;
+ for(i = 0; i < 4096; i++)
+ decoder->c_table[i] = c;
+ return;
+ }
+ }
+ make_table(decoder, N1, decoder->c_len, 12, decoder->c_table);
+}
+
+static void read_tree_p(UNLZHHandler decoder) /* read tree from file */
+{
+ int i, c;
+
+ i = 0;
+ while(i < SNP)
+ {
+ decoder->pt_len[i] = getbits(decoder, LENFIELD);
+ if(++i == 3 && decoder->pt_len[0] == 1 &&
+ decoder->pt_len[1] == 1 && decoder->pt_len[2] == 1)
+ {
+ c = getbits(decoder, MAX_DICBIT - 6);
+ for(i = 0; i < SNP; i++)
+ decoder->c_len[i] = 0;
+ for(i = 0; i < 256; i++)
+ decoder->c_table[i] = c;
+ return;
+ }
+ }
+}
+
+static void decode_start_fix(UNLZHHandler decoder)
+{
+ decoder->n_max = 314;
+ decoder->maxmatch = 60;
+ init_getbits(decoder);
+ decoder->snp = 1 << (12 - 6);
+ start_c_dyn(decoder);
+ ready_made(decoder, 0);
+ make_table(decoder, decoder->snp, decoder->pt_len, 8, decoder->pt_table);
+}
+
+static unsigned short decode_c_st0(UNLZHHandler decoder)
+{
+ int i, j;
+
+ if(decoder->blocksize == 0) /* read block head */
+ {
+ /* read block blocksize */
+ decoder->blocksize = getbits(decoder, BUFBITS);
+ read_tree_c(decoder);
+ if(getbits(decoder, 1))
+ {
+ read_tree_p(decoder);
+ }
+ else
+ {
+ ready_made(decoder, 1);
+ }
+ make_table(decoder, SNP, decoder->pt_len, 8, decoder->pt_table);
+ }
+ decoder->blocksize--;
+ j = decoder->c_table[decoder->bitbuf >> 4];
+ if(j < N1)
+ fillbuf(decoder, decoder->c_len[j]);
+ else
+ {
+ fillbuf(decoder, 12);
+ i = decoder->bitbuf;
+ do
+ {
+ if((short)i < 0)
+ j = decoder->right[j];
+ else
+ j = decoder->left [j];
+ i <<= 1;
+ } while(j >= N1);
+ fillbuf(decoder, decoder->c_len[j] - 12);
+ }
+ if(j == N1 - 1)
+ j += getbits(decoder, EXTRABITS);
+ return j;
+}
+
+static unsigned short decode_p_st0(UNLZHHandler decoder)
+{
+ int i, j;
+
+ j = decoder->pt_table[decoder->bitbuf >> 8];
+ if(j < decoder->snp)
+ {
+ fillbuf(decoder, decoder->pt_len[j]);
+ }
+ else
+ {
+ fillbuf(decoder, 8);
+ i = decoder->bitbuf;
+ do
+ {
+ if((short)i < 0)
+ j = decoder->right[j];
+ else
+ j = decoder->left[j];
+ i <<= 1;
+ } while(j >= decoder->snp);
+ fillbuf(decoder, decoder->pt_len[j] - 8);
+ }
+ return (j << 6) + getbits(decoder, 6);
+}
+
+static unsigned short decode_c_lzs(UNLZHHandler decoder)
+{
+ if(getbits(decoder, 1))
+ return getbits(decoder, 8);
+ decoder->matchpos = getbits(decoder, 11);
+ return getbits(decoder, 4) + 0x100;
+}
+
+static unsigned short decode_p_lzs(UNLZHHandler decoder)
+{
+ return (decoder->loc - decoder->matchpos - MAGIC0) & 0x7ff;
+}
+
+static void decode_start_lzs(UNLZHHandler decoder)
+{
+ init_getbits(decoder);
+}
+
+static unsigned short decode_c_lz5(UNLZHHandler decoder)
+{
+ int c;
+
+ if(decoder->flagcnt == 0)
+ {
+ decoder->flagcnt = 8;
+ decoder->flag = NEXTBYTE;
+ }
+ decoder->flagcnt--;
+ c = NEXTBYTE;
+ if((decoder->flag & 1) == 0)
+ {
+ decoder->matchpos = c;
+ c = NEXTBYTE;
+ decoder->matchpos += (c & 0xf0) << 4;
+ c &= 0x0f;
+ c += 0x100;
+ }
+ decoder->flag >>= 1;
+ return c;
+}
+
+static unsigned short decode_p_lz5(UNLZHHandler decoder)
+{
+ return (decoder->loc - decoder->matchpos - MAGIC5) & 0xfff;
+}
+
+static void decode_start_lz5(UNLZHHandler decoder)
+{
+ int i;
+
+ decoder->flagcnt = 0;
+ for(i = 0; i < 256; i++)
+ memset(&decoder->text[i * 13 + 18], i, 13);
+ for(i = 0; i < 256; i++)
+ decoder->text[256 * 13 + 18 + i] = i;
+ for(i = 0; i < 256; i++)
+ decoder->text[256 * 13 + 256 + 18 + i] = 255 - i;
+ memset(&decoder->text[256 * 13 + 512 + 18], 0, 128);
+ memset(&decoder->text[256 * 13 + 512 + 128 + 18], ' ', 128 - 18);
+}
+
+static int make_table(UNLZHHandler decoder,
+ int nchar, unsigned char bitlen[],
+ int tablebits, unsigned short table[])
+{
+ unsigned short cnttable[17]; /* count of bitlen */
+ unsigned short weight[17]; /* 0x10000ul >> bitlen */
+ unsigned short start[17]; /* first code of bitlen */
+ unsigned short total;
+ unsigned int i;
+ int j, k, l, m, n, available;
+ unsigned short *p;
+
+ available = nchar;
+
+/* initialize */
+ for(i = 1; i <= 16; i++)
+ {
+ cnttable[i] = 0;
+ weight[i] = 1 << (16 - i);
+ }
+
+/* cnttable */
+ for(i = 0; i < nchar; i++)
+ cnttable[bitlen[i]]++;
+
+/* calculate first code */
+ total = 0;
+ for(i = 1; i <= 16; i++)
+ {
+ start[i] = total;
+ total += weight[i] * cnttable[i];
+ }
+ if((total & 0xffff) != 0)
+ {
+ fprintf(stderr, "Decode: Bad table (5)\n");
+ /*exit(1);*/ /* for win32gui i/f 2002/8/17 */
+ return 1;
+ }
+
+/* shift data for make table. */
+ m = 16 - tablebits;
+ for(i = 1; i <= tablebits; i++)
+ {
+ start[i] >>= m;
+ weight[i] >>= m;
+ }
+
+/* initialize */
+ j = start[tablebits + 1] >> m;
+ k = 1 << tablebits;
+ if(j != 0)
+ for(i = j; i < k; i++)
+ table[i] = 0;
+
+/* create table and tree */
+ for(j = 0; j < nchar; j++)
+ {
+ k = bitlen[j];
+ if(k == 0)
+ continue;
+ l = start[k] + weight[k];
+ if(k <= tablebits)
+ {
+ /* code in table */
+ for(i = start[k]; i < l; i++)
+ table[i] = j;
+ }
+ else
+ {
+ /* code not in table */
+ p = &table[(i = start[k]) >> m];
+ i <<= tablebits;
+ n = k - tablebits;
+ /* make tree (n length) */
+ while(--n >= 0)
+ {
+ if(*p == 0)
+ {
+ decoder->right[available] = decoder->left[available] = 0;
+ *p = available++;
+ }
+ if(i & 0x8000)
+ p = &decoder->right[*p];
+ else
+ p = &decoder->left[*p];
+ i <<= 1;
+ }
+ *p = j;
+ }
+ start[k] = l;
+ }
+ return 0;
+}
+
+static int fill_inbuf(UNLZHHandler decoder)
+{
+ long n, i;
+
+ if(decoder->compsize == 0)
+ return EOF;
+ i = INBUFSIZ;
+ if(i > decoder->compsize)
+ i = (long)decoder->compsize;
+ n = decoder->read_func((char *)decoder->inbuf, i, decoder->user_val);
+ if(n <= 0)
+ return EOF;
+ decoder->inbuf_size = n;
+ decoder->inbuf_cnt = 1;
+ decoder->compsize -= n;
+ return (int)decoder->inbuf[0];
+}
+
+/* Shift bitbuf n bits left, read n bits */
+static void fillbuf(UNLZHHandler decoder, unsigned char n)
+{
+ unsigned char bitcount;
+ unsigned short bitbuf;
+
+ bitcount = decoder->bitcount;
+ bitbuf = decoder->bitbuf;
+ while(n > bitcount)
+ {
+ n -= bitcount;
+ bitbuf = (bitbuf << bitcount)
+ + (decoder->subbitbuf >> (CHAR_BIT - bitcount));
+ decoder->subbitbuf = (unsigned char)NEXTBYTE;
+ bitcount = CHAR_BIT;
+ }
+ bitcount -= n;
+ bitbuf = (bitbuf << n) + (decoder->subbitbuf >> (CHAR_BIT - n));
+ decoder->subbitbuf <<= n;
+ decoder->bitcount = bitcount;
+ decoder->bitbuf = bitbuf;
+}
+
+static unsigned short getbits(UNLZHHandler decoder, unsigned char n)
+{
+ unsigned short x;
+
+ x = decoder->bitbuf >> (2 * CHAR_BIT - n);
+ fillbuf(decoder, n);
+ return x;
+}
+
+static void init_getbits(UNLZHHandler decoder)
+{
+ decoder->bitbuf = 0;
+ decoder->subbitbuf = 0;
+ decoder->bitcount = 0;
+ decoder->inbuf_cnt = 0;
+ decoder->inbuf_size = 0;
+ fillbuf(decoder, 2 * CHAR_BIT);
+}
diff --git a/lib/timidity/libarc/unlzh.h b/lib/timidity/libarc/unlzh.h
new file mode 100644
index 0000000000..5b6213de49
--- /dev/null
+++ b/lib/timidity/libarc/unlzh.h
@@ -0,0 +1,35 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifndef ___LZH_H_
+#define ___LZH_H_
+
+typedef struct _UNLZHHandler *UNLZHHandler;
+
+extern UNLZHHandler open_unlzh_handler(long (* read_func)(char*,long,void*),
+ const char *method,
+ long compsize, long origsize,
+ void *user_val);
+extern long unlzh(UNLZHHandler decoder, char *buff, long buff_size);
+extern void close_unlzh_handler(UNLZHHandler decoder);
+
+extern char *lzh_methods[];
+
+#endif /* ___LZH_H_ */
diff --git a/lib/timidity/libarc/url.c b/lib/timidity/libarc/url.c
new file mode 100644
index 0000000000..3575828b99
--- /dev/null
+++ b/lib/timidity/libarc/url.c
@@ -0,0 +1,567 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#include "timidity.h"
+#include "common.h"
+#include "url.h"
+
+/* #define DEBUG */
+
+int url_errno;
+static struct URL_module *url_mod_list = NULL;
+char *user_mailaddr = NULL;
+char *url_user_agent = NULL;
+int url_newline_code = '\n';
+char *url_lib_version = URL_LIB_VERSION;
+int uudecode_unquote_html = 0;
+
+void url_add_module(struct URL_module *m)
+{
+ m->chain = url_mod_list;
+ url_mod_list = m;
+}
+
+void url_add_modules(struct URL_module *m, ...)
+{
+ va_list ap;
+ struct URL_module *mod;
+
+ if(m == NULL)
+ return;
+ url_add_module(m);
+ va_start(ap, m);
+ while((mod = va_arg(ap, struct URL_module *)) != NULL)
+ url_add_module(mod);
+}
+
+static int url_init_nop(void)
+{
+ /* Do nothing any more */
+ return 1;
+}
+
+int url_check_type(char *s)
+{
+ struct URL_module *m;
+
+ for(m = url_mod_list; m; m = m->chain)
+ if(m->type != URL_none_t && m->name_check && m->name_check(s))
+ return m->type;
+ return -1;
+}
+
+URL url_open(char *s)
+{
+ struct URL_module *m;
+
+ for(m = url_mod_list; m; m = m->chain)
+ {
+#ifdef DEBUG
+ printf("Check URL type=%d\n", m->type);
+#endif /* DEBUG */
+ if(m->type != URL_none_t && m->name_check && m->name_check(s))
+ {
+#ifdef DEBUG
+ printf("open url (type=%d, name=%s)\n", m->type, s);
+#endif /* DEBUG */
+ if(m->url_init != url_init_nop)
+ {
+ if(m->url_init && m->url_init() < 0)
+ return NULL;
+ m->url_init = url_init_nop;
+ }
+
+ url_errno = URLERR_NONE;
+ errno = 0;
+ return m->url_open(s);
+ }
+ }
+
+ url_errno = URLERR_NOURL;
+ errno = ENOENT;
+ return NULL;
+}
+
+long url_read(URL url, void *buff, long n)
+{
+ if(n <= 0)
+ return 0;
+ url_errno = URLERR_NONE;
+ errno = 0;
+ if(url->nread >= url->readlimit) {
+ url->eof = 1;
+ return 0;
+ }
+ if(url->nread + n > url->readlimit)
+ n = (long)(url->readlimit - url->nread);
+ n = url->url_read(url, buff, n);
+ if(n > 0)
+ url->nread += n;
+ return n;
+}
+
+long url_safe_read(URL url, void *buff, long n)
+{
+ long i;
+ if(n <= 0)
+ return 0;
+
+ do /* Ignore signal intruption */
+ {
+ errno = 0;
+ i = url_read(url, buff, n);
+ } while(i == -1 && errno == EINTR);
+#if 0
+ /* Already done in url_read!! */
+ if(i > 0)
+ url->nread += i;
+#endif
+ return i;
+}
+
+long url_nread(URL url, void *buff, long n)
+{
+ long insize = 0;
+ char *s = (char *)buff;
+
+ do
+ {
+ long i;
+ i = url_safe_read(url, s + insize, n - insize);
+ if(i <= 0)
+ {
+ if(insize == 0)
+ return i;
+ break;
+ }
+ insize += i;
+ } while(insize < n);
+
+ return insize;
+}
+
+char *url_gets(URL url, char *buff, int n)
+{
+ if(url->nread >= url->readlimit)
+ return NULL;
+
+ if(url->url_gets == NULL)
+ {
+ int maxlen, i, c;
+ int newline = url_newline_code;
+
+ maxlen = n - 1;
+ if(maxlen == 0)
+ *buff = '\0';
+ if(maxlen <= 0)
+ return buff;
+ i = 0;
+
+ do
+ {
+ if((c = url_getc(url)) == EOF)
+ break;
+ buff[i++] = c;
+ } while(c != newline && i < maxlen);
+
+ if(i == 0)
+ return NULL; /* EOF */
+ buff[i] = '\0';
+ return buff;
+ }
+
+ url_errno = URLERR_NONE;
+ errno = 0;
+
+ if(url->nread + n > url->readlimit)
+ n = (long)(url->readlimit - url->nread) + 1;
+
+ buff = url->url_gets(url, buff, n);
+ if(buff != NULL)
+ url->nread += strlen(buff);
+ return buff;
+}
+
+int url_readline(URL url, char *buff, int n)
+{
+ int maxlen, i, c;
+
+ maxlen = n - 1;
+ if(maxlen == 0)
+ *buff = '\0';
+ if(maxlen <= 0)
+ return 0;
+ do
+ {
+ i = 0;
+ do
+ {
+ if((c = url_getc(url)) == EOF)
+ break;
+ buff[i++] = c;
+ } while(c != '\r' && c != '\n' && i < maxlen);
+ if(i == 0)
+ return 0; /* EOF */
+ } while(i == 1 && (c == '\r' || c == '\n'));
+
+ if(c == '\r' || c == '\n')
+ i--;
+ buff[i] = '\0';
+ return i;
+}
+
+int url_fgetc(URL url)
+{
+ if(url->nread >= url->readlimit)
+ return EOF;
+
+ url->nread++;
+ if(url->url_fgetc == NULL)
+ {
+ unsigned char c;
+ if(url_read(url, &c, 1) <= 0)
+ return EOF;
+ return (int)c;
+ }
+ url_errno = URLERR_NONE;
+ errno = 0;
+ return url->url_fgetc(url);
+}
+
+long url_seek(URL url, long offset, int whence)
+{
+ long pos, savelimit;
+
+ if(url->url_seek == NULL)
+ {
+ if(whence == SEEK_CUR && offset >= 0)
+ {
+ pos = url_tell(url);
+ if(offset == 0)
+ return pos;
+ savelimit = (long)url->readlimit;
+ url->readlimit = URL_MAX_READLIMIT;
+ url_skip(url, offset);
+ url->readlimit = savelimit;
+ url->nread = 0;
+ return pos;
+ }
+
+ if(whence == SEEK_SET)
+ {
+ pos = url_tell(url);
+ if(pos != -1 && pos <= offset)
+ {
+ if(pos == offset)
+ return pos;
+ savelimit = (long)url->readlimit;
+ url->readlimit = URL_MAX_READLIMIT;
+ url_skip(url, offset - pos);
+ url->readlimit = savelimit;
+ url->nread = 0;
+ return pos;
+ }
+ }
+
+ url_errno = errno = EPERM;
+ return -1;
+ }
+ url_errno = URLERR_NONE;
+ errno = 0;
+ url->nread = 0;
+ return url->url_seek(url, offset, whence);
+}
+
+long url_tell(URL url)
+{
+ url_errno = URLERR_NONE;
+ errno = 0;
+ if(url->url_tell == NULL)
+ return (long)url->nread;
+ return url->url_tell(url);
+}
+
+void url_skip(URL url, long n)
+{
+ char tmp[BUFSIZ];
+
+ if(url->url_seek != NULL)
+ {
+ long savenread;
+
+ savenread = (long)url->nread;
+ if(savenread >= url->readlimit)
+ return;
+ if(savenread + n > url->readlimit)
+ n = (long)(url->readlimit - savenread);
+ if(url->url_seek(url, n, SEEK_CUR) != -1)
+ {
+ url->nread = savenread + n;
+ return;
+ }
+ url->nread = savenread;
+ }
+
+ while(n > 0)
+ {
+ long c;
+
+ c = n;
+ if(c > sizeof(tmp))
+ c = sizeof(tmp);
+ c = url_read(url, tmp, c);
+ if(c <= 0)
+ break;
+ n -= c;
+ }
+}
+
+void url_rewind(URL url)
+{
+ if(url->url_seek != NULL)
+ url->url_seek(url, 0, SEEK_SET);
+ url->nread = 0;
+}
+
+void url_set_readlimit(URL url, long readlimit)
+{
+ if(readlimit < 0)
+ url->readlimit = URL_MAX_READLIMIT;
+ else
+ url->readlimit = (unsigned long)readlimit;
+ url->nread = 0;
+}
+
+URL alloc_url(int size)
+{
+ URL url;
+#ifdef HAVE_SAFE_MALLOC
+ url = (URL)safe_malloc(size);
+ memset(url, 0, size);
+#else
+ url = (URL)malloc(size);
+ if(url != NULL)
+ memset(url, 0, size);
+ else
+ url_errno = errno;
+#endif /* HAVE_SAFE_MALLOC */
+
+ url->nread = 0;
+ url->readlimit = URL_MAX_READLIMIT;
+ url->eof = 0;
+ return url;
+}
+
+void url_close(URL url)
+{
+ int save_errno = errno;
+
+ if(url == NULL)
+ {
+ fprintf(stderr, "URL stream structure is NULL?\n");
+#ifdef ABORT_AT_FATAL
+ abort();
+#endif /* ABORT_AT_FATAL */
+ }
+ else if(url->url_close == NULL)
+ {
+ fprintf(stderr, "URL Error: Already URL is closed (type=%d)\n",
+ url->type);
+#ifdef ABORT_AT_FATAL
+ abort();
+#endif /* ABORT_AT_FATAL */
+ }
+ else
+ {
+ url->url_close(url);
+#if 0
+ url->url_close = NULL;
+#endif /* unix */
+ }
+ errno = save_errno;
+}
+
+#if defined(TILD_SCHEME_ENABLE)
+#include <pwd.h>
+char *url_expand_home_dir(char *fname)
+{
+ static char path[BUFSIZ];
+ char *dir;
+ int dirlen;
+
+ if(fname[0] != '~')
+ return fname;
+
+ if(IS_PATH_SEP(fname[1])) /* ~/... */
+ {
+ fname++;
+ if((dir = getenv("HOME")) == NULL)
+ if((dir = getenv("home")) == NULL)
+ return fname;
+ }
+ else /* ~user/... */
+ {
+ struct passwd *pw;
+ int i;
+
+ fname++;
+ for(i = 0; i < sizeof(path) - 1 && fname[i] && !IS_PATH_SEP(fname[i]); i++)
+ path[i] = fname[i];
+ path[i] = '\0';
+ if((pw = getpwnam(path)) == NULL)
+ return fname - 1;
+ fname += i;
+ dir = pw->pw_dir;
+ }
+ dirlen = strlen(dir);
+ strncpy(path, dir, sizeof(path) - 1);
+ if(sizeof(path) > dirlen)
+ strncat(path, fname, sizeof(path) - dirlen - 1);
+ path[sizeof(path) - 1] = '\0';
+ return path;
+}
+char *url_unexpand_home_dir(char *fname)
+{
+ static char path[BUFSIZ];
+ char *dir, *p;
+ int dirlen;
+
+ if(!IS_PATH_SEP(fname[0]))
+ return fname;
+
+ if((dir = getenv("HOME")) == NULL)
+ if((dir = getenv("home")) == NULL)
+ return fname;
+ dirlen = strlen(dir);
+ if(dirlen == 0 || dirlen >= sizeof(path) - 2)
+ return fname;
+ memcpy(path, dir, dirlen);
+ if(!IS_PATH_SEP(path[dirlen - 1]))
+ path[dirlen++] = PATH_SEP;
+
+#ifndef __W32__
+ if(strncmp(path, fname, dirlen) != 0)
+#else
+ if(strncasecmp(path, fname, dirlen) != 0)
+#endif /* __W32__ */
+ return fname;
+
+ path[0] = '~';
+ path[1] = '/';
+ p = fname + dirlen;
+ if(strlen(p) >= sizeof(path) - 3)
+ return fname;
+ path[2] = '\0';
+ strcat(path, p);
+ return path;
+}
+#else
+char *url_expand_home_dir(char *fname)
+{
+ return fname;
+}
+char *url_unexpand_home_dir(char *fname)
+{
+ return fname;
+}
+#endif
+
+static char *url_strerror_txt[] =
+{
+ "", /* URLERR_NONE */
+ "Unknown URL", /* URLERR_NOURL */
+ "Operation not permitted", /* URLERR_OPERM */
+ "Can't open a URL", /* URLERR_CANTOPEN */
+ "Invalid URL form", /* URLERR_IURLF */
+ "URL too long", /* URLERR_URLTOOLONG */
+ "No mail address", /* URLERR_NOMAILADDR */
+ ""
+};
+
+char *url_strerror(int no)
+{
+ if(no <= URLERR_NONE)
+ return strerror(no);
+ if(no >= URLERR_MAXNO)
+ return "Internal error";
+ return url_strerror_txt[no - URLERR_NONE];
+}
+
+void *url_dump(URL url, long nbytes, long *read_size)
+{
+ long allocated, offset, read_len;
+ char *buff;
+
+ if(read_size != NULL)
+ *read_size = 0;
+ if(nbytes == 0)
+ return NULL;
+ if(nbytes >= 0)
+ {
+ buff = (void *)safe_malloc(nbytes);
+ if(nbytes == 0)
+ return buff;
+ read_len = url_nread(url, buff, nbytes);
+ if(read_size != NULL)
+ *read_size = read_len;
+ if(read_len <= 0)
+ {
+ free(buff);
+ return NULL;
+ }
+ return buff;
+ }
+
+ allocated = 1024;
+ buff = (char *)safe_malloc(allocated);
+ offset = 0;
+ read_len = allocated;
+ while((nbytes = url_read(url, buff + offset, read_len)) > 0)
+ {
+ offset += nbytes;
+ read_len -= nbytes;
+ if(offset == allocated)
+ {
+ read_len = allocated;
+ allocated *= 2;
+ buff = (char *)safe_realloc(buff, allocated);
+ }
+ }
+ if(offset == 0)
+ {
+ free(buff);
+ return NULL;
+ }
+ if(read_size != NULL)
+ *read_size = offset;
+ return buff;
+}
diff --git a/lib/timidity/libarc/url.h b/lib/timidity/libarc/url.h
new file mode 100644
index 0000000000..dab2e14ef3
--- /dev/null
+++ b/lib/timidity/libarc/url.h
@@ -0,0 +1,239 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifndef ___URL_H_
+#define ___URL_H_
+
+/* This header file from liburl-1.8.3.
+ * You can get full source from:
+ * http://www.goice.co.jp/member/mo/release/index.html#liburl
+ */
+
+
+#define URL_LIB_VERSION "1.9.5"
+
+/* Define if you want to enable pipe command scheme ("command|") */
+#define PIPE_SCHEME_ENABLE
+
+/* Define if you want to appended on a user's home directory if a filename
+ * is beginning with '~'
+ */
+#if !defined(__MACOS__) && !defined(__W32__)
+#define TILD_SCHEME_ENABLE
+#endif
+
+/* Define if you want to use soft directory cache */
+#ifndef URL_DIR_CACHE_DISABLE
+#define URL_DIR_CACHE_ENABLE
+#endif /* URL_DIR_CACHE_DISABLE */
+
+/* Define if you want to use XOVER command in NNTP */
+/* #define URL_NEWS_XOVER_SUPPORT "XOVER", "XOVERVIEW" */
+
+/* M:Must, O:Optional defined */
+typedef struct _URL
+{
+ int type; /* M */
+
+ long (* url_read)(struct _URL *url, void *buff, long n); /* M */
+ char *(* url_gets)(struct _URL *url, char *buff, int n); /* O */
+ int (* url_fgetc)(struct _URL *url); /* O */
+ long (* url_seek)(struct _URL *url, long offset, int whence); /* O */
+ long (* url_tell)(struct _URL *url); /* O */
+ void (* url_close)(struct _URL *url); /* M */
+
+ unsigned long nread; /* Reset in url_seek, url_rewind,
+ url_set_readlimit */
+ unsigned long readlimit;
+ int eof; /* Used in url_nread and others */
+} *URL;
+#define URLm(url, m) (((URL)url)->m)
+
+#define url_eof(url) URLm((url), eof)
+
+/* open URL stream */
+extern URL url_open(char *url_string);
+
+/* close URL stream */
+extern void url_close(URL url);
+
+/* read n bytes */
+extern long url_read(URL url, void *buff, long n);
+extern long url_safe_read(URL url, void *buff, long n);
+extern long url_nread(URL url, void *buff, long n);
+
+/* read a line */
+/* Like a fgets */
+extern char *url_gets(URL url, char *buff, int n);
+
+/* Allow termination by CR or LF or both. Ignored empty lines.
+ * CR or LF is truncated.
+ * Success: length of the line.
+ * EOF or Error: EOF
+ */
+extern int url_readline(URL url, char *buff, int n);
+
+/* read a byte */
+extern int url_fgetc(URL url);
+#define url_getc(url) \
+ ((url)->nread >= (url)->readlimit ? ((url)->eof = 1, EOF) : \
+ (url)->url_fgetc != NULL ? ((url)->nread++, (url)->url_fgetc(url)) : \
+ url_fgetc(url))
+
+/* seek position */
+extern long url_seek(URL url, long offset, int whence);
+
+/* get the current position */
+extern long url_tell(URL url);
+
+/* skip n bytes */
+extern void url_skip(URL url, long n);
+
+/* seek to first position */
+extern void url_rewind(URL url);
+
+/* dump */
+void *url_dump(URL url, long nbytes, long *real_read);
+
+/* set read limit */
+void url_set_readlimit(URL url, long readlimit);
+
+/* url_errno to error message */
+extern char *url_strerror(int no);
+
+/* allocate URL structure */
+extern URL alloc_url(int size);
+
+/* Check URL type. */
+extern int url_check_type(char *url_string);
+
+/* replace `~' to user directory */
+extern char *url_expand_home_dir(char *filename);
+extern char *url_unexpand_home_dir(char *filename);
+
+extern int url_errno;
+enum url_errtypes
+{
+ URLERR_NONE = 10000, /* < 10000 represent system call's errno */
+ URLERR_NOURL, /* Unknown URL */
+ URLERR_OPERM, /* Operation not permitted */
+ URLERR_CANTOPEN, /* Can't open a URL */
+ URLERR_IURLF, /* Invalid URL form */
+ URLERR_URLTOOLONG, /* URL too long */
+ URLERR_NOMAILADDR, /* No mail address */
+ URLERR_MAXNO
+};
+
+struct URL_module
+{
+ /* url type */
+ int type;
+
+ /* URL checker */
+ int (* name_check)(char *url_string);
+
+ /* Once call just before url_open(). */
+ int (* url_init)(void);
+
+ /* Open specified URL */
+ URL (* url_open)(char *url_string);
+
+ /* chain next modules */
+ struct URL_module *chain;
+};
+
+extern void url_add_module(struct URL_module *m);
+extern void url_add_modules(struct URL_module *m, ...);
+
+extern URL url_file_open(char *filename);
+extern URL url_dir_open(char *directory_name);
+extern URL url_http_open(char *url_string);
+extern URL url_ftp_open(char *url_string);
+extern URL url_newsgroup_open(char *url_string);
+extern URL url_news_open(char *url_string);
+extern URL url_pipe_open(char *command);
+
+/* No URL_module */
+extern URL url_mem_open(char *memory, long memsiz, int autofree);
+extern URL url_inflate_open(URL instream, long compsize, int autoclose);
+extern URL url_buff_open(URL url, int autoclose);
+extern URL url_cache_open(URL url, int autoclose);
+extern void url_cache_detach(URL url);
+extern void url_cache_disable(URL url);
+extern URL url_uudecode_open(URL reader, int autoclose);
+extern URL url_b64decode_open(URL reader, int autoclose);
+extern URL url_hqxdecode_open(URL reader, int dataonly, int autoclose);
+extern URL url_qsdecode_open(URL reader, int autoclose);
+extern URL url_cgi_escape_open(URL reader, int autoclose);
+extern URL url_cgi_unescape_open(URL reader, int autoclose);
+
+extern char *url_dir_name(URL url);
+extern char *url_newsgroup_name(URL url);
+extern int url_news_connection_cache(int flag);
+
+extern char *url_lib_version;
+extern char *user_mailaddr;
+extern char *url_user_agent;
+extern char *url_http_proxy_host;
+extern unsigned short url_http_proxy_port;
+extern char *url_ftp_proxy_host;
+extern unsigned short url_ftp_proxy_port;
+extern int url_newline_code;
+extern int uudecode_unquote_html;
+
+enum url_types
+{
+ URL_none_t, /* Undefined URL */
+ URL_file_t, /* File system */
+ URL_dir_t, /* Directory entry */
+ URL_http_t, /* HTTP */
+ URL_ftp_t, /* FTP */
+ URL_news_t, /* NetNews article */
+ URL_newsgroup_t, /* NetNews group */
+ URL_pipe_t, /* Pipe */
+ URL_mem_t, /* On memory */
+ URL_buff_t, /* Buffered stream */
+ URL_cache_t, /* Cached stream */
+ URL_uudecode_t, /* UU decoder */
+ URL_b64decode_t, /* Base64 decoder */
+ URL_qsdecode_t, /* Quoted-string decoder */
+ URL_hqxdecode_t, /* HQX decoder */
+ URL_cgi_escape_t, /* WWW CGI Escape */
+ URL_cgi_unescape_t, /* WWW CGI Unescape */
+ URL_arc_t, /* arc stream */
+
+ URL_inflate_t = 99, /* LZ77 decode stream */
+
+ URL_extension_t = 100 /* extentional stream >= 100 */
+};
+
+enum url_news_conn_type
+{
+ URL_NEWS_CONN_NO_CACHE,
+ URL_NEWS_CONN_CACHE,
+ URL_NEWS_CLOSE_CACHE,
+ URL_NEWS_GET_FLAG
+};
+
+#define IS_URL_SEEK_SAFE(url) ((url)->url_seek != NULL && \
+ (url)->type != URL_buff_t)
+
+#define URL_MAX_READLIMIT ((~(unsigned long)0) >> 1)
+#endif /* ___URL_H_ */
diff --git a/lib/timidity/libarc/url_b64decode.c b/lib/timidity/libarc/url_b64decode.c
new file mode 100644
index 0000000000..a080a79b7f
--- /dev/null
+++ b/lib/timidity/libarc/url_b64decode.c
@@ -0,0 +1,254 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "timidity.h"
+#include "url.h"
+
+#define DECODEBUFSIZ 255 /* Must be power of 3 */
+
+typedef struct _URL_b64decode
+{
+ char common[sizeof(struct _URL)];
+ URL reader;
+ long rpos;
+ int beg, end, eof, eod;
+ unsigned char decodebuf[DECODEBUFSIZ];
+ int autoclose;
+} URL_b64decode;
+
+static long url_b64decode_read(URL url, void *buff, long n);
+static int url_b64decode_fgetc(URL url);
+static long url_b64decode_tell(URL url);
+static void url_b64decode_close(URL url);
+
+URL url_b64decode_open(URL reader, int autoclose)
+{
+ URL_b64decode *url;
+
+ url = (URL_b64decode *)alloc_url(sizeof(URL_b64decode));
+ if(url == NULL)
+ {
+ if(autoclose)
+ url_close(reader);
+ url_errno = errno;
+ return NULL;
+ }
+
+ /* common members */
+ URLm(url, type) = URL_b64decode_t;
+ URLm(url, url_read) = url_b64decode_read;
+ URLm(url, url_gets) = NULL;
+ URLm(url, url_fgetc) = url_b64decode_fgetc;
+ URLm(url, url_seek) = NULL;
+ URLm(url, url_tell) = url_b64decode_tell;
+ URLm(url, url_close) = url_b64decode_close;
+
+ /* private members */
+ url->reader = reader;
+ url->rpos = 0;
+ url->beg = 0;
+ url->end = 0;
+ url->eof = url->eod = 0;
+ memset(url->decodebuf, 0, sizeof(url->decodebuf));
+ url->autoclose = autoclose;
+
+ return (URL)url;
+}
+
+static int b64getchar(URL reader)
+{
+ int c;
+ static int b64_decode_table[256] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0,
+ 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, EOF, 0, 0, 0,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 0, 0, 0, 0, 0
+ };
+
+ do
+ {
+ if((c = url_getc(reader)) == EOF)
+ return EOF;
+ } while(c == '\r' || c == '\n');
+ return b64_decode_table[c];
+}
+
+static int b64decode(URL_b64decode *urlp)
+{
+ int c1, c2, c3, c4;
+ int n;
+ unsigned char *p;
+ URL url;
+
+ if(urlp->eod)
+ {
+ urlp->eof = 1;
+ return 1;
+ }
+
+ p = urlp->decodebuf;
+ url = urlp->reader;
+ n = 0;
+ while(n < DECODEBUFSIZ)
+ {
+ if((c1 = b64getchar(url)) == EOF)
+ {
+ urlp->eod = 1;
+ break;
+ }
+ if((c2 = b64getchar(url)) == EOF)
+ {
+ urlp->eod = 1;
+ break;
+ }
+ p[n++] = ((c1 << 2) | ((c2 & 0x30) >> 4));
+
+ if((c3 = b64getchar(url)) == EOF)
+ {
+ urlp->eod = 1;
+ break;
+ }
+ p[n++] = (((c2 & 0xf) << 4) | ((c3 & 0x3c) >> 2));
+
+ if((c4 = b64getchar(url)) == EOF)
+ {
+ urlp->eod = 1;
+ break;
+ }
+ p[n++] = (((c3 & 0x03) << 6) | c4);
+ }
+
+ urlp->rpos += urlp->beg;
+ urlp->beg = 0;
+ urlp->end = n;
+
+ if(n == 0)
+ {
+ urlp->eof = 1;
+ return 1;
+ }
+
+ return 0;
+}
+
+static long url_b64decode_read(URL url, void *buff, long size)
+{
+ URL_b64decode *urlp = (URL_b64decode *)url;
+ unsigned char *p = (unsigned char *)buff;
+ long n;
+
+ if(urlp->eof)
+ return 0;
+
+ n = 0;
+ while(n < size)
+ {
+ int i;
+
+ if(urlp->beg == urlp->end)
+ if(b64decode(urlp))
+ break;
+ i = urlp->end - urlp->beg;
+ if(i > size - n)
+ i = size - n;
+ memcpy(p + n, urlp->decodebuf + urlp->beg, i);
+ n += i;
+ urlp->beg += i;
+ }
+ return n;
+}
+
+static int url_b64decode_fgetc(URL url)
+{
+ URL_b64decode *urlp = (URL_b64decode *)url;
+
+ if(urlp->eof)
+ return EOF;
+ if(urlp->beg == urlp->end)
+ if(b64decode(urlp))
+ return EOF;
+
+ return (int)urlp->decodebuf[urlp->beg++];
+}
+
+static long url_b64decode_tell(URL url)
+{
+ URL_b64decode *urlp = (URL_b64decode *)url;
+
+ return urlp->rpos + urlp->beg;
+}
+
+static void url_b64decode_close(URL url)
+{
+ URL_b64decode *urlp = (URL_b64decode *)url;
+
+ if(urlp->autoclose)
+ url_close(urlp->reader);
+ free(url);
+}
+
+#ifdef B64DECODE_MAIN
+void main(int argc, char** argv)
+{
+ URL b64decoder;
+ char buff[256], *filename;
+ int c;
+
+ if(argc != 2)
+ {
+ fprintf(stderr, "Usage: %s b64-filename\n", argv[0]);
+ exit(1);
+ }
+ filename = argv[1];
+
+ if((b64decoder = url_file_open(filename)) == NULL)
+ {
+ perror(argv[1]);
+ url_close(b64decoder);
+ exit(1);
+ }
+
+ b64decoder = url_b64decode_open(b64decoder, 1);
+#if B64DECODE_MAIN
+ while((c = url_getc(b64decoder)) != EOF)
+ putchar(c);
+#else
+ while((c = url_read(b64decoder, buff, sizeof(buff))) > 0)
+ write(1, buff, c);
+#endif
+ url_close(b64decoder);
+ exit(0);
+}
+
+#endif /* B64DECODE_MAIN */
diff --git a/lib/timidity/libarc/url_buff.c b/lib/timidity/libarc/url_buff.c
new file mode 100644
index 0000000000..92f55dfbd4
--- /dev/null
+++ b/lib/timidity/libarc/url_buff.c
@@ -0,0 +1,345 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#include "timidity.h"
+#include "url.h"
+
+#define URL_BUFF_SIZE (8*1024)
+#define BASESIZE (URL_BUFF_SIZE * 2)
+#define BASEMASK (BASESIZE-1)
+
+typedef struct _URL_buff
+{
+ char common[sizeof(struct _URL)];
+ URL reader;
+ unsigned char buffer[BASESIZE + URL_BUFF_SIZE]; /* ring buffer */
+ int wp; /* write pointer to the buffer */
+ int rp; /* read pointer from the buffer */
+ long pos, posofs; /* position */
+ int weof;
+ int eof;
+ int autoclose;
+} URL_buff;
+
+static long url_buff_read(URL url, void *buff, long n);
+static char *url_buff_gets(URL url, char *buff, int n);
+static int url_buff_fgetc(URL url);
+static long url_buff_seek(URL url, long offset, int whence);
+static long url_buff_tell(URL url);
+static void url_buff_close(URL url);
+
+URL url_buff_open(URL url, int autoclose)
+{
+ URL_buff *urlp;
+
+ if((urlp = (URL_buff *)alloc_url(sizeof(URL_buff))) == NULL)
+ {
+ if(autoclose)
+ url_close(url);
+ return NULL;
+ }
+
+ /* common members */
+ URLm(urlp, type) = URL_buff_t;
+ URLm(urlp, url_read) = url_buff_read;
+ URLm(urlp, url_gets) = url_buff_gets;
+ URLm(urlp, url_fgetc) = url_buff_fgetc;
+ URLm(urlp, url_seek) = url_buff_seek;
+ URLm(urlp, url_tell) = url_buff_tell;
+ URLm(urlp, url_close) = url_buff_close;
+
+ /* private members */
+ urlp->reader = url;
+ memset(urlp->buffer, 0, sizeof(urlp->buffer));
+ urlp->wp = 0;
+ urlp->rp = 0;
+ if((urlp->posofs = url_tell(url)) == -1)
+ urlp->posofs = 0;
+ urlp->pos = 0;
+ urlp->eof = 0;
+ urlp->autoclose = autoclose;
+
+ return (URL)urlp;
+}
+
+static void prefetch(URL_buff *urlp)
+{
+ long i, n;
+
+ n = url_safe_read(urlp->reader, urlp->buffer + urlp->wp, URL_BUFF_SIZE);
+ if(n <= 0)
+ return;
+ urlp->wp += n;
+ if(urlp->wp < BASESIZE)
+ return;
+ if(urlp->wp == BASESIZE)
+ {
+ urlp->wp = 0;
+ return;
+ }
+
+ /* urlp->wp > BASESIZE */
+ i = urlp->wp - BASESIZE;
+ memcpy(urlp->buffer, urlp->buffer + BASESIZE, i);
+ urlp->wp = i;
+}
+
+static int url_buff_fgetc(URL url)
+{
+ URL_buff *urlp = (URL_buff *)url;
+ int c, r;
+
+ if(urlp->eof)
+ return EOF;
+
+ r = urlp->rp;
+ if(r == urlp->wp)
+ {
+ prefetch(urlp);
+ if(r == urlp->wp)
+ {
+ urlp->eof = 1;
+ return EOF;
+ }
+ }
+ c = urlp->buffer[r];
+ urlp->rp = ((r + 1) & BASEMASK);
+ urlp->pos++;
+ return c;
+}
+
+static long url_buff_read(URL url, void *buff, long n)
+{
+ URL_buff *urlp = (URL_buff *)url;
+ char *s = (char *)buff;
+ int r, i, j;
+
+ if(urlp->eof)
+ return 0;
+
+ r = urlp->rp;
+ if(r == urlp->wp)
+ {
+ prefetch(urlp);
+ if(r == urlp->wp)
+ {
+ urlp->eof = 1;
+ return EOF;
+ }
+ }
+
+ /* first fragment */
+ i = urlp->wp - r;
+ if(i < 0)
+ i = BASESIZE - r;
+ if(i > n)
+ i = n;
+ memcpy(s, urlp->buffer + r, i);
+ r = ((r + i) & BASEMASK);
+
+ if(i == n || r == urlp->wp || r != 0)
+ {
+ urlp->rp = r;
+ urlp->pos += i;
+ return i;
+ }
+
+ /* second fragment */
+ j = urlp->wp;
+ n -= i;
+ s += i;
+ if(j > n)
+ j = n;
+ memcpy(s, urlp->buffer, j);
+ urlp->rp = j;
+ urlp->pos += i + j;
+
+ return i + j;
+}
+
+static long url_buff_tell(URL url)
+{
+ URL_buff *urlp = (URL_buff *)url;
+
+ return urlp->pos + urlp->posofs;
+}
+
+static char *url_buff_gets(URL url, char *buff, int maxsiz)
+{
+ URL_buff *urlp = (URL_buff *)url;
+ int c, r, w;
+ long len, maxlen;
+ int newline = url_newline_code;
+ unsigned char *bp;
+
+ if(urlp->eof)
+ return NULL;
+
+ maxlen = maxsiz - 1;
+ if(maxlen == 0)
+ *buff = '\0';
+ if(maxlen <= 0)
+ return buff;
+ len = 0;
+ r = urlp->rp;
+ w = urlp->wp;
+ bp = urlp->buffer;
+
+ do
+ {
+ if(r == w)
+ {
+ urlp->wp = w;
+ prefetch(urlp);
+ w = urlp->wp;
+ if(r == w)
+ {
+ urlp->eof = 1;
+ if(len == 0)
+ return NULL;
+ buff[len] = '\0';
+ urlp->pos += len;
+ urlp->rp = r;
+ return buff;
+ }
+ }
+ c = bp[r];
+ buff[len++] = c;
+ r = ((r + 1) & BASEMASK);
+ } while(c != newline && len < maxlen);
+ buff[len] = '\0';
+ urlp->pos += len;
+ urlp->rp = r;
+ return buff;
+}
+
+static long url_buff_seek(URL url, long offset, int whence)
+{
+ URL_buff *urlp = (URL_buff *)url;
+ long ret, diff, n;
+ int r, w, filled, i;
+
+ ret = urlp->pos + urlp->posofs;
+ switch(whence)
+ {
+ case SEEK_SET:
+ diff = offset - ret;
+ break;
+ case SEEK_CUR:
+ diff = offset;
+ break;
+ case SEEK_END:
+ if(!urlp->eof)
+ while(url_buff_fgetc(url) != EOF)
+ ;
+ diff = offset;
+ break;
+ default:
+ url_errno = errno = EPERM;
+ return -1;
+ }
+
+ if(diff == 0)
+ {
+ urlp->eof = 0; /* To be more read */
+ return ret;
+ }
+
+ n = 0; /* number of bytes to move */
+ r = urlp->rp; /* read pointer */
+ w = urlp->wp; /* write pointer */
+
+ if(diff > 0)
+ {
+ while(diff > 0)
+ {
+ if(r == w)
+ {
+ urlp->wp = w;
+ prefetch(urlp);
+ w = urlp->wp;
+ if(r == w)
+ {
+ urlp->eof = 1;
+ urlp->pos += n;
+ urlp->rp = r;
+ return ret;
+ }
+ }
+
+ i = w - r;
+ if(i < 0)
+ i = BASESIZE - r;
+ if(i > diff)
+ i = diff;
+ n += i;
+ diff -= i;
+ r = ((r + i) & BASEMASK);
+ }
+ urlp->pos += n;
+ urlp->rp = r;
+ urlp->eof = 0; /* To be more read */
+ return ret;
+ }
+
+ /* diff < 0 */
+
+ diff = -diff;
+ filled = r - w;
+ if(filled <= 0)
+ filled = BASEMASK + filled;
+ filled--;
+ if(filled > urlp->pos)
+ filled = urlp->pos;
+
+ if(filled < diff)
+ {
+ url_errno = errno = EPERM;
+ return -1;
+ }
+
+ /* back `rp' by `diff' */
+ r -= diff;
+ if(r < 0)
+ r += BASESIZE;
+ urlp->rp = r;
+ urlp->pos -= diff;
+ urlp->eof = 0; /* To be more read */
+ return ret;
+}
+
+static void url_buff_close(URL url)
+{
+ URL_buff *urlp = (URL_buff *)url;
+ if(urlp->autoclose)
+ url_close(urlp->reader);
+ free(url);
+}
diff --git a/lib/timidity/libarc/url_cache.c b/lib/timidity/libarc/url_cache.c
new file mode 100644
index 0000000000..dfcc422d71
--- /dev/null
+++ b/lib/timidity/libarc/url_cache.c
@@ -0,0 +1,255 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "timidity.h"
+#include "url.h"
+#include "memb.h"
+
+typedef struct _URL_cache
+{
+ char common[sizeof(struct _URL)];
+ URL reader;
+ int memb_ok;
+ MemBuffer b;
+ long pos;
+ int autoclose;
+} URL_cache;
+
+static long url_cache_read(URL url, void *buff, long n);
+static int url_cache_fgetc(URL url);
+static long url_cache_seek(URL url, long offset, int whence);
+static long url_cache_tell(URL url);
+static void url_cache_close(URL url);
+
+URL url_cache_open(URL url, int autoclose)
+{
+ URL_cache *urlp;
+
+ if(url->type == URL_cache_t && autoclose)
+ {
+ if(((URL_cache *)url)->memb_ok)
+ delete_memb(&((URL_cache *)url)->b);
+ urlp = (URL_cache *)url;
+ url = urlp->reader;
+ }
+ else
+ {
+ if((urlp = (URL_cache *)alloc_url(sizeof(URL_cache))) == NULL)
+ {
+ if(autoclose)
+ url_close(url);
+ return NULL;
+ }
+ }
+
+ /* common members */
+ URLm(urlp, type) = URL_cache_t;
+ URLm(urlp, url_read) = url_cache_read;
+ URLm(urlp, url_gets) = NULL;
+ URLm(urlp, url_fgetc) = url_cache_fgetc;
+ URLm(urlp, url_seek) = url_cache_seek;
+ URLm(urlp, url_tell) = url_cache_tell;
+ URLm(urlp, url_close) = url_cache_close;
+
+ /* private members */
+ urlp->reader = url;
+ urlp->memb_ok = 1;
+ init_memb(&urlp->b);
+ urlp->pos = 0;
+ urlp->autoclose = autoclose;
+
+ return (URL)urlp;
+}
+
+void url_cache_disable(URL url)
+{
+ if(url->type == URL_cache_t)
+ url->url_seek = NULL;
+}
+
+void url_cache_detach(URL url)
+{
+ if(url != NULL && url->type == URL_cache_t)
+ {
+ URL_cache *urlp = (URL_cache *)url;
+ if(urlp->autoclose && urlp->reader != NULL)
+ url_close(urlp->reader);
+ urlp->reader = NULL;
+ }
+}
+
+static long url_cache_read(URL url, void *buff, long n)
+{
+ URL_cache *urlp = (URL_cache *)url;
+ MemBuffer *b = &urlp->b;
+
+ if(!urlp->memb_ok)
+ {
+ if(urlp->reader == NULL)
+ return 0;
+ n = url_read(urlp->reader, buff, n);
+ if(n > 0)
+ urlp->pos += n;
+ return n;
+ }
+
+ if(urlp->pos < b->total_size)
+ {
+ if(n > b->total_size - urlp->pos)
+ n = b->total_size - urlp->pos;
+ urlp->pos += read_memb(b, buff, n);
+ return n;
+ }
+
+ if(url->url_seek == NULL)
+ {
+ delete_memb(b);
+ urlp->memb_ok = 0;
+ if(urlp->reader == NULL)
+ return 0;
+ n = url_read(urlp->reader, buff, n);
+ if(n > 0)
+ urlp->pos += n;
+ return n;
+ }
+
+ if(urlp->reader == NULL)
+ return 0;
+ n = url_read(urlp->reader, buff, n);
+ if(n > 0)
+ {
+ push_memb(b, buff, n);
+ b->cur = b->tail;
+ b->cur->pos = b->cur->size;
+ urlp->pos += n;
+ }
+ return n;
+}
+
+static int url_cache_fgetc(URL url)
+{
+ URL_cache *urlp = (URL_cache *)url;
+ MemBuffer *b = &urlp->b;
+ char c;
+ int i;
+
+ if(!urlp->memb_ok)
+ {
+ if(urlp->reader == NULL)
+ return EOF;
+ if((i = url_getc(urlp->reader)) == EOF)
+ return EOF;
+ urlp->pos++;
+ return i;
+ }
+
+ if(urlp->pos < b->total_size)
+ {
+ read_memb(b, &c, 1);
+ urlp->pos++;
+ return (int)(unsigned char)c;
+ }
+
+ if(url->url_seek == NULL)
+ {
+ delete_memb(b);
+ urlp->memb_ok = 0;
+ if(urlp->reader == NULL)
+ return EOF;
+ if((i = url_getc(urlp->reader)) == EOF)
+ return EOF;
+ urlp->pos++;
+ return i;
+ }
+
+ if(urlp->reader == NULL)
+ return EOF;
+ if((i = url_getc(urlp->reader)) == EOF)
+ return EOF;
+ c = (char)i;
+ push_memb(b, &c, 1);
+ b->cur = b->tail;
+ b->cur->pos = b->cur->size;
+ urlp->pos++;
+ return i;
+}
+
+static long url_cache_seek(URL url, long offset, int whence)
+{
+ URL_cache *urlp = (URL_cache *)url;
+ MemBuffer *b = &urlp->b;
+ long ret, newpos, n, s;
+
+ ret = urlp->pos;
+ switch(whence)
+ {
+ case SEEK_SET:
+ newpos = offset;
+ break;
+ case SEEK_CUR:
+ newpos = ret + offset;
+ break;
+ case SEEK_END:
+ while(url_cache_fgetc(url) != EOF)
+ ;
+ newpos = b->total_size + whence;
+ break;
+ default:
+ url_errno = errno = EPERM;
+ return -1;
+ }
+ if(newpos < 0)
+ newpos = 0;
+ n = newpos - ret;
+
+ if(n < 0)
+ {
+ rewind_memb(b);
+ n = newpos;
+ urlp->pos = 0;
+ }
+
+ s = skip_read_memb(b, n);
+ urlp->pos += s;
+ while(s++ < n && url_cache_fgetc(url) != EOF)
+ ;
+ return ret;
+}
+
+static long url_cache_tell(URL url)
+{
+ return ((URL_cache *)url)->pos;
+}
+
+static void url_cache_close(URL url)
+{
+ URL_cache *urlp = (URL_cache *)url;
+ if(urlp->autoclose && urlp->reader != NULL)
+ url_close(urlp->reader);
+ if(urlp->memb_ok)
+ delete_memb(&urlp->b);
+ free(urlp);
+}
diff --git a/lib/timidity/libarc/url_dir.c b/lib/timidity/libarc/url_dir.c
new file mode 100644
index 0000000000..a231889899
--- /dev/null
+++ b/lib/timidity/libarc/url_dir.c
@@ -0,0 +1,487 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "timidity.h"
+#include "common.h"
+#include "url.h"
+
+#ifdef __W32READDIR__
+#include "readdir.h"
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#elif __MACOS__
+# include "mac_readdir.h"
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#endif
+
+#ifdef URL_DIR_CACHE_ENABLE
+#include <sys/stat.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+#include "strtab.h"
+
+#ifndef S_ISDIR
+#define S_ISDIR(mode) (((mode)&0xF000) == 0x4000)
+#endif /* S_ISDIR */
+
+#ifdef unix
+#define INODE_AVAILABLE
+#endif /* unix */
+
+struct dir_cache_t
+{
+ char **fnames;
+#ifdef INODE_AVAILABLE
+ dev_t dev;
+ ino_t ino;
+#else
+ char *dirname;
+#endif
+ time_t dir_mtime;
+ struct dir_cache_t *next;
+};
+static struct dir_cache_t *dir_cache = NULL;
+
+#ifdef INODE_AVAILABLE
+#define REMOVE_CACHE_ENT(p, isalloced) if(isalloced) free(p); else (p)->ino = 0
+#else
+#define REMOVE_CACHE_ENT(p, isalloced) free((p)->dirname); if(isalloced) free(p); else p->dirname = NULL
+#endif /* INODE_AVAILABLE */
+
+static struct dir_cache_t *scan_cached_files(struct dir_cache_t *p,
+ struct stat *s,
+ char *dirname)
+{
+ StringTable stab;
+ DIR *dirp;
+ struct dirent *d;
+ int allocated;
+
+ if(p == NULL)
+ {
+ if((p = (struct dir_cache_t *)safe_malloc(sizeof(struct dir_cache_t))) ==
+ NULL)
+ return NULL;
+ allocated = 1;
+ } else
+ allocated = 0;
+
+ /* save directory information */
+#ifdef INODE_AVAILABLE
+ p->ino = s->st_ino;
+ p->dev = s->st_dev;
+#else
+ p->dirname = safe_strdup(dirname);
+#endif /* INODE_AVAILABLE */
+ p->dir_mtime = s->st_mtime;
+
+ if((dirp = opendir(dirname)) == NULL)
+ {
+ url_errno = errno;
+ REMOVE_CACHE_ENT(p, allocated);
+ errno = url_errno;
+ return NULL;
+ }
+
+ init_string_table(&stab);
+ while((d = readdir(dirp)) != NULL)
+ {
+ int dlen;
+
+#ifdef INODE_AVAILABLE
+ if(d->d_ino == 0)
+ continue;
+#endif
+ if((dlen = NAMLEN(d)) == 0)
+ continue;
+
+ /* put into string table */
+ if(put_string_table(&stab, d->d_name, dlen) == NULL)
+ {
+ url_errno = errno;
+ delete_string_table(&stab);
+ REMOVE_CACHE_ENT(p, allocated);
+ closedir(dirp);
+ errno = url_errno;
+ return NULL;
+ }
+ }
+ closedir(dirp);
+
+ /* make string array */
+ p->fnames = make_string_array(&stab);
+ if(p->fnames == NULL)
+ {
+ url_errno = errno;
+ delete_string_table(&stab);
+ REMOVE_CACHE_ENT(p, allocated);
+ errno = url_errno;
+ return NULL;
+ }
+ return p;
+}
+
+static struct dir_cache_t *read_cached_files(char *dirname)
+{
+ struct dir_cache_t *p, *q;
+ struct stat s;
+
+ if(stat(dirname, &s) < 0)
+ return NULL;
+ if(!S_ISDIR(s.st_mode))
+ {
+ errno = url_errno = ENOTDIR;
+ return NULL;
+ }
+
+ q = NULL;
+ for(p = dir_cache; p; p = p->next)
+ {
+#ifdef INODE_AVAILABLE
+ if(p->ino == 0)
+#else
+ if(p->dirname == NULL)
+#endif /* INODE_AVAILABLE */
+ {
+ /* Entry is removed.
+ * Save the entry to `q' which is reused for puting in new entry.
+ */
+ if(q != NULL)
+ q = p;
+ continue;
+ }
+
+#ifdef INODE_AVAILABLE
+ if(s.st_dev == p->dev && s.st_ino == p->ino)
+#else
+ if(strcmp(p->dirname, dirname) == 0)
+#endif /* INODE_AVAILABLE */
+
+ {
+ /* found */
+ if(p->dir_mtime == s.st_mtime)
+ return p;
+
+ /* Directory entry is updated */
+ free(p->fnames[0]);
+ free(p->fnames);
+#ifndef INODE_AVAILABLE
+ free(p->dirname);
+#endif /* !INODE_AVAILABLE */
+ return scan_cached_files(p, &s, dirname);
+ }
+ }
+ /* New directory */
+ if((p = scan_cached_files(q, &s, dirname)) == NULL)
+ return NULL;
+ p->next = dir_cache;
+ dir_cache = p;
+ return p;
+}
+#endif /* URL_DIR_CACHE_ENABLE */
+
+typedef struct _URL_dir
+{
+ char common[sizeof(struct _URL)];
+#ifdef URL_DIR_CACHE_ENABLE
+ char **fptr;
+#else
+ DIR *dirp;
+ struct dirent *d;
+#endif /* URL_DIR_CACHE_ENABLE */
+
+ char *ptr;
+ int len;
+ long total;
+ char *dirname;
+ int endp;
+} URL_dir;
+
+static int name_dir_check(char *url_string);
+static long url_dir_read(URL url, void *buff, long n);
+static char *url_dir_gets(URL url, char *buff, int n);
+static long url_dir_tell(URL url);
+static void url_dir_close(URL url);
+
+struct URL_module URL_module_dir =
+{
+ URL_dir_t, /* type */
+ name_dir_check, /* URL checker */
+ NULL, /* initializer */
+ url_dir_open, /* open */
+ NULL /* must be NULL */
+};
+
+static int name_dir_check(char *url_string)
+{
+ if(strncasecmp(url_string, "dir:", 4) == 0)
+ return 1;
+ url_string = pathsep_strrchr(url_string);
+ return url_string != NULL && *(url_string + 1) == '\0';
+}
+
+#ifdef URL_DIR_CACHE_ENABLE
+URL url_dir_open(char *dname)
+{
+ struct dir_cache_t *d;
+ URL_dir *url;
+ int dlen;
+
+ if(dname == NULL)
+ dname = ".";
+ else
+ {
+ if(strncasecmp(dname, "dir:", 4) == 0)
+ dname += 4;
+ if(*dname == '\0')
+ dname = ".";
+ else
+ dname = url_expand_home_dir(dname);
+ }
+ dname = safe_strdup(dname);
+
+ /* Remove tail of path sep. */
+ dlen = strlen(dname);
+ while(dlen > 0 && IS_PATH_SEP(dname[dlen - 1]))
+ dlen--;
+ dname[dlen] = '\0';
+ if(dlen == 0)
+ strcpy(dname, PATH_STRING); /* root */
+
+ d = read_cached_files(dname);
+ if(d == NULL)
+ {
+ free(dname);
+ return NULL;
+ }
+
+ url = (URL_dir *)alloc_url(sizeof(URL_dir));
+ if(url == NULL)
+ {
+ url_errno = errno;
+ free(dname);
+ errno = url_errno; /* restore errno */
+ return NULL;
+ }
+
+ /* common members */
+ URLm(url, type) = URL_dir_t;
+ URLm(url, url_read) = url_dir_read;
+ URLm(url, url_gets) = url_dir_gets;
+ URLm(url, url_fgetc) = NULL;
+ URLm(url, url_seek) = NULL;
+ URLm(url, url_tell) = url_dir_tell;
+ URLm(url, url_close) = url_dir_close;
+
+ /* private members */
+ url->fptr = d->fnames;
+ url->ptr = NULL;
+ url->len = 0;
+ url->total = 0;
+ url->dirname = dname;
+ url->endp = 0;
+
+ return (URL)url;
+}
+#else
+URL url_dir_open(char *dname)
+{
+ URL_dir *url;
+ DIR *dirp;
+ int dlen;
+
+ if(dname == NULL)
+ dname = ".";
+ else
+ {
+ if(strncasecmp(dname, "dir:", 4) == 0)
+ dname += 4;
+ if(*dname == '\0')
+ dname = ".";
+ else
+ dname = url_expand_home_dir(dname);
+ }
+ dname = safe_strdup(dname);
+
+ /* Remove tail of path sep. */
+ dlen = strlen(dname);
+ while(dlen > 0 && IS_PATH_SEP(dname[dlen - 1]))
+ dlen--;
+ dname[dlen] = '\0';
+ if(dlen == 0)
+ strcpy(dname, PATH_STRING); /* root */
+
+ if((dirp = opendir(dname)) == NULL)
+ {
+ url_errno = errno;
+ free(dname);
+ errno = url_errno;
+ return NULL;
+ }
+
+ url = (URL_dir *)alloc_url(sizeof(URL_dir));
+ if(url == NULL)
+ {
+ url_errno = errno;
+ closedir(dirp);
+ free(dname);
+ errno = url_errno;
+ return NULL;
+ }
+
+ /* common members */
+ URLm(url, type) = URL_dir_t;
+ URLm(url, url_read) = url_dir_read;
+ URLm(url, url_gets) = url_dir_gets;
+ URLm(url, url_fgetc) = NULL;
+ URLm(url, url_seek) = NULL;
+ URLm(url, url_tell) = url_dir_tell;
+ URLm(url, url_close) = url_dir_close;
+
+ /* private members */
+ url->dirp = dirp;
+ url->d = NULL;
+ url->ptr = NULL;
+ url->len = 0;
+ url->total = 0;
+ url->dirname = dname;
+ url->endp = 0;
+
+ return (URL)url;
+}
+#endif /* URL_DIR_CACHE_ENABLE */
+
+static long url_dir_tell(URL url)
+{
+ return ((URL_dir *)url)->total;
+}
+
+char *url_dir_name(URL url)
+{
+ if(url->type != URL_dir_t)
+ return NULL;
+ return ((URL_dir *)url)->dirname;
+}
+
+static void url_dir_close(URL url)
+{
+ URL_dir *urlp = (URL_dir *)url;
+#ifndef URL_DIR_CACHE_ENABLE
+ closedir(urlp->dirp);
+#endif
+ free(urlp->dirname);
+ free(urlp);
+}
+
+static long url_dir_read(URL url, void *buff, long n)
+{
+ char *p;
+
+ p = url_dir_gets(url, (char *)buff, (int)n);
+ if(p == NULL)
+ return 0;
+ return (long)strlen(p);
+}
+
+static char *url_dir_gets(URL url, char *buff, int n)
+{
+ URL_dir *urlp = (URL_dir *)url;
+ int i;
+
+ if(urlp->endp)
+ return NULL;
+ if(n <= 0)
+ return buff;
+ if(n == 1)
+ {
+ *buff = '\0';
+ return buff;
+ }
+ n--; /* for '\0' */;
+ for(;;)
+ {
+ if(urlp->len > 0)
+ {
+ i = urlp->len;
+ if(i > n)
+ i = n;
+ memcpy(buff, urlp->ptr, i);
+ buff[i] = '\0';
+ urlp->len -= i;
+ urlp->ptr += i;
+ urlp->total += i;
+ return buff;
+ }
+
+#ifdef URL_DIR_CACHE_ENABLE
+ if(*urlp->fptr == NULL)
+ {
+ urlp->endp = 1;
+ return NULL;
+ }
+ urlp->ptr = *urlp->fptr;
+ urlp->fptr++;
+ urlp->len = strlen(urlp->ptr);
+#else
+ do
+ if((urlp->d = readdir(urlp->dirp)) == NULL)
+ {
+ urlp->endp = 1;
+ return NULL;
+ }
+ while (
+#ifdef INODE_AVAILABLE
+ urlp->d->d_ino == 0 ||
+#endif /* INODE_AVAILABLE */
+ NAMLEN(urlp->d) == 0);
+ urlp->ptr = urlp->d->d_name;
+ urlp->len = NAMLEN(urlp->d);
+#endif
+ }
+}
diff --git a/lib/timidity/libarc/url_file.c b/lib/timidity/libarc/url_file.c
new file mode 100644
index 0000000000..4ee6a581d3
--- /dev/null
+++ b/lib/timidity/libarc/url_file.c
@@ -0,0 +1,461 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include <fcntl.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+// I'm not sure xbmc maps mmapped IO
+#undef HAVE_MMAP
+
+#ifdef __W32__
+#include <windows.h>
+#endif /* __W32__ */
+
+#include "timidity.h"
+
+#ifdef HAVE_MMAP
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#ifndef MAP_FAILED
+#define MAP_FAILED ((caddr_t)-1)
+#endif /* MAP_FAILED */
+
+#else
+/* mmap is not supported */
+#ifdef __W32__
+#define try_mmap(fname, size_ret) w32_mmap(fname, size_ret, &hFile, &hMap)
+#define munmap(addr, size) w32_munmap(addr, size, hFile, hMap)
+#else
+#define try_mmap(dmy1, dmy2) NULL
+#define munmap(addr, size) /* Do nothing */
+#endif /* __W32__ */
+#endif
+
+#include "url.h"
+#ifdef __MACOS__
+#include "mblock.h"
+#endif
+
+#if !defined(__W32__) && !defined(O_BINARY)
+#define O_BINARY 0
+#endif
+
+
+typedef struct _URL_file
+{
+ char common[sizeof(struct _URL)];
+
+ char *mapptr; /* Non NULL if mmap is success */
+ long mapsize;
+ long pos;
+
+#ifdef __W32__
+ HANDLE hFile, hMap;
+#endif /* __W32__ */
+
+ FILE *fp; /* Non NULL if mmap is failure */
+} URL_file;
+
+static int name_file_check(char *url_string);
+static long url_file_read(URL url, void *buff, long n);
+static char *url_file_gets(URL url, char *buff, int n);
+static int url_file_fgetc(URL url);
+static long url_file_seek(URL url, long offset, int whence);
+static long url_file_tell(URL url);
+static void url_file_close(URL url);
+
+struct URL_module URL_module_file =
+{
+ URL_file_t, /* type */
+ name_file_check, /* URL checker */
+ NULL, /* initializer */
+ url_file_open, /* open */
+ NULL /* must be NULL */
+};
+
+static int name_file_check(char *s)
+{
+ int i;
+
+ if(IS_PATH_SEP(s[0]))
+ return 1;
+
+ if(strncasecmp(s, "file:", 5) == 0)
+ return 1;
+
+ if(strncasecmp(s, "filereader:", 10) == 0)
+ return 1;
+
+ if(strncasecmp(s, "special:", 8) == 0)
+ return 1;
+
+#ifdef __W32__
+ /* [A-Za-z]: (for Windows) */
+ if((('A' <= s[0] && s[0] <= 'Z') ||
+ ('a' <= s[0] && s[0] <= 'z')) &&
+ s[1] == ':')
+ return 1;
+#endif /* __W32__ */
+
+ for(i = 0; s[i] && s[i] != ':' && s[i] != '/'; i++)
+ ;
+ if(s[i] == ':' && s[i + 1] == '/')
+ return 0;
+
+ return 1;
+}
+
+#ifdef HAVE_MMAP
+static char *try_mmap(char *path, long *size)
+{
+ int fd;
+ char *p;
+ struct stat st;
+
+ errno = 0;
+ fd = open(path, O_RDONLY | O_BINARY);
+ if(fd < 0)
+ return NULL;
+
+ if(fstat(fd, &st) < 0)
+ {
+ int save_errno = errno;
+ close(fd);
+ errno = save_errno;
+ return NULL;
+ }
+
+ p = (char *)mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if(p == (char *)MAP_FAILED)
+ {
+ int save_errno = errno;
+ close(fd);
+ errno = save_errno;
+ return NULL;
+ }
+ close(fd);
+ *size = (long)st.st_size;
+ return p;
+}
+#elif defined(__W32__)
+static void *w32_mmap(char *fname, long *size_ret, HANDLE *hFilePtr, HANDLE *hMapPtr)
+{
+ void *map;
+
+ *hFilePtr = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ , NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if(*hFilePtr == INVALID_HANDLE_VALUE)
+ return NULL;
+ *size_ret = GetFileSize(*hFilePtr, NULL);
+ if(*size_ret == 0xffffffff)
+ {
+ CloseHandle(*hFilePtr);
+ return NULL;
+ }
+ *hMapPtr = CreateFileMapping(*hFilePtr, NULL, PAGE_READONLY,
+ 0, 0, NULL);
+ if(*hMapPtr == NULL)
+ {
+ CloseHandle(*hFilePtr);
+ return NULL;
+ }
+ map = MapViewOfFile(*hMapPtr, FILE_MAP_READ, 0, 0, 0);
+ if(map == NULL)
+ {
+ CloseHandle(*hMapPtr);
+ CloseHandle(*hFilePtr);
+ return NULL;
+ }
+ return map;
+}
+static void w32_munmap(void *ptr, long size, HANDLE hFile, HANDLE hMap)
+{
+ UnmapViewOfFile(ptr);
+ CloseHandle(hMap);
+ CloseHandle(hFile);
+}
+#endif /* HAVE_MMAP */
+
+URL url_file_open(char *fname)
+{
+ URL_file *url;
+ char *mapptr; /* Non NULL if mmap is success */
+ long mapsize;
+ FILE *fp; /* Non NULL if mmap is failure */
+#ifdef __W32__
+ HANDLE hFile, hMap;
+#endif /* __W32__ */
+
+#ifdef DEBUG
+ printf("url_file_open(%s)\n", fname);
+#endif /* DEBUG */
+
+ if(!strcmp(fname, "-"))
+ {
+ mapptr = NULL;
+ mapsize = 0;
+ fp = stdin;
+ goto done;
+ }
+
+ if(strncasecmp(fname, "file:", 5) == 0)
+ fname += 5;
+ if(*fname == '\0')
+ {
+ url_errno = errno = ENOENT;
+ return NULL;
+ }
+ fname = url_expand_home_dir(fname);
+
+ fp = NULL;
+ mapsize = 0;
+ errno = 0;
+ mapptr = try_mmap(fname, &mapsize);
+ if(errno == ENOENT || errno == EACCES)
+ {
+ url_errno = errno;
+ return NULL;
+ }
+
+#ifdef DEBUG
+ if(mapptr != NULL)
+ printf("mmap - success. size=%d\n", mapsize);
+#ifdef HAVE_MMAP
+ else
+ printf("mmap - failure.\n");
+#endif
+#endif /* DEBUG */
+
+
+ if(mapptr == NULL)
+ {
+#ifdef __MACOS__
+ char *cnvname;
+ MBlockList pool;
+ init_mblock(&pool);
+ cnvname = (char *)strdup_mblock(&pool, fname);
+ mac_TransPathSeparater(fname, cnvname);
+ fp = fopen(cnvname, "rb");
+ reuse_mblock(&pool);
+ if( fp==NULL ){ /*try original name*/
+ fp = fopen(fname, "rb");
+ }
+#else
+ fp = fopen(fname, "rb");
+#endif
+ if(fp == NULL)
+ {
+ url_errno = errno;
+ return NULL;
+ }
+ }
+
+ done:
+ url = (URL_file *)alloc_url(sizeof(URL_file));
+ if(url == NULL)
+ {
+ url_errno = errno;
+ if(mapptr)
+ munmap(mapptr, mapsize);
+ if(fp && fp != stdin)
+ fclose(fp);
+ errno = url_errno;
+ return NULL;
+ }
+
+ /* common members */
+ URLm(url, type) = URL_file_t;
+ URLm(url, url_read) = url_file_read;
+ URLm(url, url_gets) = url_file_gets;
+ URLm(url, url_fgetc) = url_file_fgetc;
+ URLm(url, url_close) = url_file_close;
+ if(fp == stdin)
+ {
+ URLm(url, url_seek) = NULL;
+ URLm(url, url_tell) = NULL;
+ }
+ else
+ {
+ URLm(url, url_seek) = url_file_seek;
+ URLm(url, url_tell) = url_file_tell;
+ }
+
+ /* private members */
+ url->mapptr = mapptr;
+ url->mapsize = mapsize;
+ url->pos = 0;
+ url->fp = fp;
+#ifdef __W32__
+ url->hFile = hFile;
+ url->hMap = hMap;
+#endif /* __W32__ */
+
+ return (URL)url;
+}
+
+static long url_file_read(URL url, void *buff, long n)
+{
+ URL_file *urlp = (URL_file *)url;
+
+ if(urlp->mapptr != NULL)
+ {
+ if(urlp->pos + n > urlp->mapsize)
+ n = urlp->mapsize - urlp->pos;
+ memcpy(buff, urlp->mapptr + urlp->pos, n);
+ urlp->pos += n;
+ }
+ else
+ {
+ if((n = (long)fread(buff, 1, n, urlp->fp)) == 0)
+ {
+ if(ferror(urlp->fp))
+ {
+ url_errno = errno;
+ return -1;
+ }
+ return 0;
+ }
+ }
+ return n;
+}
+
+char *url_file_gets(URL url, char *buff, int n)
+{
+ URL_file *urlp = (URL_file *)url;
+
+ if(urlp->mapptr != NULL)
+ {
+ long s;
+ char *nlp, *p;
+
+ if(urlp->mapsize == urlp->pos)
+ return NULL;
+ if(n <= 0)
+ return buff;
+ if(n == 1)
+ {
+ *buff = '\0';
+ return buff;
+ }
+ n--; /* for '\0' */
+ s = urlp->mapsize - urlp->pos;
+ if(s > n)
+ s = n;
+ p = urlp->mapptr + urlp->pos;
+ nlp = (char *)memchr(p, url_newline_code, s);
+ if(nlp != NULL)
+ s = nlp - p + 1;
+ memcpy(buff, p, s);
+ buff[s] = '\0';
+ urlp->pos += s;
+ return buff;
+ }
+
+ return fgets(buff, n, urlp->fp);
+}
+
+int url_file_fgetc(URL url)
+{
+ URL_file *urlp = (URL_file *)url;
+
+ if(urlp->mapptr != NULL)
+ {
+ if(urlp->mapsize == urlp->pos)
+ return EOF;
+ return urlp->mapptr[urlp->pos++] & 0xff;
+ }
+
+#ifdef getc
+ return getc(urlp->fp);
+#else
+ return fgetc(urlp->fp);
+#endif /* getc */
+}
+
+static void url_file_close(URL url)
+{
+ URL_file *urlp = (URL_file *)url;
+
+ if(urlp->mapptr != NULL)
+ {
+#ifdef __W32__
+ HANDLE hFile = urlp->hFile;
+ HANDLE hMap = urlp->hMap;
+#endif /* __W32__ */
+ munmap(urlp->mapptr, urlp->mapsize);
+ }
+ if(urlp->fp != NULL)
+ {
+ if(urlp->fp == stdin)
+ rewind(stdin);
+ else
+ fclose(urlp->fp);
+ }
+ free(url);
+}
+
+static long url_file_seek(URL url, long offset, int whence)
+{
+ URL_file *urlp = (URL_file *)url;
+ long ret;
+
+ if(urlp->mapptr == NULL)
+ return fseek(urlp->fp, offset, whence);
+ ret = urlp->pos;
+ switch(whence)
+ {
+ case SEEK_SET:
+ urlp->pos = offset;
+ break;
+ case SEEK_CUR:
+ urlp->pos += offset;
+ break;
+ case SEEK_END:
+ urlp->pos = urlp->mapsize + offset;
+ break;
+ }
+ if(urlp->pos > urlp->mapsize)
+ urlp->pos = urlp->mapsize;
+ else if(urlp->pos < 0)
+ urlp->pos = 0;
+
+ return ret;
+}
+
+static long url_file_tell(URL url)
+{
+ URL_file *urlp = (URL_file *)url;
+
+ return urlp->mapptr ? urlp->pos : ftell(urlp->fp);
+}
diff --git a/lib/timidity/libarc/url_ftp.c b/lib/timidity/libarc/url_ftp.c
new file mode 100644
index 0000000000..45588014bd
--- /dev/null
+++ b/lib/timidity/libarc/url_ftp.c
@@ -0,0 +1,561 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <signal.h> /* for SIGALRM */
+
+#include "timidity.h"
+#include "url.h"
+#include "net.h"
+
+/* supported PASV mode only */
+
+#define ALARM_TIMEOUT 10
+static VOLATILE int timeout_flag = 0;
+
+#ifdef FTP_PROXY_HOST
+char *url_ftp_proxy_host = FTP_PROXY_HOST
+unsigned short url_ftp_proxy_port = FTP_PROXY_PORT
+#else
+char *url_ftp_proxy_host = NULL;
+unsigned short url_ftp_proxy_port;
+#endif /* FTP_PROXY_HOST */
+
+
+typedef struct _URL_ftp
+{
+ char common[sizeof(struct _URL)];
+ FILE *datafp;
+ FILE *ctlifp;
+ FILE *ctlofp;
+ int abor;
+} URL_ftp;
+
+static int name_ftp_check(char *url_string);
+static long url_ftp_read(URL url, void *buff, long size);
+static char *url_ftp_gets(URL url, char *buff, int n);
+static int url_ftp_fgetc(URL url);
+static void url_ftp_close(URL url);
+static int guess_errno(char *msg);
+
+struct URL_module URL_module_ftp =
+{
+ URL_ftp_t,
+ name_ftp_check,
+ NULL,
+ url_ftp_open,
+ NULL
+};
+
+static int name_ftp_check(char *s)
+{
+ if(strncmp(s, "ftp://", 6) == 0)
+ return 1;
+ return 0;
+}
+
+static int ftp_cmd(URL_ftp *url, char *buff, char *rspns)
+{
+#ifdef DEBUG
+ printf("FTP<%s", buff);
+#endif
+ errno = 0;
+ if(socket_fwrite(buff, (long)strlen(buff), url->ctlofp) <= 0)
+ {
+ url_ftp_close((URL)url);
+ if(errno)
+ url_errno = errno;
+ else
+ url_errno = errno = ENOENT;
+ return -1;
+ }
+ socket_fflush(url->ctlofp);
+ do
+ {
+ errno = 0;
+ if(socket_fgets(buff, BUFSIZ, url->ctlifp) == NULL)
+ {
+ url_ftp_close((URL)url);
+ if(errno)
+ url_errno = errno;
+ else
+ url_errno = errno = ENOENT;
+ return -1;
+ }
+#ifdef DEBUG
+ printf("FTP>%s", buff);
+#endif
+ if(strncmp(buff, rspns, 3) != 0)
+ {
+ url_ftp_close((URL)url);
+ url_errno = errno = guess_errno(buff);
+ return -1;
+ }
+ } while(buff[3] == '-');
+ return 0;
+}
+
+/*ARGSUSED*/
+static void timeout(int sig)
+{
+ timeout_flag = 1;
+}
+
+static int guess_errno(char *msg)
+{
+ if(strncmp(msg, "550", 3) != 0)
+ return ENOENT;
+ if((msg = strchr(msg, ':')) == NULL)
+ return ENOENT;
+ msg++;
+ if(*msg == ' ')
+ msg++;
+ if(strncmp(msg, "No such file or directory", 25) == 0)
+ return ENOENT;
+ if(strncmp(msg, "Permission denied", 17) == 0)
+ return EACCES;
+ if(strncmp(msg, "HTTP/1.0 500", 12) == 0) /* Proxy Error */
+ return ENOENT;
+ return ENOENT;
+}
+
+URL url_ftp_open(char *name)
+{
+ URL_ftp *url;
+ SOCKET fd;
+ char *p, *host, *path;
+ unsigned short port;
+ char buff[BUFSIZ];
+ char path_buff[1024], host_buff[1024];
+ int n;
+ char *passwd;
+ char *user;
+
+#ifdef DEBUG
+ printf("url_ftp_open(%s)\n", name);
+#endif /* DEBUG */
+
+ passwd = user_mailaddr;
+ user = "anonymous";
+
+ url = (URL_ftp *)alloc_url(sizeof(URL_ftp));
+ if(url == NULL)
+ {
+ url_errno = errno;
+ return NULL;
+ }
+
+ /* common members */
+ URLm(url, type) = URL_ftp_t;
+ URLm(url, url_read) = url_ftp_read;
+ URLm(url, url_gets) = url_ftp_gets;
+ URLm(url, url_fgetc) = url_ftp_fgetc;
+ URLm(url, url_seek) = NULL;
+ URLm(url, url_tell) = NULL;
+ URLm(url, url_close) = url_ftp_close;
+
+ /* private members */
+ url->datafp = NULL;
+ url->ctlifp = NULL;
+ url->ctlofp = NULL;
+ url->abor = 0;
+
+ if(url_ftp_proxy_host != NULL)
+ {
+ /* proxy */
+ host = url_ftp_proxy_host;
+ port = url_ftp_proxy_port;
+ }
+ else
+ {
+ /* not proxy */
+ if(strncmp(name, "ftp://", 6) == 0)
+ name += 6;
+ strncpy(buff, name, sizeof(buff));
+ buff[sizeof(buff) - 1] = '\0';
+
+ strncpy(host_buff, buff, sizeof(host_buff));
+ host_buff[sizeof(host_buff) - 1] = '\0';
+ host = host_buff;
+
+ if((p = strchr(host, '/')) == NULL)
+ {
+ url_ftp_close((URL)url);
+ url_errno = URLERR_IURLF;
+ errno = ENOENT;
+ return NULL;
+ }
+
+ port = 21;
+ *p = '\0';
+ strncpy(path_buff, name + strlen(host), sizeof(path_buff));
+ path_buff[sizeof(path_buff) - 1] = '\0';
+ path = path_buff;
+
+ /* check user:password@host */
+ p = strchr(host, '@');
+ if(p != NULL)
+ {
+ user = host;
+ host = p;
+ *host++ = '\0';
+ if((passwd = strchr(user, ':')) == NULL)
+ passwd = user_mailaddr;
+ else
+ *passwd++ = '\0';
+ }
+
+#ifdef DEBUG
+ printf("open(host=`%s', port=`%d')\n", host, port);
+#endif /* DEBUG */
+
+#ifdef __W32__
+ timeout_flag = 0;
+ fd = open_socket(host, port);
+#else
+ timeout_flag = 0;
+ signal(SIGALRM, timeout);
+ alarm(ALARM_TIMEOUT);
+ fd = open_socket(host, port);
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+#endif /* __W32__ */
+
+ if(fd < 0)
+ {
+ VOLATILE_TOUCH(timeout_flag);
+#ifdef ETIMEDOUT
+ if(timeout_flag)
+ errno = ETIMEDOUT;
+#endif /* ETIMEDOUT */
+
+ if(errno)
+ url_errno = errno;
+ else
+ {
+ url_errno = URLERR_CANTOPEN;
+ errno = ENOENT;
+ }
+ url_ftp_close((URL)url);
+ return NULL;
+ }
+
+ if((url->ctlifp = socket_fdopen(fd, "rb")) == NULL)
+ {
+ url_ftp_close((URL)url);
+ url_errno = errno;
+ return NULL;
+ }
+
+ if((url->ctlofp = socket_fdopen(fd, "wb")) == NULL)
+ {
+ url_ftp_close((URL)url);
+ url_errno = errno;
+ return NULL;
+ }
+
+ if(socket_fgets(buff, BUFSIZ, url->ctlifp) == NULL)
+ {
+ url_ftp_close((URL)url);
+ url_errno = URLERR_CANTOPEN;
+ errno = ENOENT;
+ return NULL;
+ }
+
+ if(strncmp(buff, "220 ", 4) != 0)
+ {
+ url_ftp_close((URL)url);
+ url_errno = URLERR_CANTOPEN;
+ errno = ENOENT;
+ return NULL;
+ }
+
+ /* login */
+ sprintf(buff, "USER %s\r\n", user);
+ if(ftp_cmd(url, buff, "331") < 0)
+ return NULL;
+
+ /* password */
+ if(passwd == NULL)
+ sprintf(buff, "PASS Unknown@liburl.a\r\n");
+ else
+ sprintf(buff, "PASS %s\r\n", passwd);
+ if(ftp_cmd(url, buff, "230") < 0)
+ return NULL;
+
+ /* CWD */
+ if(path[1] == '0')
+ /* Here is root */;
+ else
+ {
+ path++; /* skip '/' */
+ while((p = strchr(path, '/')) != NULL)
+ {
+ *p = '\0';
+ sprintf(buff, "CWD %s\r\n", path);
+ if(ftp_cmd(url, buff, "250") < 0)
+ return NULL;
+ path = p + 1;
+ }
+ if(!*path)
+ {
+ url_ftp_close((URL)url);
+ url_errno = URLERR_IURLF;
+ errno = ENOENT;
+ return NULL;
+ }
+ }
+
+ /* TYPE I */
+ strcpy(buff, "TYPE I\r\n");
+ if(ftp_cmd(url, buff, "200") < 0)
+ return NULL;
+
+ /* PASV */
+ strcpy(buff, "PASV\r\n");
+ if(ftp_cmd(url, buff, "227") < 0)
+ return NULL;
+
+ /* Parse PASV
+ * 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2)
+ */
+ p = buff + 4;
+
+ while(*p && (*p < '0' || *p > '9'))
+ p++;
+ if(*p == '\0')
+ {
+ url_ftp_close((URL)url);
+ url_errno = URLERR_CANTOPEN;
+ errno = ENOENT;
+ return NULL;
+ }
+ host = p;
+ n = 0; /* number of commas */
+ while(n < 4)
+ {
+ if((p = strchr(p, ',')) == NULL)
+ {
+ url_ftp_close((URL)url);
+ url_errno = URLERR_CANTOPEN;
+ errno = ENOENT;
+ return NULL;
+ }
+ *p = '.';
+ n++;
+ }
+ *p++ = '\0';
+
+ port = atoi(p) * 256;
+ if((p = strchr(p, ',')) == NULL)
+ {
+ url_ftp_close((URL)url);
+ url_errno = URLERR_CANTOPEN;
+ errno = ENOENT;
+ return NULL;
+ }
+ port += atoi(p + 1);
+
+ /* RETR */
+ socket_fwrite("RETR ", 5, url->ctlofp);
+ socket_fwrite(path, (long)strlen(path), url->ctlofp);
+ socket_fwrite("\r\n", 2, url->ctlofp);
+ socket_fflush(url->ctlofp);
+
+#ifdef DEBUG
+ printf("FTP>RETR %s\r\n", path);
+#endif /* DEBUG */
+ }
+
+ /* Open data connection. */
+#ifdef DEBUG
+ printf("open(host=`%s', port=`%d')\n", host, port);
+#endif /* DEBUG */
+
+ if((fd = open_socket(host, port)) < 0)
+ {
+ url_ftp_close((URL)url);
+ if(errno)
+ url_errno = errno;
+ else
+ url_errno = errno = ENOENT;
+ return NULL;
+ }
+ if((url->datafp = socket_fdopen(fd, "rb")) == NULL)
+ {
+ url_errno = errno;
+ closesocket(fd);
+ url_ftp_close((URL)url);
+ errno = url_errno;
+ return NULL;
+ }
+
+ if(url_ftp_proxy_host != NULL)
+ {
+ /* proxy */
+ sprintf(buff, "GET %s HTTP/1.0\r\n", name);
+ socket_write(fd, buff, (long)strlen(buff));
+#ifdef DEBUG
+ printf("FTP<%s", buff);
+#endif /* DEBUG */
+
+ if(url_user_agent)
+ {
+ sprintf(buff, "User-Agent: %s\r\n", url_user_agent);
+ socket_write(fd, buff, (long)strlen(buff));
+#ifdef DEBUG
+ printf("FTP<%s", buff);
+#endif /* DEBUG */
+ }
+ socket_write(fd, "\r\n", 2);
+ errno = 0;
+ if(socket_fgets(buff, BUFSIZ, url->datafp) == NULL)
+ {
+ if(errno == 0)
+ errno = ENOENT;
+ url_errno = errno;
+ url_ftp_close((URL)url);
+ return NULL;
+ }
+#ifdef DEBUG
+ printf("FTP>%s", buff);
+#endif /* DEBUG */
+
+ p = buff;
+ if(strncmp(p, "HTTP/1.0 ", 9) == 0 || strncmp(p, "HTTP/1.1 ", 9) == 0)
+ p += 9;
+ if(strncmp(p, "200", 3) != 0) /* Not success */
+ {
+ url_ftp_close((URL)url);
+ url_errno = errno = guess_errno(buff);
+ return NULL;
+ }
+
+ /* Skip mime header */
+ while(socket_fgets(buff, BUFSIZ, url->datafp) != NULL)
+ {
+ if(buff[0] == '\n' || (buff[0] == '\r' && buff[1] == '\n'))
+ break; /* end of heaer */
+#ifdef DEBUG
+ printf("FTP>%s", buff);
+#endif /* DEBUG */
+ }
+ }
+ else
+ {
+ /* not proxy */
+ if(socket_fgets(buff, BUFSIZ, url->ctlifp) == NULL)
+ {
+ url_ftp_close((URL)url);
+ url_errno = errno;
+ return NULL;
+ }
+
+#ifdef DEBUG
+ printf("FTP<%s", buff);
+#endif /* DEBUG */
+
+ if(strncmp(buff, "150", 3) != 0)
+ {
+ url_ftp_close((URL)url);
+ url_errno = errno = guess_errno(buff);
+ return NULL;
+ }
+ url->abor = 1;
+ }
+
+#ifdef __W32__
+ return url_buff_open((URL)url, 1);
+#else
+ return (URL)url;
+#endif /* __W32__ */
+}
+
+static long url_ftp_read(URL url, void *buff, long n)
+{
+ URL_ftp *urlp = (URL_ftp *)url;
+
+ n = socket_fread(buff, n, urlp->datafp);
+ if(n <= 0)
+ urlp->abor = 0;
+ return n;
+}
+
+static char *url_ftp_gets(URL url, char *buff, int n)
+{
+ URL_ftp *urlp = (URL_ftp *)url;
+
+ buff = socket_fgets(buff, n, urlp->datafp);
+ if(buff == NULL)
+ urlp->abor = 0;
+ return buff;
+}
+
+static int url_ftp_fgetc(URL url)
+{
+ URL_ftp *urlp = (URL_ftp *)url;
+ int n;
+ unsigned char c;
+
+ n = socket_fread(&c, 1, urlp->datafp);
+ if(n <= 0)
+ {
+ urlp->abor = 0;
+ if(errno)
+ url_errno = errno;
+ return EOF;
+ }
+ return (int)c;
+}
+
+static void url_ftp_close(URL url)
+{
+ URL_ftp *urlp = (URL_ftp *)url;
+ int save_errno = errno;
+
+ if(urlp->datafp != NULL)
+ socket_fclose(urlp->datafp);
+ else
+ urlp->abor = 0;
+ if(urlp->ctlofp != NULL)
+ {
+ if(urlp->abor)
+ socket_fwrite("ABOR\r\n", 6, urlp->ctlofp);
+ socket_fwrite("QUIT\r\n", 6, urlp->ctlofp);
+ socket_fflush(urlp->ctlofp);
+ socket_fclose(urlp->ctlofp);
+ }
+ if(urlp->ctlifp != NULL)
+ socket_fclose(urlp->ctlifp);
+ free(url);
+ errno = save_errno;
+}
diff --git a/lib/timidity/libarc/url_hqxdecode.c b/lib/timidity/libarc/url_hqxdecode.c
new file mode 100644
index 0000000000..c2f5a6b9ca
--- /dev/null
+++ b/lib/timidity/libarc/url_hqxdecode.c
@@ -0,0 +1,453 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "timidity.h"
+#include "url.h"
+
+#define DECODEBUFSIZ 255 /* Must be power of 3 */
+#define INFOBYTES 128
+
+typedef struct _URL_hqxdecode
+{
+ char common[sizeof(struct _URL)];
+ URL reader;
+ long rpos;
+ int beg, end, eof, eod;
+ unsigned char decodebuf[DECODEBUFSIZ];
+ long datalen, rsrclen, restlen;
+ int dsoff, rsoff, zoff;
+ int stage, dataonly, autoclose;
+} URL_hqxdecode;
+
+static long url_hqxdecode_read(URL url, void *buff, long n);
+static int url_hqxdecode_fgetc(URL url);
+static long url_hqxdecode_tell(URL url);
+static void url_hqxdecode_close(URL url);
+
+URL url_hqxdecode_open(URL reader, int dataonly, int autoclose)
+{
+ URL_hqxdecode *url;
+
+ url = (URL_hqxdecode *)alloc_url(sizeof(URL_hqxdecode));
+ if(url == NULL)
+ {
+ if(autoclose)
+ url_close(reader);
+ url_errno = errno;
+ return NULL;
+ }
+
+ /* common members */
+ URLm(url, type) = URL_hqxdecode_t;
+ URLm(url, url_read) = url_hqxdecode_read;
+ URLm(url, url_gets) = NULL;
+ URLm(url, url_fgetc) = url_hqxdecode_fgetc;
+ URLm(url, url_seek) = NULL;
+ URLm(url, url_tell) = url_hqxdecode_tell;
+ URLm(url, url_close) = url_hqxdecode_close;
+
+ /* private members */
+ url->reader = reader;
+ url->rpos = 0;
+ url->beg = 0;
+ url->end = 0;
+ url->eof = url->eod = 0;
+ memset(url->decodebuf, 0, sizeof(url->decodebuf));
+ url->datalen = -1;
+ url->rsrclen = -1;
+ url->restlen = 0;
+ url->stage = 0;
+ url->dataonly = dataonly;
+ url->autoclose = autoclose;
+
+ return (URL)url;
+}
+
+static int hqxgetchar(URL reader)
+{
+ int c;
+ static int hqx_decode_table[256] =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x00, 0x00,
+ 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x00,
+ 0x14, 0x15, EOF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+ 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x00,
+ 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x00,
+ 0x2c, 0x2d, 0x2e, 0x2f, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x00,
+ 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x00, 0x00,
+ 0x3d, 0x3e, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ do
+ {
+ if((c = url_getc(reader)) == EOF)
+ return EOF;
+ } while(c == '\r' || c == '\n');
+ return hqx_decode_table[c];
+}
+
+static int hqxdecode_chunk(URL url, unsigned char *p)
+{
+ int c1, c2, c3, c4;
+ int n;
+
+ n = 0;
+ if((c1 = hqxgetchar(url)) == EOF)
+ return 0;
+ if((c2 = hqxgetchar(url)) == EOF)
+ return 0;
+ p[n++] = ((c1 << 2) | ((c2 & 0x30) >> 4));
+ if((c3 = hqxgetchar(url)) == EOF)
+ return n;
+ p[n++] = (((c2 & 0xf) << 4) | ((c3 & 0x3c) >> 2));
+ if((c4 = hqxgetchar(url)) == EOF)
+ return n;
+ p[n++] = (((c3 & 0x03) << 6) | c4);
+ return n;
+}
+
+static uint32 convert_int32(unsigned char *p)
+{
+ return ((uint32)p[3]) |
+ (((uint32)p[2]) << 8) |
+ (((uint32)p[1]) << 16) |
+ (((uint32)p[0]) << 24);
+}
+
+static int hqxdecode_header(URL_hqxdecode *urlp)
+{
+ int i, n;
+ unsigned char *p, *q;
+ URL url;
+ int hlen, nlen;
+
+ n = 0;
+ p = urlp->decodebuf;
+ q = urlp->decodebuf + INFOBYTES;
+ url = urlp->reader;
+ while(n < DECODEBUFSIZ - INFOBYTES - 2)
+ {
+ i = hqxdecode_chunk(url, q + n);
+ n += i;
+ if(i != 3)
+ {
+ urlp->eod = 1;
+ break;
+ }
+ }
+
+ memset(p, 0, INFOBYTES);
+ nlen = q[0];
+ hlen = nlen + 22;
+
+ if(n < hlen)
+ {
+ urlp->eof = 1;
+ return -1; /* Error */
+ }
+
+ urlp->datalen = (long)convert_int32(q + hlen - 10);
+ urlp->rsrclen = (long)convert_int32(q + hlen - 6);
+ urlp->dsoff = (((urlp->datalen + 127) >> 7) << 7) - urlp->datalen;
+ urlp->rsoff = (((urlp->rsrclen + 127) >> 7) << 7) - urlp->rsrclen;
+ urlp->zoff = 0;
+
+ p[1] = nlen;
+ memcpy(p + 2, q + 1, nlen);
+ memcpy(p + 65, q + hlen - 20, 4+4+2); /* type, author, flags */
+ memcpy(p + 83, q + hlen - 10, 4+4); /* datalen, rsrclen */
+ /* 91: create time (4) */
+ /* 95: modify time (4) */
+
+ q += hlen;
+ n -= hlen;
+ for(i = 0; i < n; i++)
+ p[INFOBYTES + i] = q[i];
+ return INFOBYTES + n;
+}
+
+static int hqxdecode(URL_hqxdecode *urlp)
+{
+ int i, n;
+ unsigned char *p;
+ URL url;
+
+ if(urlp->eod)
+ {
+ urlp->eof = 1;
+ return 1;
+ }
+
+ if(urlp->stage == 0)
+ {
+ n = hqxdecode_header(urlp);
+ if(n == -1)
+ return 1;
+ urlp->end = n;
+
+ if(urlp->dataonly)
+ {
+ urlp->beg = INFOBYTES;
+ urlp->restlen = urlp->datalen;
+ }
+ else
+ {
+ urlp->beg = 0;
+ urlp->restlen = urlp->datalen + INFOBYTES;
+ }
+
+ urlp->stage = 1;
+ return 0;
+ }
+
+ p = urlp->decodebuf;
+ url = urlp->reader;
+ n = 0;
+
+ if(urlp->restlen == 0)
+ {
+ if(urlp->dataonly)
+ {
+ urlp->eof = 1;
+ return 1;
+ }
+
+ if(urlp->stage == 2)
+ {
+ urlp->zoff = urlp->rsoff;
+ urlp->eof = 1;
+ return 1;
+ }
+
+ urlp->zoff = urlp->dsoff;
+ urlp->stage = 2;
+
+ n = urlp->end - urlp->beg;
+ if(n <= 2)
+ {
+ for(i = 0; i < n; i++)
+ p[i] = p[i + urlp->beg];
+ n += hqxdecode_chunk(url, p + n);
+ if(n <= 2)
+ {
+ urlp->eof = 1;
+ return 1;
+ }
+ urlp->rpos += urlp->beg;
+ urlp->beg = 0;
+ urlp->end = n;
+ }
+ urlp->restlen = urlp->rsrclen;
+
+ /* skip 2 byte (crc) */
+ urlp->beg += 2;
+ urlp->rpos -= 2;
+
+ n = urlp->beg;
+ }
+
+ while(n < DECODEBUFSIZ)
+ {
+ i = hqxdecode_chunk(url, p + n);
+ n += i;
+ if(i != 3)
+ {
+ urlp->eod = 1;
+ break;
+ }
+ }
+
+ urlp->rpos += urlp->beg;
+ urlp->beg = 0;
+ urlp->end = n;
+
+ if(n == 0)
+ {
+ urlp->eof = 1;
+ return 1;
+ }
+
+ return 0;
+}
+
+static long url_hqxdecode_read(URL url, void *buff, long size)
+{
+ URL_hqxdecode *urlp = (URL_hqxdecode *)url;
+ char *p = (char *)buff;
+ long n;
+ int i;
+
+ n = 0;
+ while(n < size)
+ {
+ if(urlp->zoff > 0)
+ {
+ i = urlp->zoff;
+ if(i > size - n)
+ i = size - n;
+ memset(p + n, 0, i);
+ urlp->zoff -= i;
+ urlp->rpos += i;
+ n += i;
+ continue;
+ }
+
+ if(urlp->eof)
+ break;
+
+ if(urlp->restlen == 0 || urlp->beg == urlp->end)
+ {
+ hqxdecode(urlp);
+ continue;
+ }
+
+ i = urlp->end - urlp->beg;
+ if(i > urlp->restlen)
+ i = urlp->restlen;
+ if(i > size - n)
+ i = size - n;
+ memcpy(p + n, urlp->decodebuf + urlp->beg, i);
+ urlp->beg += i;
+ n += i;
+ urlp->restlen -= i;
+ }
+
+ return n;
+}
+
+static int url_hqxdecode_fgetc(URL url)
+{
+ URL_hqxdecode *urlp = (URL_hqxdecode *)url;
+ int c;
+
+ retry_read:
+ if(urlp->zoff > 0)
+ {
+ urlp->zoff--;
+ urlp->rpos++;
+ return 0;
+ }
+
+ if(urlp->eof)
+ return EOF;
+
+ if(urlp->restlen == 0 || urlp->beg == urlp->end)
+ {
+ hqxdecode(urlp);
+ goto retry_read;
+ }
+
+ c = (int)urlp->decodebuf[urlp->beg++];
+ urlp->restlen--;
+
+ return c;
+}
+
+static long url_hqxdecode_tell(URL url)
+{
+ URL_hqxdecode *urlp = (URL_hqxdecode *)url;
+
+ if(urlp->dataonly)
+ return urlp->rpos + urlp->beg - INFOBYTES;
+ return urlp->rpos + urlp->beg;
+}
+
+static void url_hqxdecode_close(URL url)
+{
+ URL_hqxdecode *urlp = (URL_hqxdecode *)url;
+
+ if(urlp->autoclose)
+ url_close(urlp->reader);
+ free(url);
+}
+
+#ifdef HQXDECODE_MAIN
+void main(int argc, char** argv)
+{
+ URL hqxdecoder;
+ char buff[256], *filename;
+ int c;
+
+ if(argc != 2)
+ {
+ fprintf(stderr, "Usage: %s hqx-filename\n", argv[0]);
+ exit(1);
+ }
+ filename = argv[1];
+
+ if((hqxdecoder = url_file_open(filename)) == NULL)
+ {
+ perror(argv[1]);
+ exit(1);
+ }
+
+ for(;;)
+ {
+ if(url_readline(hqxdecoder, buff, sizeof(buff)) == NULL)
+ {
+ fprintf(stderr, "%s: Not a hqx-file\n", filename);
+ url_close(hqxdecoder);
+ exit(1);
+ }
+ if((strncmp(buff, "(This file", 10) == 0) ||
+ (strncmp(buff, "(Convert with", 13) == 0))
+ break;
+ }
+
+ while((c = url_getc(hqxdecoder)) != EOF)
+ if(c == ':')
+ break;
+ if(c == EOF)
+ {
+ fprintf(stderr, "%s: Not a hqx-file\n", filename);
+ url_close(hqxdecoder);
+ exit(1);
+ }
+
+ hqxdecoder = url_hqxdecode_open(hqxdecoder, 0, 1);
+#if HQXDECODE_MAIN
+ while((c = url_getc(hqxdecoder)) != EOF)
+ putchar(c);
+#else
+ while((c = url_read(hqxdecoder, buff, sizeof(buff))) > 0)
+ write(1, buff, c);
+#endif
+ url_close(hqxdecoder);
+ exit(0);
+}
+
+#endif /* HQXDECODE_MAIN */
diff --git a/lib/timidity/libarc/url_http.c b/lib/timidity/libarc/url_http.c
new file mode 100644
index 0000000000..28c79d1c7b
--- /dev/null
+++ b/lib/timidity/libarc/url_http.c
@@ -0,0 +1,342 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include <signal.h> /* for SIGALRM */
+
+#include "timidity.h"
+#include "url.h"
+#include "net.h"
+
+/* #define DEBUG */
+
+#ifdef HTTP_PROXY_HOST
+char *url_http_proxy_host = HTTP_PROXY_HOST;
+unsigned short url_http_proxy_port = HTTP_PROXY_PORT;
+#else
+char *url_http_proxy_host = NULL;
+unsigned short url_http_proxy_port;
+#endif /* HTTP_PROXY_HOST */
+
+
+#define REQUEST_OFFSET 16
+
+#define ALARM_TIMEOUT 10
+static VOLATILE int timeout_flag = 1;
+
+
+typedef struct _URL_http
+{
+ char common[sizeof(struct _URL)];
+
+ FILE *fp;
+} URL_http;
+
+static int name_http_check(char *url_string);
+static long url_http_read(URL url, void *buff, long n);
+static char *url_http_gets(URL url, char *buff, int n);
+static int url_http_fgetc(URL url);
+static void url_http_close(URL url);
+
+struct URL_module URL_module_http =
+{
+ URL_http_t,
+ name_http_check,
+ NULL,
+ url_http_open,
+ NULL
+};
+
+static int name_http_check(char *s)
+{
+ if(strncmp(s, "http://", 7) == 0)
+ return 1;
+ return 0;
+}
+
+/*ARGSUSED*/
+static void timeout(int sig)
+{
+ timeout_flag = 1;
+}
+
+URL url_http_open(char *name)
+{
+ URL_http *url;
+ SOCKET fd;
+ char *host, *path = NULL, *p;
+ unsigned short port;
+ char buff[BUFSIZ];
+ char wwwserver[256];
+ int n;
+
+#ifdef DEBUG
+ printf("url_http_open(%s)\n", name);
+#endif /* DEBUG */
+
+ url = (URL_http *)alloc_url(sizeof(URL_http));
+ if(url == NULL)
+ {
+ url_errno = errno;
+ return NULL;
+ }
+
+ /* common members */
+ URLm(url, type) = URL_http_t;
+ URLm(url, url_read) = url_http_read;
+ URLm(url, url_gets) = url_http_gets;
+ URLm(url, url_fgetc) = url_http_fgetc;
+ URLm(url, url_seek) = NULL;
+ URLm(url, url_tell) = NULL;
+ URLm(url, url_close) = url_http_close;
+
+ /* private members */
+ url->fp = NULL;
+
+ if(url_http_proxy_host)
+ {
+ char *q;
+ int len;
+
+ host = url_http_proxy_host;
+ port = url_http_proxy_port;
+
+ p = name;
+ if(strncmp(p, "http://", 7) == 0)
+ p += 7;
+ for(q = p; *q && *q != ':' && *q != '/'; q++)
+ ;
+ len = q - p;
+ if(len >= sizeof(wwwserver) - 1) { /* What?? */
+ strcpy(wwwserver, "localhost");
+ } else {
+ strncpy(wwwserver, p, len);
+ }
+ }
+ else
+ {
+ if(strncmp(name, "http://", 7) == 0)
+ name += 7;
+ n = strlen(name);
+ if(n + REQUEST_OFFSET >= BUFSIZ)
+ {
+ url_http_close((URL)url);
+ url_errno = URLERR_URLTOOLONG;
+ errno = ENOENT;
+ return NULL;
+ }
+
+ memcpy(buff, name, n + 1);
+
+ host = buff;
+ for(p = host; *p && *p != ':' && *p != '/'; p++)
+ ;
+ if(*p == ':')
+ {
+ char *pp;
+
+ *p++ = '\0'; /* terminate `host' string */
+ port = atoi(p);
+ pp = strchr(p, '/');
+ if(pp == NULL)
+ p[0] = '\0';
+ else
+ p = pp;
+ }
+ else
+ port = 80;
+ path = p;
+
+ if(*path == '\0')
+ *(path + 1) = '\0';
+
+ *path = '\0'; /* terminate `host' string */
+ strncpy(wwwserver, host, sizeof(wwwserver));
+ }
+
+#ifdef DEBUG
+ printf("open(host=`%s', port=`%d')\n", host, port);
+#endif /* DEBUG */
+
+#ifdef __W32__
+ timeout_flag = 0;
+ fd = open_socket(host, port);
+#else
+ timeout_flag = 0;
+ signal(SIGALRM, timeout);
+ alarm(ALARM_TIMEOUT);
+ fd = open_socket(host, port);
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+#endif /* __W32__ */
+
+ if(fd == (SOCKET)-1)
+ {
+ VOLATILE_TOUCH(timeout_flag);
+#ifdef ETIMEDOUT
+ if(timeout_flag)
+ errno = ETIMEDOUT;
+#endif /* ETIMEDOUT */
+ if(errno)
+ url_errno = errno;
+ else
+ {
+ url_errno = URLERR_CANTOPEN;
+ errno = ENOENT;
+ }
+ url_http_close((URL)url);
+ return NULL;
+ }
+
+ if((url->fp = socket_fdopen(fd, "rb")) == NULL)
+ {
+ url_errno = errno;
+ closesocket(fd);
+ url_http_close((URL)url);
+ errno = url_errno;
+ return NULL;
+ }
+
+ if(url_http_proxy_host)
+ sprintf(buff, "GET %s HTTP/1.0\r\n", name);
+ else
+ {
+ *path = '/';
+ sprintf(buff, "GET %s HTTP/1.0\r\n", path);
+ }
+ socket_write(fd, buff, (long)strlen(buff));
+
+#ifdef DEBUG
+ printf("HTTP<%s", buff);
+#endif /* DEBUG */
+
+ if(url_user_agent)
+ {
+ sprintf(buff, "User-Agent: %s\r\n", url_user_agent);
+ socket_write(fd, buff, (long)strlen(buff));
+#ifdef DEBUG
+ printf("HTTP<%s", buff);
+#endif /* DEBUG */
+ }
+
+ /* Host field */
+ sprintf(buff, "Host: %s\r\n", wwwserver);
+ socket_write(fd, buff, (long)strlen(buff));
+#ifdef DEBUG
+ printf("HTTP<%s", buff);
+#endif /* DEBUG */
+
+ /* End of header */
+ socket_write(fd, "\r\n", 2);
+ socket_shutdown(fd, 1);
+
+ if(socket_fgets(buff, BUFSIZ, url->fp) == NULL)
+ {
+ if(errno)
+ url_errno = errno;
+ else
+ {
+ url_errno = URLERR_CANTOPEN;
+ errno = ENOENT;
+ }
+ url_http_close((URL)url);
+ return NULL;
+ }
+
+#ifdef DEBUG
+ printf("HTTP>%s", buff);
+#endif /* DEBUG */
+
+ p = buff;
+ if(strncmp(p, "HTTP/1.0 ", 9) == 0 || strncmp(p, "HTTP/1.1 ", 9) == 0)
+ p += 9;
+ if(strncmp(p, "200", 3) != 0) /* Not success */
+ {
+ url_http_close((URL)url);
+ url_errno = errno = ENOENT;
+ return NULL;
+ }
+
+ /* Skip mime header */
+ while(socket_fgets(buff, BUFSIZ, url->fp) != NULL)
+ {
+ if(buff[0] == '\n' || (buff[0] == '\r' && buff[1] == '\n'))
+ break; /* end of heaer */
+#ifdef DEBUG
+ printf("HTTP>%s", buff);
+#endif /* DEBUG */
+ }
+
+#ifdef __W32__
+ return url_buff_open((URL)url, 1);
+#else
+ return (URL)url;
+#endif /* __W32__ */
+}
+
+static void url_http_close(URL url)
+{
+ URL_http *urlp = (URL_http *)url;
+ int save_errno = errno;
+ if(urlp->fp != NULL)
+ socket_fclose(urlp->fp);
+ free(url);
+ errno = save_errno;
+}
+
+static long url_http_read(URL url, void *buff, long n)
+{
+ URL_http *urlp = (URL_http *)url;
+ return socket_fread(buff, n, urlp->fp);
+}
+
+static char *url_http_gets(URL url, char *buff, int n)
+{
+ URL_http *urlp = (URL_http *)url;
+ return socket_fgets(buff, n, urlp->fp);
+}
+
+static int url_http_fgetc(URL url)
+{
+ URL_http *urlp = (URL_http *)url;
+ int n;
+ unsigned char c;
+
+ n = socket_fread(&c, 1, urlp->fp);
+ if(n <= 0)
+ {
+ if(errno)
+ url_errno = errno;
+ return EOF;
+ }
+ return (int)c;
+}
diff --git a/lib/timidity/libarc/url_inflate.c b/lib/timidity/libarc/url_inflate.c
new file mode 100644
index 0000000000..4160af041d
--- /dev/null
+++ b/lib/timidity/libarc/url_inflate.c
@@ -0,0 +1,135 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#include "timidity.h"
+#include "url.h"
+#include "mblock.h"
+#include "zip.h"
+
+typedef struct _URL_inflate
+{
+ char common[sizeof(struct _URL)];
+ InflateHandler decoder;
+ URL instream;
+ long compsize;
+ long pos;
+ int autoclose;
+} URL_inflate;
+
+static long url_inflate_read_func(char *buf, long size, void *v);
+static long url_inflate_read(URL url, void *buff, long n);
+static long url_inflate_tell(URL url);
+static void url_inflate_close(URL url);
+
+URL url_inflate_open(URL instream, long compsize, int autoclose)
+{
+ URL_inflate *url;
+
+ url = (URL_inflate *)alloc_url(sizeof(URL_inflate));
+ if(url == NULL)
+ {
+ if(autoclose)
+ url_close(instream);
+ url_errno = errno;
+ return NULL;
+ }
+
+ /* common members */
+ URLm(url, type) = URL_inflate_t;
+ URLm(url, url_read) = url_inflate_read;
+ URLm(url, url_gets) = NULL;
+ URLm(url, url_fgetc) = NULL;
+ URLm(url, url_seek) = NULL;
+ URLm(url, url_tell) = url_inflate_tell;
+ URLm(url, url_close) = url_inflate_close;
+
+ /* private members */
+ url->decoder = NULL;
+ url->instream = instream;
+ url->pos = 0;
+ url->compsize = compsize;
+ url->autoclose = autoclose;
+
+ errno = 0;
+ url->decoder = open_inflate_handler(url_inflate_read_func, url);
+ if(url->decoder == NULL)
+ {
+ if(autoclose)
+ url_close(instream);
+ url_inflate_close((URL)url);
+ url_errno = errno;
+ return NULL;
+ }
+
+ return (URL)url;
+}
+
+static long url_inflate_read_func(char *buf, long size, void *v)
+{
+ URL_inflate *urlp = (URL_inflate *)v;
+ long n;
+
+ if(urlp->compsize == -1) /* size if unknown */
+ return url_read(urlp->instream, buf, size);
+
+ if(urlp->compsize == 0)
+ return 0;
+ n = size;
+ if(n > urlp->compsize)
+ n = urlp->compsize;
+ n = url_read(urlp->instream, buf, n);
+ if(n == -1)
+ return -1;
+ urlp->compsize -= n;
+ return n;
+}
+
+static long url_inflate_read(URL url, void *buff, long n)
+{
+ URL_inflate *urlp = (URL_inflate *)url;
+
+ n = zip_inflate(urlp->decoder, (char *)buff, n);
+ if(n <= 0)
+ return n;
+ urlp->pos += n;
+ return n;
+}
+
+static long url_inflate_tell(URL url)
+{
+ return ((URL_inflate *)url)->pos;
+}
+
+static void url_inflate_close(URL url)
+{
+ int save_errno = errno;
+ URL_inflate *urlp = (URL_inflate *)url;
+ if(urlp->decoder)
+ close_inflate_handler(urlp->decoder);
+ if(urlp->autoclose)
+ url_close(urlp->instream);
+ free(url);
+ errno = save_errno;
+}
diff --git a/lib/timidity/libarc/url_mem.c b/lib/timidity/libarc/url_mem.c
new file mode 100644
index 0000000000..6d0b1296eb
--- /dev/null
+++ b/lib/timidity/libarc/url_mem.c
@@ -0,0 +1,180 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include "timidity.h"
+#include "url.h"
+
+typedef struct _URL_mem
+{
+ char common[sizeof(struct _URL)];
+ char *memory;
+ long memsiz;
+ long mempos;
+ int autofree;
+} URL_mem;
+
+static long url_mem_read(URL url, void *buff, long n);
+static char *url_mem_gets(URL url, char *buff, int n);
+static int url_mem_fgetc(URL url);
+static long url_mem_seek(URL url, long offset, int whence);
+static long url_mem_tell(URL url);
+static void url_mem_close(URL url);
+
+URL url_mem_open(char *memory, long memsiz, int autofree)
+{
+ URL_mem *url;
+
+ url = (URL_mem *)alloc_url(sizeof(URL_mem));
+ if(url == NULL)
+ {
+ url_errno = errno;
+ if(autofree)
+ {
+ free(memory);
+ errno = url_errno;
+ }
+ return NULL;
+ }
+
+ /* common members */
+ URLm(url, type) = URL_mem_t;
+ URLm(url, url_read) = url_mem_read;
+ URLm(url, url_gets) = url_mem_gets;
+ URLm(url, url_fgetc) = url_mem_fgetc;
+ URLm(url, url_seek) = url_mem_seek;
+ URLm(url, url_tell) = url_mem_tell;
+ URLm(url, url_close) = url_mem_close;
+
+ /* private members */
+ url->memory = memory;
+ url->memsiz = memsiz;
+ url->mempos = 0;
+ url->autofree = autofree;
+
+ return (URL)url;
+}
+
+static long url_mem_read(URL url, void *buff, long n)
+{
+ URL_mem *urlp = (URL_mem *)url;
+ long s;
+ char *p = (char *)buff;
+
+ s = urlp->memsiz - urlp->mempos;
+ if(s > n)
+ s = n;
+ if(s <= 0)
+ return 0;
+ memcpy(p, urlp->memory + urlp->mempos, s);
+ urlp->mempos += s;
+ return s;
+}
+
+static char *url_mem_gets(URL url, char *buff, int n)
+{
+ URL_mem *urlp = (URL_mem *)url;
+ long s;
+ char *nlp, *p;
+
+ if(urlp->memsiz == urlp->mempos)
+ return NULL;
+ if(n <= 0)
+ return buff;
+ if(n == 1)
+ {
+ *buff = '\0';
+ return buff;
+ }
+ n--; /* for '\0' */
+ s = urlp->memsiz - urlp->mempos;
+ if(s > n)
+ s = n;
+ p = urlp->memory + urlp->mempos;
+ nlp = (char *)memchr(p, url_newline_code, s);
+ if(nlp != NULL)
+ s = nlp - p + 1;
+ memcpy(buff, p, s);
+ buff[s] = '\0';
+ urlp->mempos += s;
+ return buff;
+}
+
+static int url_mem_fgetc(URL url)
+{
+ URL_mem *urlp = (URL_mem *)url;
+
+ if(urlp->memsiz == urlp->mempos)
+ return EOF;
+ return (int)(unsigned char)urlp->memory[urlp->mempos++];
+}
+
+static long url_mem_seek(URL url, long offset, int whence)
+{
+ URL_mem *urlp = (URL_mem *)url;
+ long ret;
+
+ ret = urlp->mempos;
+ switch(whence)
+ {
+ case SEEK_SET:
+ urlp->mempos = offset;
+ break;
+ case SEEK_CUR:
+ urlp->mempos += offset;
+ break;
+ case SEEK_END:
+ urlp->mempos = urlp->memsiz + offset;
+ break;
+ }
+ if(urlp->mempos > urlp->memsiz)
+ urlp->mempos = urlp->memsiz;
+ else if(urlp->mempos < 0)
+ urlp->mempos = 0;
+
+ return ret;
+}
+
+static long url_mem_tell(URL url)
+{
+ return ((URL_mem *)url)->mempos;
+}
+
+static void url_mem_close(URL url)
+{
+ int save_errno = errno;
+ URL_mem *urlp = (URL_mem *)url;
+ if(urlp->autofree)
+ free(urlp->memory);
+ free(url);
+ errno = save_errno;
+}
diff --git a/lib/timidity/libarc/url_news.c b/lib/timidity/libarc/url_news.c
new file mode 100644
index 0000000000..1432d41fcb
--- /dev/null
+++ b/lib/timidity/libarc/url_news.c
@@ -0,0 +1,494 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include <signal.h> /* for SIGALRM */
+
+#include "timidity.h"
+#include "common.h"
+#include "url.h"
+#include "net.h"
+
+typedef struct _NewsConnection
+{
+ char *host;
+ unsigned short port;
+ FILE *fp;
+ SOCKET fd;
+ struct _NewsConnection *next;
+ int status; /* -1, 0, 1 */
+} NewsConnection;
+
+#define NNTP_OK_ID '2'
+#define ALARM_TIMEOUT 10
+/* #define DEBUG */
+
+static VOLATILE int timeout_flag = 1;
+static NewsConnection *connection_cache;
+static int connection_cache_flag = URL_NEWS_CONN_NO_CACHE;
+
+typedef struct _URL_news
+{
+ char common[sizeof(struct _URL)];
+
+ NewsConnection *news;
+ int status; /* for detection '\r?\n.\r?\n'
+ * 1 2 34 5
+ */
+ int eof;
+} URL_news;
+
+enum
+{
+ ARTICLE_STATUS_0,
+ ARTICLE_STATUS_1,
+ ARTICLE_STATUS_2,
+ ARTICLE_STATUS_3,
+ ARTICLE_STATUS_4
+};
+
+static int name_news_check(char *url_string);
+static long url_news_read(URL url, void *buff, long n);
+static int url_news_fgetc(URL url);
+static void url_news_close(URL url);
+
+struct URL_module URL_module_news =
+{
+ URL_news_t,
+ name_news_check,
+ NULL,
+ url_news_open,
+ NULL
+};
+
+static int name_news_check(char *s)
+{
+ if(strncmp(s, "news://", 7) == 0 && strchr(s, '@') != NULL)
+ return 1;
+ return 0;
+}
+
+/*ARGSUSED*/
+static void timeout(int sig)
+{
+ timeout_flag = 1;
+}
+
+static void close_news_server(NewsConnection *news)
+{
+ if(news->fd != (SOCKET)-1)
+ {
+ socket_write(news->fd, "QUIT\r\n", 6);
+ closesocket(news->fd);
+ }
+ if(news->fp != NULL)
+ socket_fclose(news->fp);
+ free(news->host);
+ news->status = -1;
+}
+
+static NewsConnection *open_news_server(char *host, unsigned short port)
+{
+ NewsConnection *p;
+ char buff[512];
+
+ for(p = connection_cache; p != NULL; p = p->next)
+ {
+ if(p->status == 0 && strcmp(p->host, host) == 0 && p->port == port)
+ {
+ p->status = 1;
+ return p;
+ }
+ }
+ for(p = connection_cache; p != NULL; p = p->next)
+ if(p->status == -1)
+ break;
+ if(p == NULL)
+ {
+ if((p = (NewsConnection *)safe_malloc(sizeof(NewsConnection))) == NULL)
+ return NULL;
+ p->next = connection_cache;
+ connection_cache = p;
+ p->status = -1;
+ }
+
+ if((p->host = safe_strdup(host)) == NULL)
+ return NULL;
+ p->port = port;
+
+#ifdef __W32__
+ timeout_flag = 0;
+ p->fd = open_socket(host, port);
+#else
+ timeout_flag = 0;
+ signal(SIGALRM, timeout);
+ alarm(ALARM_TIMEOUT);
+ p->fd = open_socket(host, port);
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+#endif /* __W32__ */
+
+ if(p->fd == (SOCKET)-1)
+ {
+ int save_errno;
+
+ VOLATILE_TOUCH(timeout_flag);
+#ifdef ETIMEDOUT
+ if(timeout_flag)
+ errno = ETIMEDOUT;
+#endif /* ETIMEDOUT */
+ if(errno)
+ url_errno = errno;
+ else
+ {
+ url_errno = URLERR_CANTOPEN;
+ errno = ENOENT;
+ }
+#ifdef DEBUG
+ perror(host);
+#endif /* DEBUG */
+
+ save_errno = errno;
+ free(p->host);
+ errno = save_errno;
+
+ return NULL;
+ }
+
+ if((p->fp = socket_fdopen(p->fd, "rb")) == NULL)
+ {
+ url_errno = errno;
+ closesocket(p->fd);
+ free(p->host);
+ errno = url_errno;
+ return NULL;
+ }
+
+ buff[0] = '\0';
+ if(socket_fgets(buff, sizeof(buff), p->fp) == NULL)
+ {
+ url_errno = errno;
+ closesocket(p->fd);
+ socket_fclose(p->fp);
+ free(p->host);
+ errno = url_errno;
+ return NULL;
+ }
+
+#ifdef DEBUG
+ printf("Connect status: %s", buff);
+#endif /* DEBUG */
+
+ if(buff[0] != NNTP_OK_ID)
+ {
+ closesocket(p->fd);
+ socket_fclose(p->fp);
+ free(p->host);
+ url_errno = URLERR_CANTOPEN;
+ errno = ENOENT;
+ return NULL;
+ }
+ p->status = 1;
+ return p;
+}
+
+int url_news_connection_cache(int flag)
+{
+ NewsConnection *p;
+ int oldflag;
+
+ oldflag = connection_cache_flag;
+
+ switch(flag)
+ {
+ case URL_NEWS_CONN_NO_CACHE:
+ case URL_NEWS_CONN_CACHE:
+ connection_cache_flag = flag;
+ break;
+ case URL_NEWS_CLOSE_CACHE:
+ for(p = connection_cache; p != NULL; p = p->next)
+ if(p->status == 0)
+ close_news_server(p);
+ break;
+ case URL_NEWS_GET_FLAG:
+ break;
+ }
+ return oldflag;
+}
+
+URL url_news_open(char *name)
+{
+ URL_news *url;
+ char *host, *p;
+ unsigned short port;
+ char buff[BUFSIZ], messageID[256];
+ int check_timeout;
+ int i;
+
+#ifdef DEBUG
+ printf("url_news_open(%s)\n", name);
+#endif /* DEBUG */
+
+ url = (URL_news *)alloc_url(sizeof(URL_news));
+ if(url == NULL)
+ {
+ url_errno = errno;
+ return NULL;
+ }
+
+ /* common members */
+ URLm(url, type) = URL_news_t;
+ URLm(url, url_read) = url_news_read;
+ URLm(url, url_gets) = NULL;
+ URLm(url, url_fgetc) = url_news_fgetc;
+ URLm(url, url_seek) = NULL;
+ URLm(url, url_tell) = NULL;
+ URLm(url, url_close) = url_news_close;
+
+ /* private members */
+ url->news = NULL;
+ url->status = ARTICLE_STATUS_2;
+ url->eof = 0;
+
+ if(strncmp(name, "news://", 7) == 0)
+ name += 7;
+
+ strncpy(buff, name, sizeof(buff) - 1);
+ buff[sizeof(buff) - 1] = '\0';
+
+ host = buff;
+ for(p = host; *p && *p != ':' && *p != '/'; p++)
+ ;
+ if(*p == ':')
+ {
+ *p++ = '\0'; /* terminate `host' string */
+ port = atoi(p);
+ p = strchr(p, '/');
+ if(p == NULL)
+ {
+ url_errno = URLERR_CANTOPEN;
+ errno = ENOENT;
+ url_news_close((URL)url);
+ return NULL;
+ }
+ }
+ else
+ port = 119;
+ *p++ = '\0'; /* terminate `host' string */
+ if(*p == '<')
+ p++;
+ strncpy(messageID, p, sizeof(messageID) - 1);
+ messageID[sizeof(messageID) - 1] = '\0';
+ i = strlen(messageID);
+ if(i > 0 && messageID[i - 1] == '>')
+ messageID[i - 1] = '\0';
+
+#ifdef DEBUG
+ printf("messageID: <%s>\n", messageID);
+#endif /* DEBUG */
+
+#ifdef DEBUG
+ printf("open(host=`%s', port=`%d')\n", host, port);
+#endif /* DEBUG */
+
+ if((url->news = open_news_server(host, port)) == NULL)
+ {
+ url_news_close((URL)url);
+ return NULL;
+ }
+
+ check_timeout = 1;
+ retry_article:
+
+ sprintf(buff, "ARTICLE <%s>\r\n", messageID);
+
+#ifdef DEBUG
+ printf("CMD> %s", buff);
+#endif /* DEBUG */
+
+ socket_write(url->news->fd, buff, (long)strlen(buff));
+ buff[0] = '\0';
+ if(socket_fgets(buff, sizeof(buff), url->news->fp) == NULL)
+ {
+ if(check_timeout)
+ {
+ check_timeout = 0;
+ close_news_server(url->news);
+ if((url->news = open_news_server(host, port)) != NULL)
+ goto retry_article;
+ }
+ url_news_close((URL)url);
+ url_errno = URLERR_CANTOPEN;
+ errno = ENOENT;
+ return NULL;
+ }
+
+#ifdef DEBUG
+ printf("CMD< %s", buff);
+#endif /* DEBUG */
+
+ if(buff[0] != NNTP_OK_ID)
+ {
+ if(check_timeout && strncmp(buff, "503", 3) == 0)
+ {
+ check_timeout = 0;
+ close_news_server(url->news);
+ if((url->news = open_news_server(host, port)) != NULL)
+ goto retry_article;
+ }
+ url_news_close((URL)url);
+ url_errno = errno = ENOENT;
+ return NULL;
+ }
+ return (URL)url;
+}
+
+static void url_news_close(URL url)
+{
+ URL_news *urlp = (URL_news *)url;
+ NewsConnection *news = urlp->news;
+ int save_errno = errno;
+
+ if(news != NULL)
+ {
+ if(connection_cache_flag == URL_NEWS_CONN_CACHE)
+ news->status = 0;
+ else
+ close_news_server(news);
+ }
+ free(url);
+
+ errno = save_errno;
+}
+
+static long url_news_read(URL url, void *buff, long size)
+{
+ char *p = (char *)buff;
+ long n;
+ int c;
+
+ n = 0;
+ while(n < size)
+ {
+ if((c = url_news_fgetc(url)) == EOF)
+ break;
+ p[n++] = c;
+ }
+ return n;
+}
+
+static int url_news_fgetc(URL url)
+{
+ URL_news *urlp = (URL_news *)url;
+ NewsConnection *news = urlp->news;
+ int c;
+
+ if(urlp->eof)
+ return EOF;
+ if((c = socket_fgetc(news->fp)) == EOF)
+ {
+ urlp->eof = 1;
+ return EOF;
+ }
+
+ switch(urlp->status)
+ {
+ case ARTICLE_STATUS_0:
+ if(c == '\r')
+ urlp->status = ARTICLE_STATUS_1;
+ else if(c == '\n')
+ urlp->status = ARTICLE_STATUS_2;
+ break;
+
+ case ARTICLE_STATUS_1:
+ if(c == '\n')
+ urlp->status = ARTICLE_STATUS_2;
+ else
+ urlp->status = ARTICLE_STATUS_0;
+ break;
+
+ case ARTICLE_STATUS_2:
+ if(c == '.')
+ urlp->status = ARTICLE_STATUS_3;
+ else
+ urlp->status = ARTICLE_STATUS_0;
+ break;
+
+ case ARTICLE_STATUS_3:
+ if(c == '\r')
+ urlp->status = ARTICLE_STATUS_4;
+ else if(c == '\n')
+ urlp->eof = 1;
+ else
+ urlp->status = ARTICLE_STATUS_0;
+ break;
+
+ case ARTICLE_STATUS_4:
+ if(c == '\n')
+ urlp->eof = 1;
+ break;
+ }
+
+ return c;
+}
+
+#ifdef NEWS_MAIN
+void main(int argc, char **argv)
+{
+ URL url;
+ char buff[BUFSIZ];
+ int c;
+
+ if(argc != 2)
+ {
+ fprintf(stderr, "Usage: %s news-URL\n", argv[0]);
+ exit(1);
+ }
+ if((url = url_news_open(argv[1])) == NULL)
+ {
+ fprintf(stderr, "Can't open news group: %s\n", argv[1]);
+ exit(1);
+ }
+
+#if NEWS_MAIN
+ while((c = url_getc(url)) != EOF)
+ putchar(c);
+#else
+ while((c = url_read(url, buff, sizeof(buff))) > 0)
+ write(1, buff, c);
+#endif
+ url_close(url);
+ exit(0);
+}
+#endif /* NEWS_MAIN */
diff --git a/lib/timidity/libarc/url_newsgroup.c b/lib/timidity/libarc/url_newsgroup.c
new file mode 100644
index 0000000000..c946171dce
--- /dev/null
+++ b/lib/timidity/libarc/url_newsgroup.c
@@ -0,0 +1,546 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include <signal.h> /* for SIGALRM */
+
+#include "timidity.h"
+#include "common.h"
+#include "url.h"
+#include "net.h"
+
+#define NNTP_OK_ID '2'
+#define MAX_LINE_BUFF 1024
+#define ALARM_TIMEOUT 10
+/* #define DEBUG */
+
+#ifdef URL_NEWS_XOVER_SUPPORT
+static char *xover_commands[] = {URL_NEWS_XOVER_SUPPORT, NULL};
+#else
+static char *xover_commands[] = {NULL};
+#endif /* URL_NEWS_XOVER_SUPPORT */
+
+static VOLATILE int timeout_flag = 1;
+
+typedef struct _URL_newsgroup
+{
+ char common[sizeof(struct _URL)];
+
+ FILE *fp;
+ SOCKET fd;
+ int first, last;
+ int minID, maxID;
+ int xover;
+ int eof;
+ char *name;
+} URL_newsgroup;
+
+static int name_newsgroup_check(char *url_string);
+static long url_newsgroup_read(URL url, void *buff, long n);
+static char *url_newsgroup_gets(URL url, char *buff, int n);
+static void url_newsgroup_close(URL url);
+
+struct URL_module URL_module_newsgroup =
+{
+ URL_newsgroup_t,
+ name_newsgroup_check,
+ NULL,
+ url_newsgroup_open,
+ NULL
+};
+
+static int name_newsgroup_check(char *s)
+{
+ if(strncmp(s, "news://", 7) == 0 && strchr(s, '@') == NULL)
+ return 1;
+ return 0;
+}
+
+/*ARGSUSED*/
+static void timeout(int sig)
+{
+ timeout_flag = 1;
+}
+
+URL url_newsgroup_open(char *name)
+{
+ URL_newsgroup *url;
+ SOCKET fd;
+ char *host, *p, *urlname;
+ unsigned short port;
+ char buff[BUFSIZ], group[256], *range;
+ int n;
+
+#ifdef DEBUG
+ printf("url_newsgroup_open(%s)\n", name);
+#endif /* DEBUG */
+
+ if((urlname = safe_strdup(name)) == NULL)
+ return NULL;
+ n = strlen(urlname);
+ while(n > 0 && urlname[n - 1] == '/')
+ urlname[--n] = '\0';
+
+ url = (URL_newsgroup *)alloc_url(sizeof(URL_newsgroup));
+ if(url == NULL)
+ {
+ url_errno = errno;
+ free(urlname);
+ errno = url_errno;
+ return NULL;
+ }
+
+ /* common members */
+ URLm(url, type) = URL_newsgroup_t;
+ URLm(url, url_read) = url_newsgroup_read;
+ URLm(url, url_gets) = url_newsgroup_gets;
+ URLm(url, url_fgetc) = NULL;
+ URLm(url, url_seek) = NULL;
+ URLm(url, url_tell) = NULL;
+ URLm(url, url_close) = url_newsgroup_close;
+
+ /* private members */
+ url->fd = (SOCKET)-1;
+ url->fp = NULL;
+ url->xover = -1;
+ url->eof = 0;
+ url->first = url->last = 0;
+ url->minID = url->maxID = 0;
+ url->name = urlname;
+
+ if(strncmp(name, "news://", 7) == 0)
+ name += 7;
+
+ strncpy(buff, name, sizeof(buff) - 1);
+ buff[sizeof(buff) - 1] = '\0';
+
+ host = buff;
+ for(p = host; *p && *p != ':' && *p != '/'; p++)
+ ;
+ if(*p == ':')
+ {
+ *p++ = '\0'; /* terminate `host' string */
+ port = atoi(p);
+ p = strchr(p, '/');
+ if(p == NULL)
+ {
+ url_errno = URLERR_CANTOPEN;
+ errno = ENOENT;
+ url_newsgroup_close((URL)url);
+ return NULL;
+ }
+ }
+ else
+ port = 119;
+ *p++ = '\0'; /* terminate `host' string */
+ strncpy(group, p, sizeof(group) - 1);
+ group[sizeof(group) - 1] = '\0';
+
+ if((range = strchr(group, '/')) != NULL)
+ *range++ = '\0';
+
+#ifdef DEBUG
+ printf("group: %s\n", group);
+#endif /* DEBUG */
+
+#ifdef DEBUG
+ printf("open(host=`%s', port=`%d')\n", host, port);
+#endif /* DEBUG */
+
+#ifdef __W32__
+ timeout_flag = 0;
+ fd = open_socket(host, port);
+#else
+ timeout_flag = 0;
+ signal(SIGALRM, timeout);
+ alarm(ALARM_TIMEOUT);
+ url->fd = fd = open_socket(host, port);
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+#endif /* __W32__ */
+
+ if(fd == (SOCKET)-1)
+ {
+ VOLATILE_TOUCH(timeout_flag);
+#ifdef ETIMEDOUT
+ if(timeout_flag)
+ errno = ETIMEDOUT;
+#endif /* ETIMEDOUT */
+ if(errno)
+ url_errno = errno;
+ else
+ {
+ url_errno = URLERR_CANTOPEN;
+ errno = ENOENT;
+ }
+ url_newsgroup_close((URL)url);
+ return NULL;
+ }
+
+ if((url->fp = socket_fdopen(fd, "rb")) == NULL)
+ {
+ url_errno = errno;
+ closesocket(fd);
+ url_newsgroup_close((URL)url);
+ errno = url_errno;
+ return NULL;
+ }
+
+ if(socket_fgets(buff, sizeof(buff), url->fp) == NULL)
+ {
+ url_newsgroup_close((URL)url);
+ return NULL;
+ }
+
+#ifdef DEBUG
+ printf("Connect status: %s", buff);
+#endif /* DEBUG */
+
+ if(buff[0] != NNTP_OK_ID)
+ {
+ url_newsgroup_close((URL)url);
+ url_errno = URLERR_CANTOPEN;
+ errno = ENOENT;
+ return NULL;
+ }
+
+ sprintf(buff, "GROUP %s\r\n", group);
+
+#ifdef DEBUG
+ printf("CMD> %s", buff);
+#endif /* DEBUG */
+
+ socket_write(fd, buff, (long)strlen(buff));
+ if(socket_fgets(buff, sizeof(buff), url->fp) == NULL)
+ {
+ url_newsgroup_close((URL)url);
+ url_errno = URLERR_CANTOPEN;
+ errno = ENOENT;
+ return NULL;
+ }
+
+#ifdef DEBUG
+ printf("CMD< %s", buff);
+#endif /* DEBUG */
+
+ if(buff[0] != NNTP_OK_ID)
+ {
+ url_newsgroup_close((URL)url);
+ url_errno = URLERR_CANTOPEN;
+ errno = ENOENT;
+ return NULL;
+ }
+
+ p = buff + 4;
+ if(*p == '0') /* No article */
+ url->eof = 1;
+ p++;
+ while('0' <= *p && *p <= '9')
+ p++;
+ while(*p == ' ')
+ p++;
+ url->first = url->minID = atoi(p);
+ while('0' <= *p && *p <= '9')
+ p++;
+ while(*p == ' ')
+ p++;
+ url->last = url->maxID = atoi(p);
+
+ if(range != NULL)
+ {
+ if('0' <= *range && *range <= '9')
+ {
+ url->first = atoi(range);
+ if(url->first < url->minID)
+ url->first = url->minID;
+ }
+ if((range = strchr(range, '-')) != NULL)
+ {
+ range++;
+ if('0' <= *range && *range <= '9')
+ {
+ url->last = atoi(range);
+ if(url->last > url->maxID)
+ url->last = url->maxID;
+ }
+ }
+ }
+
+ return (URL)url;
+}
+
+char *url_newsgroup_name(URL url)
+{
+ if(url->type != URL_newsgroup_t)
+ return NULL;
+ return ((URL_newsgroup *)url)->name;
+}
+
+static void url_newsgroup_close(URL url)
+{
+ URL_newsgroup *urlp = (URL_newsgroup *)url;
+ int save_errno = errno;
+ if(urlp->fd != (SOCKET)-1)
+ {
+ socket_write(urlp->fd, "QUIT\r\n", 6);
+ closesocket(urlp->fd);
+ }
+ if(urlp->fp != NULL)
+ socket_fclose(urlp->fp);
+ if(urlp->name != NULL)
+ free(urlp->name);
+ free(url);
+ errno = save_errno;
+}
+
+static long url_newsgroup_read(URL url, void *buff, long n)
+{
+ char *p;
+
+ p = url_newsgroup_gets(url, (char *)buff, n);
+ if(p == NULL)
+ return 0;
+ return (long)strlen(p);
+}
+
+static char *url_newsgroup_gets(URL url, char *buff, int n)
+{
+ URL_newsgroup *urlp = (URL_newsgroup *)url;
+ char linebuff[MAX_LINE_BUFF], *p, numbuf[32];
+ int i, j, nump;
+ int find_first;
+
+ if(urlp->eof || n <= 0)
+ return NULL;
+ if(n == 1)
+ {
+ buff[0] = '\0';
+ return buff;
+ }
+
+ find_first = 0;
+ if(urlp->xover == -1)
+ {
+ urlp->xover = 0;
+ for(i = 0; xover_commands[i] != NULL; i++)
+ {
+ sprintf(linebuff, "%s %d-%d\r\n", xover_commands[i],
+ urlp->first, urlp->last);
+#ifdef DEBUG
+ printf("CMD> %s", linebuff);
+#endif /* DEBUG */
+ socket_write(urlp->fd, linebuff, (long)strlen(linebuff));
+ if(socket_fgets(linebuff, sizeof(linebuff), urlp->fp) == NULL)
+ {
+ urlp->eof = 1;
+ return NULL;
+ }
+#ifdef DEBUG
+ printf("CMD< %s", linebuff);
+#endif /* DEBUG */
+ if(linebuff[0] == NNTP_OK_ID)
+ {
+ urlp->xover = 1;
+ break;
+ }
+ }
+ if(!urlp->xover)
+ find_first = 1;
+ }
+ else if(!urlp->xover)
+ socket_write(urlp->fd, "NEXT\r\n", 6);
+
+ next_read:
+ if(find_first)
+ {
+ for(i = urlp->first; i <= urlp->last; i++)
+ {
+ sprintf(linebuff, "STAT %d\r\n", i);
+#ifdef DEBUG
+ printf("CMD> %s", linebuff);
+#endif /* DEBUG */
+ socket_write(urlp->fd, linebuff, (long)strlen(linebuff));
+ if(socket_fgets(linebuff, sizeof(linebuff), urlp->fp) == NULL)
+ {
+ urlp->eof = 1;
+ return NULL;
+ }
+#ifdef DEBUG
+ printf("CMD< %s", linebuff);
+#endif /* DEBUG */
+ if(atoi(linebuff) != 423)
+ break;
+ }
+ if(i > urlp->last)
+ {
+ urlp->eof = 1;
+ return NULL;
+ }
+ find_first = 0;
+ }
+ else
+ {
+ if(socket_fgets(linebuff, sizeof(linebuff), urlp->fp) == NULL)
+ {
+ urlp->eof = 1;
+ return NULL;
+ }
+
+ i = strlen(linebuff);
+ if(i > 0 && linebuff[i - 1] != '\n')
+ {
+ int c;
+
+ do
+ {
+ c = socket_fgetc(urlp->fp);
+ } while(c != '\n' && c != EOF);
+ }
+ }
+ p = linebuff;
+#ifdef DEBUG
+ printf("line: %s", linebuff);
+#endif /* DEBUG */
+
+ if(urlp->xover == 0)
+ {
+ if(p[0] != '2')
+ {
+ if(strncmp(p, "421", 3) == 0)
+ {
+ urlp->eof = 1;
+ return NULL;
+ }
+
+ socket_write(urlp->fd, "NEXT\r\n", 6);
+ goto next_read;
+ }
+
+ p += 3;
+ while(*p == ' ' || *p == '\t')
+ p++;
+ nump = 0;
+ i = atoi(p);
+ if(i > urlp->last)
+ {
+ urlp->eof = 1;
+ return NULL;
+ }
+ if(i == urlp->last)
+ urlp->eof = 1;
+ while('0' <= *p && *p <= '9' && nump < sizeof(numbuf))
+ numbuf[nump++] = *p++;
+ if(nump == 0)
+ {
+ socket_write(urlp->fd, "NEXT\r\n", 6);
+ goto next_read;
+ }
+
+ if((p = strchr(linebuff, '<')) == NULL)
+ {
+ socket_write(urlp->fd, "NEXT\r\n", 6);
+ goto next_read;
+ }
+ }
+ else
+ {
+ int i;
+
+ if(linebuff[0] == '.')
+ {
+ urlp->eof = 1;
+ return NULL;
+ }
+
+ nump = 0;
+ while('0' <= linebuff[nump] && linebuff[nump] <= '9'
+ && nump < sizeof(numbuf))
+ {
+ numbuf[nump] = linebuff[nump];
+ nump++;
+ }
+
+ for(i = 0; i < 4; i++)
+ {
+ p = strchr(p, '\t');
+ if(p == NULL)
+ goto next_read;
+ p++;
+ }
+ }
+
+ if(*p == '<')
+ p++;
+
+ i = j = 0;
+ while(j < n - 2 && j < nump)
+ {
+ buff[j] = numbuf[j];
+ j++;
+ }
+
+ buff[j++] = ' ';
+ while(j < n - 1 && p[i] && p[i] != '>' && p[i] != ' ' && p[i] != '\t')
+ {
+ buff[j] = p[i];
+ i++;
+ j++;
+ }
+ buff[j] = '\0';
+ return buff;
+}
+
+#ifdef NEWSGROUP_MAIN
+void *safe_malloc(int n) { return malloc(n); }
+void *safe_realloc(void *p, int n) { return realloc(p, n); }
+void main(int argc, char **argv)
+{
+ URL url;
+ char buff[BUFSIZ];
+
+ if(argc != 2)
+ {
+ fprintf(stderr, "Usage: %s news-URL\n", argv[0]);
+ exit(1);
+ }
+ if((url = url_newsgroup_open(argv[1])) == NULL)
+ {
+ fprintf(stderr, "Can't open news group: %s\n", argv[1]);
+ exit(1);
+ }
+
+ while(url_gets(url, buff, sizeof(buff)) != NULL)
+ puts(buff);
+ url_close(url);
+ exit(0);
+}
+#endif /* NEWSGROUP_MAIN */
diff --git a/lib/timidity/libarc/url_pipe.c b/lib/timidity/libarc/url_pipe.c
new file mode 100644
index 0000000000..711709ab2a
--- /dev/null
+++ b/lib/timidity/libarc/url_pipe.c
@@ -0,0 +1,174 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "timidity.h"
+#include "url.h"
+
+#ifdef HAVE_POPEN
+/* It is not supported command PIPE at Windows */
+
+typedef struct _URL_pipe
+{
+ char common[sizeof(struct _URL)];
+ FILE *fp;
+} URL_pipe;
+
+#define PIPE_FP(url) (((URL_pipe *)(url))->fp)
+
+static int name_pipe_check(char *url_string);
+static long url_pipe_read(URL url, void *buff, long n);
+static char *url_pipe_gets(URL url, char *buff, int n);
+static int url_pipe_fgetc(URL url);
+static void url_pipe_close(URL url);
+
+struct URL_module URL_module_pipe =
+{
+ URL_pipe_t, /* type */
+ name_pipe_check, /* URL checker */
+ NULL, /* initializer */
+ url_pipe_open, /* open */
+ NULL /* must be NULL */
+};
+
+/* url_string := "command|" */
+static int name_pipe_check(char *url_string)
+{
+#ifdef PIPE_SCHEME_ENABLE
+ char *p;
+ p = strrchr(url_string, '|');
+ if(p == NULL)
+ return 0;
+ p++;
+ while(*p == ' ')
+ p++;
+ return *p == '\0';
+#else
+ return 0;
+#endif
+}
+
+URL url_pipe_open(char *command)
+{
+ URL_pipe *url;
+ char buff[BUFSIZ], *p;
+
+ strncpy(buff, command, sizeof(buff));
+ buff[sizeof(buff) - 1] = '\0';
+ p = strrchr(buff, '|');
+ if(p != NULL)
+ {
+ char *q;
+
+ q = p + 1;
+ while(*q == ' ')
+ q++;
+ if(*q == '\0')
+ {
+ p--;
+ while(buff < p && *p == ' ')
+ p--;
+ if(buff == p)
+ {
+ errno = ENOENT;
+ url_errno = URLERR_IURLF;
+ return NULL;
+ }
+ p[1] = '\0';
+ }
+ }
+
+ url = (URL_pipe *)alloc_url(sizeof(URL_pipe));
+ if(url == NULL)
+ {
+ url_errno = errno;
+ return NULL;
+ }
+
+ /* common members */
+ URLm(url, type) = URL_pipe_t;
+ URLm(url, url_read) = url_pipe_read;
+ URLm(url, url_gets) = url_pipe_gets;
+ URLm(url, url_fgetc) = url_pipe_fgetc;
+ URLm(url, url_seek) = NULL;
+ URLm(url, url_tell) = NULL;
+ URLm(url, url_close) = url_pipe_close;
+
+ /* private members */
+ url->fp = NULL;
+
+ if((url->fp = popen(buff, "r")) == NULL)
+ {
+ url_pipe_close((URL)url);
+ url_errno = errno;
+ return NULL;
+ }
+
+ return (URL)url;
+}
+
+static long url_pipe_read(URL url, void *buff, long n)
+{
+ return (long)fread(buff, 1, n, PIPE_FP(url));
+}
+
+static char *url_pipe_gets(URL url, char *buff, int n)
+{
+ return fgets(buff, n, PIPE_FP(url));
+}
+
+static int url_pipe_fgetc(URL url)
+{
+#ifdef getc
+ return getc(PIPE_FP(url));
+#else
+ return fgetc(PIPE_FP(url));
+#endif /* getc */
+}
+
+static void url_pipe_close(URL url)
+{
+ int save_errno = errno;
+ if(PIPE_FP(url) != NULL)
+ pclose(PIPE_FP(url));
+ free(url);
+ errno = save_errno;
+}
+
+#else /* HAVE_POPEN */
+struct URL_module URL_module_pipe =
+{
+ URL_none_t, /* type */
+ NULL, /* URL checker */
+ NULL, /* initializer */
+ NULL, /* open */
+ NULL /* must be NULL */
+};
+URL url_pipe_open(char *command) { return NULL; } /* dmy */
+#endif
diff --git a/lib/timidity/libarc/url_qsdecode.c b/lib/timidity/libarc/url_qsdecode.c
new file mode 100644
index 0000000000..35c74f4875
--- /dev/null
+++ b/lib/timidity/libarc/url_qsdecode.c
@@ -0,0 +1,252 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "timidity.h"
+#include "url.h"
+
+#define DECODEBUFSIZ BUFSIZ
+
+typedef struct _URL_qsdecode
+{
+ char common[sizeof(struct _URL)];
+ URL reader;
+ long rpos;
+ int beg, end, eof, eod;
+ unsigned char decodebuf[DECODEBUFSIZ];
+ int autoclose;
+} URL_qsdecode;
+
+static long url_qsdecode_read(URL url, void *buff, long n);
+static int url_qsdecode_fgetc(URL url);
+static long url_qsdecode_tell(URL url);
+static void url_qsdecode_close(URL url);
+
+URL url_qsdecode_open(URL reader, int autoclose)
+{
+ URL_qsdecode *url;
+
+ url = (URL_qsdecode *)alloc_url(sizeof(URL_qsdecode));
+ if(url == NULL)
+ {
+ if(autoclose)
+ url_close(reader);
+ url_errno = errno;
+ return NULL;
+ }
+
+ /* common members */
+ URLm(url, type) = URL_qsdecode_t;
+ URLm(url, url_read) = url_qsdecode_read;
+ URLm(url, url_gets) = NULL;
+ URLm(url, url_fgetc) = url_qsdecode_fgetc;
+ URLm(url, url_seek) = NULL;
+ URLm(url, url_tell) = url_qsdecode_tell;
+ URLm(url, url_close) = url_qsdecode_close;
+
+ /* private members */
+ url->reader = reader;
+ url->rpos = 0;
+ url->beg = 0;
+ url->end = 0;
+ url->eof = url->eod = 0;
+ memset(url->decodebuf, 0, sizeof(url->decodebuf));
+ url->autoclose = autoclose;
+
+ return (URL)url;
+}
+
+static int qsdecode(URL_qsdecode *urlp)
+{
+ int n;
+ unsigned char *p;
+ URL url;
+
+ if(urlp->eod)
+ {
+ urlp->eof = 1;
+ return 1;
+ }
+
+ p = urlp->decodebuf;
+ url = urlp->reader;
+ n = 0;
+ while(n < DECODEBUFSIZ)
+ {
+ int c1, c2;
+
+ if((c1 = url_getc(url)) == EOF)
+ break;
+ if(c1 != '=')
+ {
+ p[n++] = c1;
+ continue;
+ }
+
+ /* quoted character */
+ next_quote:
+ if((c1 = url_getc(url)) == EOF)
+ break;
+ if(c1 == '\n')
+ continue;
+ if(c1 == '\r')
+ {
+ if((c1 = url_getc(url)) == EOF)
+ break;
+ if(c1 == '\n')
+ continue;
+ if(c1 == '=')
+ goto next_quote;
+ p[n++] = c1;
+ continue;
+ }
+ if((c2 = url_getc(url)) == EOF)
+ break;
+ if('0' <= c1 && c1 <= '9')
+ c1 -= '0';
+ else if('A' <= c1 && c1 <= 'F')
+ c1 -= 'A' - 10;
+ else
+ c1 = 0;
+ if('0' <= c2 && c2 <= '9')
+ c2 -= '0';
+ else if('A' <= c2 && c2 <= 'F')
+ c2 -= 'A' - 10;
+ else
+ c2 = 0;
+ p[n++] = (c1 << 4 | c2);
+ }
+
+ urlp->rpos += urlp->beg;
+ urlp->beg = 0;
+ urlp->end = n;
+
+ if(n < DECODEBUFSIZ)
+ urlp->eod = 1;
+
+ if(n == 0)
+ {
+ urlp->eof = 1;
+ return 1;
+ }
+
+
+ return 0;
+}
+
+static long url_qsdecode_read(URL url, void *buff, long size)
+{
+ URL_qsdecode *urlp = (URL_qsdecode *)url;
+ unsigned char *p = (unsigned char *)buff;
+ long n;
+
+ if(urlp->eof)
+ return 0;
+
+ n = 0;
+ while(n < size)
+ {
+ int i;
+
+ if(urlp->beg == urlp->end)
+ if(qsdecode(urlp))
+ break;
+ i = urlp->end - urlp->beg;
+ if(i > size - n)
+ i = size - n;
+ memcpy(p + n, urlp->decodebuf + urlp->beg, i);
+ n += i;
+ urlp->beg += i;
+ }
+ return n;
+}
+
+static int url_qsdecode_fgetc(URL url)
+{
+ URL_qsdecode *urlp = (URL_qsdecode *)url;
+
+ if(urlp->eof)
+ return EOF;
+ if(urlp->beg == urlp->end)
+ if(qsdecode(urlp))
+ return EOF;
+
+ return (int)urlp->decodebuf[urlp->beg++];
+}
+
+static long url_qsdecode_tell(URL url)
+{
+ URL_qsdecode *urlp = (URL_qsdecode *)url;
+
+ return urlp->rpos + urlp->beg;
+}
+
+static void url_qsdecode_close(URL url)
+{
+ URL_qsdecode *urlp = (URL_qsdecode *)url;
+
+ if(urlp->autoclose)
+ url_close(urlp->reader);
+ free(url);
+}
+
+#ifdef QSDECODE_MAIN
+void main(int argc, char** argv)
+{
+ URL qsdecoder;
+ char buff[256], *filename;
+ int c;
+
+ if(argc != 2)
+ {
+ fprintf(stderr, "Usage: %s qs-filename\n", argv[0]);
+ exit(1);
+ }
+ filename = argv[1];
+
+ if((qsdecoder = url_file_open(filename)) == NULL)
+ {
+ perror(argv[1]);
+ url_close(qsdecoder);
+ exit(1);
+ }
+
+ qsdecoder = url_qsdecode_open(qsdecoder, 1);
+#if QSDECODE_MAIN
+ while((c = url_getc(qsdecoder)) != EOF)
+ putchar(c);
+#else
+ while((c = url_read(qsdecoder, buff, sizeof(buff))) > 0)
+ write(1, buff, c);
+#endif
+ url_close(qsdecoder);
+ exit(0);
+}
+
+#endif /* QSDECODE_MAIN */
diff --git a/lib/timidity/libarc/url_uudecode.c b/lib/timidity/libarc/url_uudecode.c
new file mode 100644
index 0000000000..7eba820c5e
--- /dev/null
+++ b/lib/timidity/libarc/url_uudecode.c
@@ -0,0 +1,282 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "timidity.h"
+#include "url.h"
+
+typedef struct _URL_uudecode
+{
+ char common[sizeof(struct _URL)];
+ URL reader;
+ long rpos;
+ int beg, end, eof;
+ unsigned char decodebuf[128];
+ int autoclose;
+} URL_uudecode;
+
+static long url_uudecode_read(URL url, void *buff, long n);
+static int url_uudecode_fgetc(URL url);
+static long url_uudecode_tell(URL url);
+static void url_uudecode_close(URL url);
+
+URL url_uudecode_open(URL reader, int autoclose)
+{
+ URL_uudecode *url;
+
+ url = (URL_uudecode *)alloc_url(sizeof(URL_uudecode));
+ if(url == NULL)
+ {
+ if(autoclose)
+ url_close(reader);
+ url_errno = errno;
+ return NULL;
+ }
+
+ /* common members */
+ URLm(url, type) = URL_uudecode_t;
+ URLm(url, url_read) = url_uudecode_read;
+ URLm(url, url_gets) = NULL;
+ URLm(url, url_fgetc) = url_uudecode_fgetc;
+ URLm(url, url_seek) = NULL;
+ URLm(url, url_tell) = url_uudecode_tell;
+ URLm(url, url_close) = url_uudecode_close;
+
+ /* private members */
+ url->reader = reader;
+ url->rpos = 0;
+ url->beg = 0;
+ url->end = 0;
+ url->eof = 0;
+ memset(url->decodebuf, 0, sizeof(url->decodebuf));
+ url->autoclose = autoclose;
+
+ return (URL)url;
+}
+
+#define DEC(c) (((c) - ' ') & 077) /* single character decode */
+static int uudecodeline(URL_uudecode *urlp)
+{
+ unsigned char inbuf[BUFSIZ], *p, *q, ch;
+ int n;
+
+ if(url_gets(urlp->reader, (char *)inbuf, sizeof(inbuf)) == NULL)
+ {
+ urlp->eof = 1;
+ return 1;
+ }
+
+ if((n = DEC(*inbuf)) <= 0)
+ {
+ urlp->eof = 1;
+ return 1;
+ }
+
+ if(uudecode_unquote_html)
+ {
+ int i, j, len;
+
+ len = strlen((char *)inbuf);
+ while(len > 0 &&
+ (inbuf[len - 1] == '\r' || inbuf[len - 1] == '\n' ||
+ inbuf[len - 1] == '\t' || inbuf[len - 1] == ' '))
+ inbuf[--len] = '\0';
+ if(n * 4 != (len - 1) * 3)
+ {
+ /* &lt;/&gt;/&amp; */
+ i = j = 0;
+ while(i < len - 3)
+ if(inbuf[i] != '&')
+ inbuf[j++] = inbuf[i++];
+ else
+ {
+ i++;
+ if(strncmp((char *)inbuf + i, "lt;", 3) == 0)
+ {
+ inbuf[j++] = '<';
+ i += 3;
+ }
+ else if(strncmp((char *)inbuf + i, "gt;", 3) == 0)
+ {
+ inbuf[j++] = '>';
+ i += 3;
+ }
+ else if(strncmp((char *)inbuf + i, "amp;", 4) == 0)
+ {
+ inbuf[j++] = '&';
+ i += 4;
+ }
+ else
+ inbuf[j++] = '&';
+ }
+ while(i < len)
+ inbuf[j++] = inbuf[i++];
+ inbuf[j++] = '\0';
+ }
+ }
+
+ p = inbuf + 1;
+ q = urlp->decodebuf;
+ for(; n > 0; p += 4, n -= 3)
+ {
+ if(n >= 3)
+ {
+ ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
+ *q++ = ch;
+ ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
+ *q++ = ch;
+ ch = DEC(p[2]) << 6 | DEC(p[3]);
+ *q++ = ch;
+ }
+ else
+ {
+ if(n >= 1)
+ {
+ ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
+ *q++ = ch;
+ }
+ if(n >= 2)
+ {
+ ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
+ *q++ = ch;
+ }
+ if(n >= 3)
+ {
+ ch = DEC(p[2]) << 6 | DEC(p[3]);
+ *q++ = ch;
+ }
+ }
+ }
+ urlp->rpos += urlp->beg;
+ urlp->beg = 0;
+ urlp->end = q - urlp->decodebuf;
+ return 0;
+}
+
+static long url_uudecode_read(URL url, void *buff, long size)
+{
+ URL_uudecode *urlp = (URL_uudecode *)url;
+ unsigned char *p = (unsigned char *)buff;
+ long n;
+
+ if(urlp->eof)
+ return 0;
+
+ n = 0;
+ while(n < size)
+ {
+ int i;
+
+ if(urlp->beg == urlp->end)
+ if(uudecodeline(urlp))
+ break;
+ i = urlp->end - urlp->beg;
+ if(i > size - n)
+ i = size - n;
+ memcpy(p + n, urlp->decodebuf + urlp->beg, i);
+ n += i;
+ urlp->beg += i;
+ }
+ return n;
+}
+
+static int url_uudecode_fgetc(URL url)
+{
+ URL_uudecode *urlp = (URL_uudecode *)url;
+
+ if(urlp->eof)
+ return EOF;
+ if(urlp->beg == urlp->end)
+ if(uudecodeline(urlp))
+ return EOF;
+
+ return (int)urlp->decodebuf[urlp->beg++];
+}
+
+static long url_uudecode_tell(URL url)
+{
+ URL_uudecode *urlp = (URL_uudecode *)url;
+
+ return urlp->rpos + urlp->beg;
+}
+
+static void url_uudecode_close(URL url)
+{
+ URL_uudecode *urlp = (URL_uudecode *)url;
+
+ if(urlp->autoclose)
+ url_close(urlp->reader);
+ free(url);
+}
+
+#ifdef UUDECODE_MAIN
+void main(int argc, char** argv)
+{
+ URL uudecoder;
+ char buff[256], *filename;
+ int c;
+
+ if(argc != 2)
+ {
+ fprintf(stderr, "Usage: %s uu-filename\n", argv[0]);
+ exit(1);
+ }
+ filename = argv[1];
+
+ if((uudecoder = url_file_open(filename)) == NULL)
+ {
+ perror(argv[1]);
+ exit(1);
+ }
+
+ for(;;)
+ {
+ if(url_readline(uudecoder, buff, sizeof(buff)) == EOF)
+ {
+ fprintf(stderr, "%s: Not a hqx-file\n", filename);
+ url_close(uudecoder);
+ exit(1);
+ }
+ if(strncmp(buff, "begin ", 6) == 0)
+ break;
+ }
+
+ uudecoder = url_uudecode_open(uudecoder, 1);
+#if UUDECODE_MAIN
+ while((c = url_getc(uudecoder)) != EOF)
+ putchar(c);
+#else
+ while((c = url_read(uudecoder, buff, sizeof(buff))) > 0)
+ write(1, buff, c);
+#endif
+ url_close(uudecoder);
+ exit(0);
+}
+
+#endif /* UUDECODE_MAIN */
diff --git a/lib/timidity/libarc/zip.h b/lib/timidity/libarc/zip.h
new file mode 100644
index 0000000000..b3f771e276
--- /dev/null
+++ b/lib/timidity/libarc/zip.h
@@ -0,0 +1,116 @@
+/*
+ TiMidity++ -- MIDI to WAVE converter and player
+ Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+ Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+ 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
+*/
+
+#ifndef ___ZIP_H_
+#define ___ZIP_H_
+
+/* zip.h -- common declarations for deflate/inflate routine */
+
+#define INBUF_EXTRA 64
+#define OUTBUF_EXTRA 2048
+
+#ifdef SMALL_MEM
+# define INBUFSIZ 8192 /* input buffer size */
+# define OUTBUFSIZ 8192 /* output buffer size */
+#else
+# define INBUFSIZ 32768 /* input buffer size */
+# define OUTBUFSIZ 16384 /* output buffer size */
+#endif
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model).
+ Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16
+ means that v is a literal, 16 < e < 32 means that v is a pointer to
+ the next table, which codes e - 16 bits, and lastly e == 99 indicates
+ an unused code. If a code with e == 99 is looked up, this implies an
+ error in the data. */
+struct huft {
+ uch e; /* number of extra bits or operation */
+ uch b; /* number of bits in this code or subcode */
+ union {
+ ush n; /* literal, length base, or distance base */
+ struct huft *t; /* pointer to next level of table */
+ } v;
+};
+
+int huft_build(unsigned *, unsigned, unsigned, ush *, ush *,
+ struct huft **, int *, MBlockList *pool);
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define WSIZE 32768 /* window size--must be a power of two, and */
+ /* at least 32K for zip's deflate method */
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# define Trace(x) fprintf x
+# define Tracev(x) {fprintf x ;}
+# define Tracevv(x) {fprintf x ;}
+# define Tracec(c,x) {fprintf x ;}
+# define Tracecv(c,x) {fprintf x ;}
+#else
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+#define near
+
+typedef struct _InflateHandler *InflateHandler;
+typedef struct _DeflateHandler *DeflateHandler;
+
+/*****************************************************************/
+/* INTERFACE FUNCTIONS */
+/*****************************************************************/
+
+/* in deflate.c */
+extern DeflateHandler open_deflate_handler(
+ long (* read_func)(char *buf, long size, void *user_val),
+ void *user_val,
+ int compression_level);
+
+extern long zip_deflate(DeflateHandler encoder,
+ char *decode_buff,
+ long decode_buff_size);
+
+extern void close_deflate_handler(DeflateHandler encoder);
+
+
+/* in inflate.c */
+extern InflateHandler open_inflate_handler(
+ long (* read_func)(char *buf, long size, void *user_val),
+ void *user_val);
+
+extern long zip_inflate(InflateHandler decoder,
+ char *decode_buff,
+ long decode_buff_size);
+
+extern void close_inflate_handler(InflateHandler decoder);
+
+#endif /* ___ZIP_H_ */