diff options
author | theuni <theuni-nospam-@xbmc.org> | 2011-01-24 16:05:21 -0500 |
---|---|---|
committer | theuni <theuni-nospam-@xbmc.org> | 2011-01-24 16:05:21 -0500 |
commit | c51b1189e3d5353e842991f5859ddcea0f73e426 (patch) | |
tree | ef2cb8a6184699aa614f3655dca4ce661cdc108e /lib/timidity/libarc | |
parent | be61ebdc9e897fe40c6f371111724de79ddee8d5 (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')
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) + { + /* </>/& */ + 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_ */ |