summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnas Nashif <anas.nashif@intel.com>2012-11-04 12:13:45 -0800
committerAnas Nashif <anas.nashif@intel.com>2012-11-04 12:13:45 -0800
commit8085c3ee0d3e83e7693c162c10e4bc367c23518b (patch)
treee092f95b6503969974b6fc9e6473a7162207d1f4
downloadlibzio-8085c3ee0d3e83e7693c162c10e4bc367c23518b.tar.gz
libzio-8085c3ee0d3e83e7693c162c10e4bc367c23518b.tar.bz2
libzio-8085c3ee0d3e83e7693c162c10e4bc367c23518b.zip
Imported Upstream version 0.99upstream/0.99
-rw-r--r--COPYING340
-rw-r--r--Makefile133
-rw-r--r--README50
-rw-r--r--fzopen.3.in342
-rw-r--r--lzw.h123
-rw-r--r--tests.c28
-rw-r--r--testt.c33
-rw-r--r--unlzw.c464
-rw-r--r--zio.c1208
-rw-r--r--zio.h.in33
-rw-r--r--zio.map7
-rw-r--r--zioP.h165
12 files changed, 2926 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..60549be
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..604b655
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,133 @@
+#
+# Makefile for compiling libzio
+#
+# Author: Werner Fink, <werner@suse.de>
+#
+
+LARGE = $(shell getconf LFS_CFLAGS)
+CFLAGS = $(RPM_OPT_FLAGS) -pipe -Wall -D_GNU_SOURCE -D_REENTRANT $(LARGE)
+CC = gcc
+MAJOR = 0
+MINOR = 99
+VERSION = $(MAJOR).$(MINOR)
+SONAME = libzio.so.$(MAJOR)
+LDMAP = -Wl,--version-script=zio.map
+
+prefix = /usr
+libdir = $(prefix)/lib
+datadir = $(prefix)/share
+mandir = $(datadir)/man
+incdir = $(prefix)/include
+
+FILES = README \
+ COPYING \
+ Makefile \
+ zio.c \
+ zioP.h \
+ zio.h.in \
+ testt.c \
+ tests.c \
+ lzw.h \
+ unlzw.c \
+ zio.map \
+ fzopen.3.in
+
+### Includes and Defines (add further entries here):
+
+cc-include = $(shell $(CC) $(INCLUDES) -include $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1 && echo "-D$(2)")
+cc-library = $(shell echo 'int main () { return 0; }' |$(CC) -l$(1:lib%=%) -o /dev/null -xc - > /dev/null 2>&1 && echo yes)
+cc-function = $(shell echo 'extern void $(1)(void); int main () { $(1)(); return 0; }' |$(CC) -o /dev/null -xc - > /dev/null 2>&1 && echo "-D$(2)")
+
+CFLAGS += $(call cc-include,libio.h,HAVE_LIBIO_H)
+CFLAGS += $(call cc-function,fopencookie,HAVE_FOPENCOOKIE)
+CFLAGS += $(call cc-function,funopen,HAVE_FUNOPEN)
+
+CFLAGS += $(call cc-include,zlib.h,HAS_ZLIB_H)
+CFLAGS += $(call cc-include,bzlib.h,HAS_BZLIB_H)
+CFLAGS += $(call cc-include,lzmadec.h,HAS_LZMADEC_H)
+CFLAGS += $(call cc-include,lzma.h,HAS_LZMA_H)
+
+LIBS = -lz
+ifeq ($(call cc-library,libbz2),yes)
+ LIBS += -lbz2
+endif
+ifeq ($(call cc-library,liblzma),yes)
+ LIBS += -llzma
+else
+ifeq ($(call cc-library,lzmadec),yes)
+ LIBS += -llzmadec
+endif
+endif
+
+all: shared static
+noweak: CFLAGS += -DNO_WEAK
+noweak: LINK += $(LIBS)
+noweak: all
+shared: libzio.so.$(VERSION) zio.map
+static: libzio.a
+
+obj/zio.o: zio.c zioP.h zio.h
+ test -d obj/ || mkdir obj/
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+obs/zio.o: zio.c zioP.h zio.h
+ test -d obs/ || mkdir obs/
+ $(CC) $(CFLAGS) -fPIC -o $@ -c $<
+
+obj/unlzw.o: unlzw.c lzw.h
+ test -d obj/ || mkdir obj/
+ $(CC) $(CFLAGS) -funroll-loops -o $@ -c $<
+
+obs/unlzw.o: unlzw.c lzw.h
+ test -d obs/ || mkdir obs/
+ $(CC) $(CFLAGS) -fPIC -o $@ -c $<
+
+libzio.a: obj/zio.o obj/unlzw.o
+ ar -rv $@ $^
+ ranlib $@
+
+libzio.so.$(VERSION): obs/zio.o obs/unlzw.o
+ gcc -shared -Wl,-soname,$(SONAME),-stats $(LDMAP) -o $@ $^ $(LINK)
+
+zioP.h: /usr/include/bzlib.h /usr/include/zlib.h
+zio.h: zio.h.in /usr/include/stdio.h
+ sed 's/@@VERSION@@/$(VERSION)/' < $< > $@
+fzopen.3: fzopen.3.in
+ sed 's/@@VERSION@@/$(VERSION)/' < $< > $@
+
+unlzw.c: lzw.h
+
+install: install-shared install-static install-data
+
+install-shared: libzio.so.$(VERSION)
+ mkdir -p $(DESTDIR)$(libdir)
+ install -m 0755 libzio.so.$(VERSION) $(DESTDIR)$(libdir)/
+ ln -sf libzio.so.$(VERSION) $(DESTDIR)$(libdir)/libzio.so.$(MAJOR)
+ ln -sf libzio.so.$(MAJOR) $(DESTDIR)$(libdir)/libzio.so
+
+install-static: libzio.a
+ mkdir -p $(DESTDIR)$(libdir)
+ install -m 0644 libzio.a $(DESTDIR)$(libdir)/
+
+install-data: zio.h fzopen.3
+ mkdir -p $(DESTDIR)$(incdir)
+ mkdir -p $(DESTDIR)$(mandir)/man3
+ install -m 0644 zio.h $(DESTDIR)$(incdir)/
+ install -m 0644 fzopen.3 $(DESTDIR)$(mandir)/man3/
+
+clean:
+ rm -f *.a *.so* testt tests zio.h
+ rm -rf obj/ obs/
+ rm -f libzio-$(VERSION).tar.gz
+
+dest: clean
+ mkdir libzio-$(VERSION)
+ cp -p $(FILES) libzio-$(VERSION)/
+ tar czf libzio-$(VERSION).tar.gz libzio-$(VERSION)/
+ rm -rf libzio-$(VERSION)/
+
+testt: testt.c libzio.a
+ $(CC) $(CFLAGS) -o $@ $^ $(LIBS)
+
+tests: tests.c libzio.a
+ $(CC) $(CFLAGS) -o $@ $^ $(LIBS)
diff --git a/README b/README
new file mode 100644
index 0000000..b53999c
--- /dev/null
+++ b/README
@@ -0,0 +1,50 @@
+ Wrapper for reading or writing gzip/bzip2 files
+ ===============================================
+
+This small lib provides with the help of the fopencookie(3)
+interface of the glibc together with the zlib and libbzip2
+an simple interface for reading or writing gzip/bzip2 files
+with streams. Beside handling gzip files and bzip2 files,
+the libzio provides support for reading ``.Z'' compressed
+files. By using the GNUC compiler weak facility one or both
+libraries, zlib or libbzip2, can be skipped at linkage time.
+
+To use this e.g. an
+
+ #include <zio.h>
+
+and
+
+ FILE * file = fzopen("myfile.gz", "r");
+
+or
+
+ int fd = open("myfile.gz", O_RDONLY);
+ FILE * file = fdzopen(fd, "r", "g");
+
+together with linking the resulting program with -lzio _and_
+`-lz'. For bzip2 files clearly the libbz2 with `-lbz2' has
+to used at linkage time.
+
+The zlib and/or libbzip2 librares are required because the
+libzio is not linked with `-lz' nor with `-lbz2'. If the
+appropriate library functions of libz or libbz2 are not found
+the fzopen(3) function returns NULL and the errno is set to
+the value ENOSYS for not implemented.
+
+As the libbzip2 does not provide a function for seeking in
+a bzip2 file, any call of fseek(3) on the open stream will
+fail and set the errno to ESPIPE.
+
+For writing gzip/bzip2 files, fzopen(3) only supports the
+suffixes ``.z'' and ``.gz'' for gzipped files and ``.bz2''
+for bzip2ed files.
+
+On reading first the appropriate suffixes are checked if not
+provided. If no file is found the magic byte sequence at the
+beginning of the file is checked to detect which type of
+compressing is used for the file.
+
+Happy (un)compressing,
+
+ Werner Fink
diff --git a/fzopen.3.in b/fzopen.3.in
new file mode 100644
index 0000000..72829a9
--- /dev/null
+++ b/fzopen.3.in
@@ -0,0 +1,342 @@
+'\" t -*- coding: UTF-8 -*-
+.\"
+.\" Copyright 2004 Werner Fink, 2004 SuSE LINUX AG, Germany.
+.\" Copyright 2006 Werner Fink, 2006 SuSE Products GmbH, Germany.
+.\" Copyright 2008 Werner Fink, 2008 SuSE Products GmbH, Germany.
+.\" Copyright 2009 Werner Fink, 2009 SuSE Products GmbH, Germany.
+.\"
+.\" 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.
+.\"
+.TH fzopen 3 "Apr 20, 2006" "Version @@VERSION@@" " Linux Programmer's Manual"
+.UC 3
+.OS SuSE Linux
+.SH NAME
+fzopen \- stream open functions on compressed files
+.br
+fdzopen \- stream open functions on compressed files
+.SH SYNOPSIS
+.\"
+.B #include <zio.h>
+.sp
+.BI "FILE *fzopen (const char *" path ", const char *" mode );
+.br
+.BI "FILE *fdzopen (int " fildes ", const char *" mode ", const char *" what );
+.SH DESCRIPTION
+The
+.B fzopen
+function opens the compressed file whose name is the string to by
+.I path
+and associates a stream with it.
+The
+.B fdopen
+function associates a stream for the existing files descriptor
+.I fildes
+for a compressed file.
+.PP
+The argument
+.I mode
+points to a string beginning with one of the following sequences
+(Additional characters may follow these sequences.):
+.TP
+.B r
+Open compressed text file for reading. The stream is positioned
+at the beginning of the file.
+.TP
+.B w
+Truncate file to zero length or create compressed text file for writing.
+The stream is positioned at the beginning of the file.
+.TP
+.BR w1 - 9
+Just like above but provides also the compression level.
+.PP
+The argument
+.I what
+of the function
+.B fdzopen
+specifies the underlying compression method which should be used:
+.TP
+.BR g , z
+The file descriptor points to a gziped file.
+.TP
+.BR b
+The file descriptor points to a bzip2ed file.
+.TP
+.BR l
+The file descriptor points to a lzma2ed file.
+.TP
+.BR Z
+The file descriptor points to a file in LZW format.
+.PP
+Note that
+.B fzopen
+and
+.B fdzopen
+can only open a compressed text file for reading
+.B or
+writing, but
+.IR both ,
+which means that the
+.B +
+is not possible. Nor can any compressed text file open for appending,
+which makes
+.B a
+not usable with
+.BR fzopen .
+.\"
+.SH NOTE
+The program using libzio with
+.B -lzio
+at linking time should also be linked with
+the appropriate library for accessing compressed
+text files. This is the libz with
+.B -lz
+for accessing gziped text files and/or with
+.B -lbz2
+for accessing bzip2ed text files.
+.PP
+For writing gzip/bzip2 files,
+.B fzopen
+only supports the suffixes
+.IR .z " and ".gz
+for gzipped files and
+.I .bz2
+for bzip2ed files. All supported formats can be found in
+the following table:
+.IP
+.TS H
+allbox;
+c l l l l l
+rb l l l l l.
+ fread fwrite fseek suffix library
+gzip yes yes yes .gz -lz
+bzip2 yes yes yes .bz2 -lbz2
+LZW yes no yes .Z builtin
+lzma yes yes(no) yes .lzma -llzma (-llzmadec)
+xz yes yes yes .xz -llzma
+.TE
+.PP
+.PP
+On reading first the appropriate suffixes are checked
+if not provided. If no file is found the magic
+byte sequence at the beginning of the file is checked
+to detect a gzip or bzip2 file.
+.PP
+.\"
+.SH CONFIGURATION
+With the help of
+.BR autoconf (1)
+or
+.BR autoreconf (1)
+and a few lines in the common file
+.B configure.in
+or
+.B configure.ac
+found in many source packages a programmer or maintainer
+can extend the automatic configuration to find the
+appropriate libraries together with the libzio:
+.PP
+.IP
+.nf
+AC_CHECK_HEADER(zio.h, [
+ AC_CHECK_LIB(zio, fzopen, [
+ AC_CHECK_LIB(zio, fdzopen, [LIBS="$LIBS -l$zio"; am_cv_libzio=yes])
+ ])
+])
+if test "$am_cv_libzio" = yes; then
+ am_cv_libzio=with
+ AC_DEFINE(HAVE_ZIO, 1, [Define if you have libzio for opening compressed files.])
+ AC_CHECK_HEADER(zlib.h, [
+ for lib in z gz; do
+ AC_CHECK_LIB($lib, gzopen, [
+ LIBS="$LIBS -l$lib"
+ am_cv_libzio="$am_cv_libzio lib$lib"
+ break
+ ])
+ done
+ ])
+ AC_CHECK_HEADER(bzlib.h, [
+ for lib in bz2 bzip2; do
+ AC_CHECK_LIB($lib, BZ2_bzopen, [
+ LIBS="$LIBS -l$lib"
+ am_cv_libzio="$am_cv_libzio lib$lib"
+ break
+ ])
+ done
+ ])
+ AC_CHECK_HEADER(lzmadec.h, [
+ for lib in libzma lzmadec; do
+ AC_CHECK_LIB($lib, lzmadec_open, [
+ LIBS="$LIBS -l$lib"
+ am_cv_libzio="$am_cv_libzio lib$lib"
+ break
+ ])
+ done
+ ])
+ AC_MSG_NOTICE([libzio is used [$]am_cv_libzio])
+fi
+.fi
+.PP
+combined with two lines in the common file
+.B config.h.in
+like
+.PP
+.RS 1c
+.nf
+/* Define to 1 if you have libzio for opening compressed files */
+#undef HAVE_ZIO
+.fi
+.RE
+.PP
+(automatically added by
+.BR autoreconf (1))
+it is easy to use the
+.BR cpp (1)
+macro
+.I HAVE_ZIO
+for the usage of
+.B fzopen
+instead of
+.BR fopen (3).
+.PP
+.\"
+.SH RETURN VALUES
+Upon successful completion
+.B fzopen
+return a
+.B FILE
+pointer. Otherwise,
+.B NULL
+is returned and the global variable errno is set to
+indicate the error.
+.\"
+.SH ERRORS
+.TP
+.B EINVAL
+The
+.I mode
+provided to
+.B fzopen
+was invalid.
+.TP
+.B ENOSYS
+The program using
+.B fzopen
+is not linked with the appropriate library
+.RB ( -lz
+for gziped files and
+.B -lbz2
+for bzip2ed files.)
+.TP
+.B ENOTSUP
+The program using
+.B fzopen
+has specified a wrong mode for a
+.B .bz2
+files
+or has opened a
+.B .Z
+file for writing.
+.TP
+.B ENOMEM
+The call of the library functions of the
+.B libz
+or
+.B libbz2
+fails due failed memory allocation.
+.TP
+.B ESPIPE
+This happens if
+.BR fseek (3)
+is used in the case of seesking files is not
+supported.
+.\"
+.SH WARNINGS
+The functions
+.BR fileno (3)
+or
+.BR freopen (3)
+may not be applied on streams opened by
+.BR fzopen .
+An further explanation will be found in section
+.BR BUGS .
+.\"
+.SH BUGS
+.B Fzopen
+can not seek within
+.I bzip2
+files due to the fact that the
+.B libbz2
+does not provide a function like
+.I libz
+does with
+.BR gzseek .
+.B .Z
+compressed file will be opened by
+.B fzopen
+and
+.B fzdopen
+only for reading. Also a seek
+is not possible for
+.B .Z
+files.
+.B .lzma
+compressed file will be opened by
+.B fzopen
+and
+.B fzdopen
+only for reading as the liblzmadec only
+supports reading.
+As the
+.B fzopen
+and
+.B fdzopen
+are custom-made streams created with the help of
+.BR fopencookie (3)
+function of the
+.B glibc
+or
+.BR funopen (3)
+known from BSD Systems
+it is not possible to use the file descriptor with e.g.
+.BR fileno (3)
+in combination with system calls like
+.BR read (2)
+as this will evade the underlying read/write
+functions of the e.g.
+.BR libz .
+.SH FILES
+.\"
+.BR /usr/include/zio.h
+.SH SEE ALSO
+.BR fopen (3),
+.br
+.BR fopencookie (3)
+.br
+.BR funopen (3)
+.br
+.BR gzip (1),
+.br
+.BR bzip2 (1),
+.br
+.BR lzma (1),
+.br
+.BR xz (1),
+.br
+.BR /usr/include/zlib.h ,
+.br
+.BR /usr/include/bzlib.h .
+.br
+.BR /usr/include/lzma.h .
+.br
+.BR /usr/include/lzmadec.h .
+.SH COPYRIGHT
+2004 Werner Fink,
+2004 SuSE LINUX AG Nuernberg, Germany.
+.br
+2006,2008,2009 Werner Fink,
+2006,2008,2009 SuSE Products GmbH, Germany.
+.SH AUTHOR
+Werner Fink <werner@suse.de>
diff --git a/lzw.h b/lzw.h
new file mode 100644
index 0000000..f1251f3
--- /dev/null
+++ b/lzw.h
@@ -0,0 +1,123 @@
+/* lzw.h -- define the lzw functions.
+
+ Copyright (C) 1992-1993 Jean-loup Gailly.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef BITS
+# define BITS 16
+#endif
+#define INIT_BITS 9 /* Initial number of bits per code */
+
+#define LZW_MAGIC "\037\235" /* Magic header for lzw files, 1F 9D */
+
+#define BIT_MASK 0x1f /* Mask for 'number of compression bits' */
+/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
+ * It's a pity that old uncompress does not check bit 0x20. That makes
+ * extension of the format actually undesirable because old compress
+ * would just crash on the new format instead of giving a meaningful
+ * error message. It does check the number of bits, but it's more
+ * helpful to say "unsupported format, get a new version" than
+ * "can only handle 16 bits".
+ */
+
+#define BLOCK_MODE 0x80
+/* Block compression: if table is full and compression rate is dropping,
+ * clear the dictionary.
+ */
+
+#define LZW_RESERVED 0x60 /* reserved bits */
+
+#define CLEAR 256 /* flush the dictionary */
+#define FIRST (CLEAR+1) /* first free entry */
+
+#include <stdint.h>
+#include <ucontext.h>
+#include "zioP.h"
+
+#if defined _REENTRANT || defined _THREAD_SAFE
+# include <pthread.h>
+weak_symbol(pthread_sigmask);
+#endif
+
+__extension__
+static __inline__ int sigucmask(int how, const sigset_t * __restrict set, sigset_t * __restrict oset)
+{
+#if defined _REENTRANT || defined _THREAD_SAFE
+ if (&pthread_sigmask)
+ return pthread_sigmask(how, set, oset);
+ else
+#endif
+ return sigprocmask(how, set, oset);
+}
+
+#if defined(__ia64__) && defined(uc_sigmask) /* Broken header sys/ucontext.h -> bits/sigcontext.h */
+__extension__
+static __inline__ unsigned long int sig_ia64_mask(const sigset_t set)
+{
+ unsigned long int mask = 0;
+ int cnt = (8 * sizeof(unsigned long int));
+ if (cnt > NSIG) cnt = NSIG;
+ while (--cnt >= 0) {
+ if (!sigismember(&set, cnt))
+ continue;
+ mask |= (1 << (cnt - 1)); /* sigmask() macro is is not usable for BSD way */
+ }
+ return mask;
+}
+#endif
+
+typedef struct _LZW_s {
+ uint8_t *inbuf;
+ uint8_t *outbuf;
+ uint16_t *d_buf;
+ uint8_t *tab_suffix;
+ uint16_t *tab_prefix;
+ uint8_t *transfer;
+ off_t bytes_in;
+ off_t bytes_out;
+ size_t insize;
+ size_t inptr;
+ size_t outpos;
+ size_t tcount;
+ ssize_t tsize;
+ ssize_t rsize;
+ struct unlzw_s {
+ uint8_t *stackp;
+ int32_t code;
+ int finchar;
+ int32_t oldcode;
+ int32_t incode;
+ uint32_t inbits;
+ uint32_t posbits;
+ uint32_t bitmask;
+ int32_t free_ent;
+ int32_t maxcode;
+ int32_t maxmaxcode;
+ off_t newdif;
+ int n_bits;
+ int block_mode;
+ int maxbits;
+ } n;
+ int ifd;
+ char *ifname;
+ ucontext_t *uc;
+ uint8_t *stack;
+} LZW_t;
+
+extern LZW_t *openlzw(const char * __restrict, const char * __restrict);
+extern LZW_t *dopenlzw(int fildes, const char * __restrict);
+extern ssize_t readlzw(LZW_t * __restrict, char * __restrict, const size_t);
+extern void closelzw(LZW_t * __restrict);
diff --git a/tests.c b/tests.c
new file mode 100644
index 0000000..7512573
--- /dev/null
+++ b/tests.c
@@ -0,0 +1,28 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "zio.h"
+
+int main(int argc, char *argv[])
+{
+ FILE *file;
+ char line[1024];
+ size_t len;
+
+ if (!(file = fdzopen(fileno(stdin), "r", argc > 1 ? argv[1] : "g"))) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ return 1;
+ }
+
+ while ((len = fread(line, sizeof(char), sizeof (line), file))) {
+ size_t ret = fwrite(line, sizeof(char), len, stdout);
+ if ((ret != len) && ferror(stdout)) {
+ clearerr(stdout);
+ }
+ }
+
+ fclose(file);
+
+ return 0;
+}
diff --git a/testt.c b/testt.c
new file mode 100644
index 0000000..e64885d
--- /dev/null
+++ b/testt.c
@@ -0,0 +1,33 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "zio.h"
+
+int main(int argc, char *argv[])
+{
+ while (argc > 1) {
+ FILE *file;
+ char line[1024];
+ size_t len;
+
+ argv++;
+ argc--;
+
+ if (!(file = fzopen(*argv, "r"))) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ continue;
+ }
+
+ while ((len = fread(line, sizeof(char), sizeof (line), file))) {
+ size_t ret = fwrite(line, sizeof(char), len, stdout);
+ if ((ret != len) && ferror(stdout)) {
+ clearerr(stdout);
+ }
+ }
+
+ fclose(file);
+ }
+
+ return 0;
+}
diff --git a/unlzw.c b/unlzw.c
new file mode 100644
index 0000000..1741803
--- /dev/null
+++ b/unlzw.c
@@ -0,0 +1,464 @@
+/* unlzw.c -- decompress files in LZW format.
+ * The code in this file is directly derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * This is a temporary version which will be rewritten in some future version
+ * to accommodate in-memory decompression.
+ *
+ * Tue Dec 12 17:54:07 CET 2006 - werner@suse.de
+ * Be able to emulate a zlib-like behaviour: open, read, and close .Z files
+ * in memory. I'm using context switchting and a global allocated structure
+ * to be able to read during the main loop in unlzw() does its work. For this
+ * nearly _all_ variables affected by the context switch are forward to this
+ * structure, even the stack and the context type its self.
+ * The oringal source was adopted from the gzip version 1.3.7.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define DIST_BUFSIZE 0x2000
+#define INBUFSIZ 0x2000
+#define WSIZE 0x2000
+#define INBUF_EXTRA 0x40
+#define OUTBUFSIZ 0x2000
+#define OUTBUF_EXTRA 0x800
+#define STACK_SIZE 0x1000
+
+#include "lzw.h"
+
+static void unlzw(LZW_t *in);
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty.
+ * Adopted from gzip version 1.3.7 util.c
+ */
+__extension__
+static __inline__ int fill_inbuf(LZW_t *in)
+{
+ /* Read as much as possible */
+ in->insize = 0;
+ do {
+ ssize_t len = read(in->ifd, in->inbuf + in->insize, INBUFSIZ - in->insize);
+ if (len < 0) {
+ if (errno == EINTR)
+ continue;
+ perror(__FUNCTION__);
+ break;
+ }
+ if (len == 0)
+ break;
+ in->insize += len;
+ } while (in->insize < INBUFSIZ);
+
+ if (in->insize == 0)
+ return EOF;
+
+ in->bytes_in += (off_t)in->insize;
+ in->inptr = 1;
+ return (in->inbuf)[0];
+}
+
+/* ===========================================================================
+ * Does the same as write(), but also handles partial pipe writes and checks
+ * for error return.
+ * Adopted from gzip version 1.3.7 util.c
+ * Note that this version uses context switching, switch back to old context.
+ */
+__extension__
+static __inline__ void write_buf(LZW_t *in, const unsigned char* buf, size_t cnt)
+{
+ do {
+ if ((in->tsize = (in->tcount > cnt) ? cnt : in->tcount)) {
+ (void)memcpy(in->transfer, buf, in->tsize);
+ buf += in->tsize;
+ cnt -= in->tsize;
+ }
+ swapcontext(&in->uc[1], &in->uc[0]);
+ } while (cnt);
+}
+
+#define get_byte(in) ((in)->inptr < (in)->insize ? (in)->inbuf[(in)->inptr++] : fill_inbuf((in)))
+#define memzero(s,n) memset ((void*)(s), 0, (n))
+
+#define MAXCODE(n) (1L << (n))
+
+#ifndef BYTEORDER
+# define BYTEORDER 0000
+#endif
+
+#ifndef NOALLIGN
+# define NOALLIGN 0
+#endif
+
+
+union bytes {
+ long word;
+ struct {
+#if BYTEORDER == 4321
+ uint8_t b1;
+ uint8_t b2;
+ uint8_t b3;
+ uint8_t b4;
+#else
+#if BYTEORDER == 1234
+ uint8_t b4;
+ uint8_t b3;
+ uint8_t b2;
+ uint8_t b1;
+#else
+# undef BYTEORDER
+ int dummy;
+#endif
+#endif
+ } bytes;
+};
+
+#if BYTEORDER == 4321 && NOALLIGN == 1
+# define input(b,o,c,n,m){ \
+ (c) = (*(uint32_t *)(&(b)[(o)>>3])>>((o)&0x7))&(m); \
+ (o) += (n); \
+ }
+#else
+# define input(b,o,c,n,m){ \
+ uint8_t *p = &(b)[(o)>>3]; \
+ (c) = ((((long)(p[0]))|((long)(p[1])<<8)| \
+ ((long)(p[2])<<16))>>((o)&0x7))&(m); \
+ (o) += (n); \
+ }
+#endif
+
+#define tab_prefixof(i) in->tab_prefix[i]
+#define clear_tab_prefixof(in) memzero((in)->tab_prefix, sizeof(unsigned short)*(1<<(BITS)));
+#define de_stack ((uint8_t *)(&in->d_buf[DIST_BUFSIZE-1]))
+#define tab_suffixof(i) in->tab_suffix[i]
+
+/* ============================================================================
+ * Decompress in to out. This routine adapts to the codes in the
+ * file building the "string" table on-the-fly; requiring no table to
+ * be stored in the compressed file.
+ * IN assertions: the buffer inbuf contains already the beginning of
+ * the compressed data, from offsets iptr to insize-1 included.
+ * The magic header has already been checked and skipped.
+ * bytes_in and bytes_out have been initialized.
+ *
+ * Adopted from gzip version 1.3.7 unlzw.c
+ * This is mainly the head of the old unlzw() before its main loop.
+ */
+LZW_t *openlzw(const char * path, const char *mode)
+{
+ int fildes;
+ if (!mode || *mode != 'r')
+ goto out;
+ if ((fildes = open(path, O_RDONLY)) < 0)
+ goto out;
+ return dopenlzw(fildes, mode);
+out:
+ return (LZW_t*)0;
+}
+
+LZW_t *dopenlzw(int fildes, const char *mode)
+{
+ LZW_t *in = (LZW_t*)0;
+ uint8_t magic[2];
+ sigset_t sigmask, oldmask;
+
+ if (!mode || *mode != 'r')
+ goto out;
+
+ if ((in = (LZW_t*)malloc(sizeof(LZW_t))) == (LZW_t*)0)
+ goto err;
+ memset(in, 0, sizeof(LZW_t));
+
+ if ((in->inbuf = (uint8_t*)malloc(sizeof(uint8_t)*(INBUFSIZ))) == (uint8_t*)0)
+ goto err;
+ if ((in->outbuf = (uint8_t*)malloc(sizeof(uint8_t)*(OUTBUFSIZ+OUTBUF_EXTRA))) == (uint8_t*)0)
+ goto err;
+ if ((in->d_buf = (uint16_t*)malloc(sizeof(uint16_t)*DIST_BUFSIZE)) == (uint16_t*)0)
+ goto err;
+ if ((in->tab_suffix = (uint8_t*) malloc(sizeof(uint8_t )*(2L*WSIZE))) == (uint8_t*)0)
+ goto err;
+ if ((in->tab_prefix = (uint16_t*)malloc(sizeof(uint16_t)*(1<<(BITS)))) == (uint16_t*)0)
+ goto err;
+ if ((in->ifd = fildes) < 0)
+ goto err;
+
+ if ((in->stack = (uint8_t*)malloc(STACK_SIZE)) == (uint8_t*)0)
+ goto err;
+ if ((in->uc = (ucontext_t*)malloc(2*sizeof(ucontext_t))) == (ucontext_t*)0)
+ goto err;
+ if (getcontext(&in->uc[1]) < 0)
+ goto err;
+ in->uc[1].uc_link = &in->uc[0];
+ in->uc[1].uc_stack.ss_sp = in->stack;
+ in->uc[1].uc_stack.ss_size = STACK_SIZE;
+ if (sigucmask(SIG_SETMASK, (sigset_t*)0, &sigmask) < 0)
+ goto err;
+ if (sigaddset(&sigmask, SIGINT) < 0)
+ goto err;
+ if (sigaddset(&sigmask, SIGQUIT) < 0)
+ goto err;
+#if defined(__ia64__) && defined(uc_sigmask) /* On ia64 the type of uc_sigmask is ulong not sigset_t */
+ in->uc[1].uc_sigmask = sig_ia64_mask(sigmask);
+#else
+ in->uc[1].uc_sigmask = sigmask;
+#endif
+ makecontext(&in->uc[1], (void(*)(void))unlzw, 1, in);
+
+ sigucmask(SIG_SETMASK, &sigmask, &oldmask);
+ magic[0] = get_byte(in);
+ magic[1] = get_byte(in);
+ sigucmask(SIG_SETMASK, &oldmask, &sigmask);
+
+ if (memcmp(magic, LZW_MAGIC, sizeof(magic)))
+ goto err;
+
+ in->n.block_mode = BLOCK_MODE; /* block compress mode -C compatible with 2.0 */
+ in->rsize = in->insize;
+
+ in->n.maxbits = get_byte(in);
+ in->n.block_mode = in->n.maxbits & BLOCK_MODE;
+
+ if ((in->n.maxbits & LZW_RESERVED) != 0) {
+ fprintf(stderr, "%s: warning, unknown flags 0x%x\n",
+ __FUNCTION__, in->n.maxbits & LZW_RESERVED);
+ }
+ in->n.maxbits &= BIT_MASK;
+ in->n.maxmaxcode = MAXCODE(in->n.maxbits);
+
+ if (in->n.maxbits > BITS) {
+ fprintf(stderr, "%s: compressed with %d bits, can only handle %d bits\n",
+ __FUNCTION__, in->n.maxbits, BITS);
+ goto err;
+ }
+
+ in->n.maxcode = MAXCODE(in->n.n_bits = INIT_BITS)-1;
+ in->n.bitmask = (1<<in->n.n_bits)-1;
+ in->n.oldcode = -1;
+ in->n.finchar = 0;
+ in->n.posbits = in->inptr<<3;
+
+ in->n.free_ent = ((in->n.block_mode) ? FIRST : 256);
+
+ clear_tab_prefixof(in); /* Initialize the first 256 entries in the table. */
+
+ for (in->n.code = 255 ; in->n.code >= 0 ; --in->n.code) {
+ tab_suffixof(in->n.code) = (uint8_t)in->n.code;
+ }
+out:
+ return in;
+err:
+ closelzw(in);
+ return (LZW_t*)0;
+}
+
+/*
+ * New function, simply to free all allocated objects in
+ * reverse order and close the input file.
+ */
+void closelzw(LZW_t * in)
+{
+ if (in == (LZW_t*)0)
+ return;
+ if (in->uc) free(in->uc);
+ if (in->stack) free(in->stack);
+ if (in->ifd >= 0) close(in->ifd);
+ if (in->tab_prefix) free(in->tab_prefix);
+ if (in->tab_suffix) free(in->tab_suffix);
+ if (in->d_buf) free(in->d_buf);
+ if (in->outbuf) free(in->outbuf);
+ if (in->inbuf) free(in->inbuf);
+ free(in);
+ in = (LZW_t*)0;
+}
+
+/*
+ * Adopted from gzip version 1.3.7 unlzw.c
+ * This is mainly the body of the old unlzw() which is its main loop.
+ */
+static void unlzw(LZW_t *in)
+{
+ do {
+ int i;
+ int e;
+ int o;
+
+ resetbuf:
+ e = in->insize - (o = (in->n.posbits>>3));
+
+ for (i = 0 ; i < e ; ++i) {
+ in->inbuf[i] = in->inbuf[i+o];
+ }
+ in->insize = e;
+ in->n.posbits = 0;
+
+ if (in->insize < INBUF_EXTRA) {
+ do {
+ in->rsize = read(in->ifd, in->inbuf + in->insize, INBUFSIZ - in->insize);
+ if (in->rsize < 0) {
+ if (errno == EINTR)
+ continue;
+ perror(__FUNCTION__);
+ break;
+ }
+ if (in->rsize == 0)
+ break;
+ in->insize += in->rsize;
+ } while (in->insize < INBUFSIZ);
+ in->bytes_in += (off_t)in->insize;
+ }
+ in->n.inbits = ((in->rsize != 0) ? ((long)in->insize - in->insize%in->n.n_bits)<<3 :
+ ((long)in->insize<<3)-(in->n.n_bits-1));
+
+ while (in->n.inbits > in->n.posbits) {
+ if (in->n.free_ent > in->n.maxcode) {
+ in->n.posbits = ((in->n.posbits-1) +
+ ((in->n.n_bits<<3)-(in->n.posbits-1+(in->n.n_bits<<3))%(in->n.n_bits<<3)));
+ ++in->n.n_bits;
+ if (in->n.n_bits == in->n.maxbits) {
+ in->n.maxcode = in->n.maxmaxcode;
+ } else {
+ in->n.maxcode = MAXCODE(in->n.n_bits)-1;
+ }
+ in->n.bitmask = (1<<in->n.n_bits)-1;
+ goto resetbuf;
+ }
+ input(in->inbuf,in->n.posbits,in->n.code,in->n.n_bits,in->n.bitmask);
+
+ if (in->n.oldcode == -1) {
+ if (256 <= in->n.code)
+ fprintf(stderr, "%s: corrupt input.\n", __FUNCTION__);
+ in->outbuf[in->outpos++] = (uint8_t)(in->n.finchar = (int)(in->n.oldcode=in->n.code));
+ continue;
+ }
+ if (in->n.code == CLEAR && in->n.block_mode) {
+ clear_tab_prefixof(in);
+ in->n.free_ent = FIRST - 1;
+ in->n.posbits = ((in->n.posbits-1) +
+ ((in->n.n_bits<<3)-(in->n.posbits-1+(in->n.n_bits<<3))%(in->n.n_bits<<3)));
+ in->n.maxcode = MAXCODE(in->n.n_bits = INIT_BITS)-1;
+ in->n.bitmask = (1<<in->n.n_bits)-1;
+ goto resetbuf;
+ }
+ in->n.incode = in->n.code;
+ in->n.stackp = de_stack;
+
+ if (in->n.code >= in->n.free_ent) { /* Special case for KwKwK string. */
+ if (in->n.code > in->n.free_ent) {
+#ifdef DEBUG
+ uint8_t *p;
+ in->n.posbits -= in->n.n_bits;
+ p = &in->inbuf[in->n.posbits>>3];
+ fprintf(stderr,
+ "code:%ld free_ent:%ld n_bits:%d insize:%lu\n",
+ in->n.code, in->n.free_ent, in->n.n_bits, in->insize);
+ fprintf(stderr,
+ "posbits:%ld inbuf:%02X %02X %02X %02X %02X\n",
+ in->n.posbits, p[-1],p[0],p[1],p[2],p[3]);
+#endif
+ if (in->outpos > 0) {
+ write_buf(in, in->outbuf, in->outpos);
+ in->bytes_out += (off_t)in->outpos;
+ in->outpos = 0;
+ }
+ fprintf(stderr, "%s: corrupt input.\n", __FUNCTION__);
+ }
+ *--in->n.stackp = (uint8_t)in->n.finchar;
+ in->n.code = in->n.oldcode;
+ }
+
+ /* Generate output characters in reverse order */
+ while ((uint32_t)in->n.code >= (uint32_t)256) {
+ *--in->n.stackp = tab_suffixof(in->n.code);
+ in->n.code = tab_prefixof(in->n.code);
+ }
+ *--in->n.stackp = (uint8_t)(in->n.finchar = tab_suffixof(in->n.code));
+
+ /* And put them out in forward order */
+ if (in->outpos + (in->n.newdif = (de_stack - in->n.stackp)) >= OUTBUFSIZ) {
+ do {
+ if (in->n.newdif > OUTBUFSIZ - in->outpos)
+ in->n.newdif = OUTBUFSIZ - in->outpos;
+
+ if (in->n.newdif > 0) {
+ memcpy(in->outbuf + in->outpos, in->n.stackp, in->n.newdif);
+ in->outpos += in->n.newdif;
+ }
+ if (in->outpos >= OUTBUFSIZ) {
+ write_buf(in, in->outbuf, in->outpos);
+ in->bytes_out += (off_t)in->outpos;
+ in->outpos = 0;
+ }
+ in->n.stackp+= in->n.newdif;
+ } while ((in->n.newdif = (de_stack - in->n.stackp)) > 0);
+ } else {
+ memcpy(in->outbuf + in->outpos, in->n.stackp, in->n.newdif);
+ in->outpos += in->n.newdif;
+ }
+
+ if ((in->n.code = in->n.free_ent) < in->n.maxmaxcode) { /* Generate the new entry. */
+
+ tab_prefixof(in->n.code) = (uint16_t)in->n.oldcode;
+ tab_suffixof(in->n.code) = (uint8_t)in->n.finchar;
+ in->n.free_ent = in->n.code+1;
+ }
+ in->n.oldcode = in->n.incode; /* Remember previous code. */
+ }
+ } while (in->rsize != 0);
+
+ if (in->outpos > 0) {
+ write_buf(in, in->outbuf, in->outpos);
+ in->bytes_out += (off_t)in->outpos;
+ in->tsize = EOF;
+ in->outpos = 0;
+ }
+}
+
+/*
+ * New function, simply to read from the output buffer of unlzw().
+ * We do this by switching into the context of unlzw() and back
+ * to our old context if the provided buffer is filled.
+ */
+ssize_t readlzw(LZW_t * in, char* buffer, const size_t size)
+{
+ in->transfer = (uint8_t*)buffer;
+ in->tcount = size;
+ in->tsize = 0;
+ if (in->uc == (ucontext_t*)0)
+ return 0; /* For (f)lex scanner ... */
+ swapcontext(&in->uc[0], &in->uc[1]);
+ if (in->tsize < 0) {
+ free(in->uc); /* ... do not enter next */
+ in->uc = (ucontext_t*)0;
+ free(in->stack);
+ in->stack = (uint8_t*)0;
+ return 0;
+ }
+ return in->tsize;
+}
+
+#ifdef TEST
+int main()
+{
+ ssize_t len;
+ char buffer[1024];
+
+ LZW_t *lzw = openlzw("man.1.Z", "r");
+ if (!lzw)
+ return -1;
+
+ do {
+ len = readlzw(lzw, &buffer[0], sizeof(buffer));
+ write(1, &buffer[0], len);
+ } while (len != 0);
+
+ closelzw(lzw);
+ return 0;
+}
+#endif
diff --git a/zio.c b/zio.c
new file mode 100644
index 0000000..95788d2
--- /dev/null
+++ b/zio.c
@@ -0,0 +1,1208 @@
+/*
+ * zio.c Provide an streamable interface to gziped/bzip2ed/LZW/LZMA files
+ *
+ * Copyright 2004 Werner Fink, 2004 SuSE LINUX AG, Germany.
+ * Copyright 2006 Werner Fink, 2006 SuSE Products GmbH, Germany.
+ * Copyright 2009 Werner Fink, 2009 SuSE Products GmbH, Germany.
+ *
+ * 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.
+ *
+ * Author: Werner Fink <werner@suse.de>
+ */
+
+#include "zioP.h"
+#include "zio.h"
+#include "lzw.h"
+
+#if defined(HAS_ZLIB_H)
+static ssize_t zread(void *cookie, char *buf, size_t count)
+{
+ if (!cookie) {
+ errno = EINVAL;
+ return -1;
+ }
+ return (ssize_t)gzread((gzFile)cookie, (voidp)buf, count);
+}
+
+static ssize_t zwrite(void *cookie, const char *buf, size_t count)
+{
+ if (!cookie) {
+ errno = EINVAL;
+ return -1;
+ }
+ return (ssize_t)gzwrite((gzFile)cookie, (const voidp)buf, count);
+}
+
+static zio_int_t zseek(void *cookie, zio_off_t *poffset, int whence)
+{
+ if (!cookie) {
+ errno = EINVAL;
+ return -1;
+ }
+ return (zio_int_t)gzseek((gzFile)cookie, (z_off_t)(*poffset), whence);
+}
+
+static int zclose(void *cookie)
+{
+ int status;
+ if (!cookie) {
+ errno = EINVAL;
+ return -1;
+ }
+ (void)gzflush((gzFile)cookie, Z_FINISH);
+ status = gzclose((gzFile)cookie);
+ return (status >= 0) ? 0 : EOF;
+}
+
+__extension__
+static cookie_io_functions_t ioz = {
+ .read = (cookie_read_function_t*) &zread,
+ .write = (cookie_write_function_t*)&zwrite,
+ .seek = (cookie_seek_function_t*) &zseek,
+ .close = (cookie_close_function_t*)&zclose,
+};
+#else /* !HAS_ZLIB_H */
+# error No support for `.gz' nor `.z' format
+#endif /* !HAS_ZLIB_H */
+
+#if defined(HAS_BZLIB_H)
+# ifndef MIN
+# define MIN(x,y) ((x) < (y) ? (x) : (y))
+# endif
+
+typedef struct bzfile_s {
+ size_t total_out;
+ BZFILE *file;
+ char *mode;
+ char *path;
+ int fd;
+} bzfile_t;
+
+static ssize_t bzread(void *cookie, char *buf, size_t count)
+{
+ bzfile_t *bzf = (bzfile_t*)cookie;
+ ssize_t len = -1;
+ if (!bzf)
+ goto out;
+ if (bzf->file)
+ len = (ssize_t)BZ2_bzread(bzf->file, (void*)buf, count);
+ if (len > 0)
+ bzf->total_out += len;
+out:
+ if (len < 0)
+ errno = EINVAL;
+ return len;
+}
+
+static ssize_t bzwrite(void *cookie, const char *buf, size_t count)
+{
+ bzfile_t *bzf = (bzfile_t*)cookie;
+ ssize_t len = -1;
+ if (!bzf)
+ goto out;
+ if (bzf->file)
+ len = (ssize_t)BZ2_bzread(bzf->file, (void*)buf, count);
+ if (len > 0)
+ bzf->total_out += len;
+out:
+ if (len < 0)
+ errno = EINVAL;
+ return len;
+}
+
+static zio_int_t bzseek(void *cookie, zio_off_t *poffset, int whence)
+{
+ bzfile_t *bzf = (bzfile_t*)cookie;
+ off_t offset = (off_t)*poffset;
+ off_t oldpos, newpos;
+ if (!bzf) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ oldpos = (off_t)bzf->total_out;
+ switch (whence) {
+ case SEEK_SET:
+ if (offset < 0)
+ return -1;
+ newpos = offset;
+ break;
+ case SEEK_CUR:
+ if ((offset < 0 && (off_t)(-1 * offset) > oldpos) || (offset > 0 && (offset+oldpos) < oldpos))
+ return -1;
+ newpos = (off_t)bzf->total_out + offset;
+ break;
+ case SEEK_END:
+ newpos = -1;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (whence != SEEK_END && newpos < oldpos) {
+ int status = BZ2_bzflush(bzf->file);
+ BZ2_bzclose(bzf->file);
+ if (status < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (bzf->fd >= 0) {
+ lseek(bzf->fd, 0, SEEK_SET);
+ bzf->file = BZ2_bzdopen(bzf->fd, bzf->mode);
+ } else if (bzf->path) {
+ bzf->file = BZ2_bzopen(bzf->path, bzf->mode);
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+ if (bzf->file == (BZFILE*)0) {
+ errno = EINVAL;
+ return -1;
+ }
+ bzf->total_out = 0;
+ }
+ if (newpos == oldpos)
+ return oldpos;
+ else {
+ char buf[1<<12];
+ while (newpos > oldpos || newpos == -1) {
+ size_t req_size = MIN(sizeof(buf), newpos - oldpos);
+ ssize_t got_size = BZ2_bzread(bzf->file, buf, req_size);
+ if (got_size != (ssize_t)(req_size)) {
+ if (got_size < 0)
+ return -1;
+ else {
+ newpos = oldpos + got_size;
+ break;
+ }
+ }
+ oldpos += got_size;
+ }
+ return newpos;
+ }
+}
+
+static int bzclose(void *cookie)
+{
+ bzfile_t *bzf = (bzfile_t*)cookie;
+ int status = -1;
+ if (!bzf) {
+ errno = EINVAL;
+ goto out;
+ }
+ if (bzf->file) {
+ status = BZ2_bzflush(bzf->file);
+ BZ2_bzclose(bzf->file);
+ }
+ free(cookie);
+out:
+ return (status >= 0) ? 0 : EOF;
+}
+
+__extension__
+static cookie_io_functions_t iobz = {
+ .read = (cookie_read_function_t*) &bzread,
+ .write = (cookie_write_function_t*)&bzwrite,
+ .seek = (cookie_seek_function_t*) &bzseek,
+ .close = (cookie_close_function_t*)&bzclose,
+};
+#else /* !HAS_BZLIB_H */
+# warning No support for .bz2 format
+#endif /* !HAS_BZLIB_H */
+
+#if defined(HAS_LZMA_H)
+# ifndef MIN
+# define MIN(x,y) ((x) < (y) ? (x) : (y))
+# endif
+
+typedef struct lzfile_s {
+ uint8_t buf[1<<12];
+ lzma_stream strm;
+ FILE *file;
+ int encoding;
+ int level;
+ int what;
+ int eof;
+} lzfile_t;
+
+static lzma_ret lzmaopen(lzma_stream *__restrict strm, const char mode, const char what, int level)
+{
+ lzma_ret ret;
+ if (mode == 'w') {
+ if (what == 'x')
+ ret = lzma_easy_encoder(strm, level, LZMA_CHECK_CRC32);
+ else {
+ lzma_options_lzma opt;
+ lzma_lzma_preset(&opt, level);
+ ret = lzma_alone_encoder(strm, &opt);
+ }
+ } else
+ ret = lzma_auto_decoder(strm, 100<<20, 0);
+ return ret;
+}
+
+static ssize_t lzmaread(void *cookie, char *buf, size_t count)
+{
+ lzfile_t *lzma = (lzfile_t*)cookie;
+ lzma_stream *strm;
+ ssize_t eof = 0;
+ if (!lzma || lzma->encoding)
+ return -1;
+ if (lzma->eof)
+ return 0;
+ strm = &lzma->strm;
+
+ strm->next_out = (uint8_t*)buf;
+ strm->avail_out = count;
+ while (1) {
+ lzma_ret lret;
+ if (!strm->avail_in) {
+ strm->next_in = lzma->buf;
+ strm->avail_in = fread(lzma->buf, 1, sizeof(lzma->buf), lzma->file);
+ if (strm->avail_in == 0)
+ eof = 1;
+ }
+ lret = lzma_code(strm, LZMA_RUN);
+ if (lret == LZMA_STREAM_END) {
+ lzma->eof = 1;
+ return count - strm->avail_out;
+ }
+ if (lret != LZMA_OK)
+ return -1;
+ if (strm->avail_out == 0)
+ return count;
+ if (eof) {
+ eof = feof(lzma->file);
+ clearerr(lzma->file);
+ if (eof)
+ break;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static ssize_t lzmawrite(void *cookie, const char *buf, size_t count)
+{
+ lzfile_t *lzma = (lzfile_t*)cookie;
+ lzma_stream *strm;
+ if (!lzma || !lzma->encoding)
+ return -1;
+ if (!count)
+ return 0;
+ strm = &lzma->strm;
+
+ strm->next_in = (uint8_t*)buf;
+ strm->avail_in = count;
+ while (1) {
+ lzma_ret lret;
+ size_t len;
+ strm->next_out = lzma->buf;
+ strm->avail_out = sizeof(lzma->buf);
+ lret = lzma_code(strm, LZMA_RUN);
+ if (lret != LZMA_OK)
+ break;
+ len = sizeof(lzma->buf) - strm->avail_out;
+ if (len && fwrite(lzma->buf, 1, len, lzma->file) != len)
+ break;
+ if (strm->avail_in == 0)
+ return len;
+ }
+ return -1;
+}
+
+static zio_int_t lzmaseek(void *cookie, zio_off_t *poffset, int whence)
+{
+ lzfile_t *lzma = (lzfile_t*)cookie;
+ off_t offset = (off_t)*poffset;
+ lzma_stream *strm;
+ off_t oldpos, newpos;
+ if (!lzma)
+ return -1;
+ strm = &lzma->strm;
+
+ oldpos = (off_t)strm->total_out;
+ switch (whence) {
+ case SEEK_SET:
+ if (offset < 0)
+ return -1;
+ newpos = offset;
+ break;
+ case SEEK_CUR:
+ if ((offset < 0 && (off_t)(-1 * offset) > oldpos) || (offset > 0 && (offset+oldpos) < oldpos))
+ return -1;
+ newpos = (off_t)strm->total_out + offset;
+ break;
+ case SEEK_END:
+ newpos = -1;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (whence != SEEK_END && newpos < oldpos) {
+ lzma_ret ret;
+ lzma_end(strm);
+ rewind(lzma->file);
+ ret = lzmaopen(strm, lzma->encoding ? 'w' : 'r', lzma->what, lzma->level);
+ if (ret != LZMA_OK || strm->total_out != 0) {
+ fclose(lzma->file);
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ if (newpos == oldpos)
+ return oldpos;
+ else {
+ char buf[sizeof(lzma->buf)];
+ while (newpos > oldpos || newpos == -1) {
+ size_t req_size = MIN(sizeof(buf), newpos - oldpos);
+ ssize_t got_size = lzmaread(cookie, buf, req_size);
+ if (got_size != (ssize_t)(req_size)) {
+ if (got_size < 0)
+ return -1;
+ else {
+ newpos = oldpos + got_size;
+ break;
+ }
+ }
+ oldpos += got_size;
+ }
+ return newpos;
+ }
+}
+
+static int lzmaclose(void *cookie)
+{
+ lzfile_t *lzma = (lzfile_t*)cookie;
+ lzma_ret lret = LZMA_STREAM_END;
+ lzma_stream *strm;
+ int fret = -1;
+ if (!lzma)
+ return -1;
+ if (!lzma->encoding)
+ goto out;
+ strm = &lzma->strm;
+ while (1) {
+ size_t len;
+ strm->avail_out = sizeof(lzma->buf);
+ strm->next_out = (uint8_t*)lzma->buf;
+ lret = lzma_code(strm, LZMA_FINISH);
+ if (lret != LZMA_OK && lret != LZMA_STREAM_END)
+ goto out;
+ len = sizeof(lzma->buf) - strm->avail_out;
+ if (len && fwrite(lzma->buf, 1, len, lzma->file) != len)
+ goto out;
+ if (lret == LZMA_STREAM_END)
+ break;
+ }
+ lzma_end(strm);
+out:
+ fret = fclose(lzma->file);
+ free(lzma);
+ if (lret != LZMA_STREAM_END)
+ fret = -1;
+ return fret;
+}
+
+__extension__
+static cookie_io_functions_t iolzma = {
+ .read = (cookie_read_function_t*) &lzmaread,
+ .write = (cookie_write_function_t*)&lzmawrite,
+ .seek = (cookie_seek_function_t*) &lzmaseek,
+ .close = (cookie_close_function_t*)&lzmaclose,
+};
+#else /* !HAS_LZMA_H */
+# if defined(HAS_LZMADEC_H)
+static ssize_t lzmaread(void *cookie, char *buf, size_t count)
+{
+ if (!cookie) {
+ errno = EINVAL;
+ return -1;
+ }
+ return lzmadec_read((lzmadec_FILE*)cookie, (uint8_t*)buf, count);
+}
+
+static ssize_t lzmawrite(void *cookie, const char *buf, size_t count)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+static zio_int_t lzmaseek(void *cookie, zio_off_t *poffset, int whence)
+{
+ if (!cookie) {
+ errno = EINVAL;
+ return -1;
+ }
+ return (zio_int_t)lzmadec_seek((lzmadec_FILE*)cookie, (off_t)(*poffset), whence);
+}
+
+static int lzmaclose(void *cookie)
+{
+ if (!cookie) {
+ errno = EINVAL;
+ return -1;
+ }
+ int_fast8_t status = lzmadec_close((lzmadec_FILE*)cookie);
+ return (status >= 0) ? 0 : EOF;
+}
+
+__extension__
+static cookie_io_functions_t iolzma = {
+ .read = (cookie_read_function_t*) &lzmaread,
+ .write = (cookie_write_function_t*)&lzmawrite,
+ .seek = (cookie_seek_function_t*) &lzmaseek,
+ .close = (cookie_close_function_t*)&lzmaclose,
+};
+# else /* !HAS_LZMADEC_H */
+# warning No support for .lzma format
+# endif /* !HAS_LZMADEC_H */
+#endif /* !HAS_LZMA_H */
+
+typedef struct lzwfile_s {
+ size_t total_out;
+ LZW_t *file;
+ char *mode;
+ char *path;
+ int fd;
+} lzwfile_t;
+
+static ssize_t lzwread(void *cookie, char *buf, size_t count)
+{
+ lzwfile_t *lzw = (lzwfile_t*)cookie;
+ ssize_t len = -1;
+ if (!lzw)
+ goto out;
+ if (lzw->file)
+ len = readlzw(lzw->file, buf, count);
+ if (len > 0)
+ lzw->total_out += len;
+out:
+ if (len < 0)
+ errno = EINVAL;
+ return len;
+}
+
+static ssize_t lzwwrite(void *cookie, const char *buf, size_t count)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+static zio_int_t lzwseek(void *cookie, zio_off_t *poffset, int whence)
+{
+ lzwfile_t *lzw = (lzwfile_t*)cookie;
+ off_t offset = (off_t)*poffset;
+ off_t oldpos, newpos;
+ if (!lzw) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ oldpos = (off_t)lzw->total_out;
+ switch (whence) {
+ case SEEK_SET:
+ if (offset < 0)
+ return -1;
+ newpos = offset;
+ break;
+ case SEEK_CUR:
+ if ((offset < 0 && (off_t)(-1 * offset) > oldpos) || (offset > 0 && (offset+oldpos) < oldpos))
+ return -1;
+ newpos = (off_t)lzw->total_out + offset;
+ break;
+ case SEEK_END:
+ newpos = -1;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (whence != SEEK_END && newpos < oldpos) {
+ closelzw(lzw->file);
+ if (lzw->fd >= 0) {
+ lseek(lzw->fd, 0, SEEK_SET);
+ lzw->file = dopenlzw(lzw->fd, lzw->mode);
+ } else if (lzw->path) {
+ lzw->file = openlzw(lzw->path, lzw->mode);
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+ if (lzw->file == (LZW_t*)0) {
+ errno = EINVAL;
+ return -1;
+ }
+ lzw->total_out = 0;
+ }
+ if (newpos == oldpos)
+ return oldpos;
+ else {
+ char buf[1<<12];
+ while (newpos > oldpos || newpos == -1) {
+ size_t req_size = MIN(sizeof(buf), newpos - oldpos);
+ ssize_t got_size = readlzw(lzw->file, buf, req_size);
+ if (got_size != (ssize_t)(req_size)) {
+ if (got_size < 0)
+ return -1;
+ else {
+ newpos = oldpos + got_size;
+ break;
+ }
+ }
+ oldpos += got_size;
+ }
+ return newpos;
+ }
+}
+
+static int lzwclose(void *cookie)
+{
+ lzwfile_t *lzw = (lzwfile_t*)cookie;
+ if (!lzw) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (lzw->file)
+ closelzw(lzw->file);
+ free(cookie);
+ return 0;
+}
+
+__extension__
+static cookie_io_functions_t iolzw = {
+ .read = (cookie_read_function_t*) &lzwread,
+ .write = (cookie_write_function_t*)&lzwwrite,
+ .seek = (cookie_seek_function_t*) &lzwseek,
+ .close = (cookie_close_function_t*)&lzwclose,
+};
+
+static inline char autodetect(char **__restrict path, const char *__restrict check)
+{
+ const size_t len = strlen(*path);
+ char *suff = strrchr(*path, '.');
+ char *ext = *path;
+ char what = 'n';
+
+ if (suff) {
+ suff++;
+ if (strcmp(suff, "z" ) == 0)
+ what = 'z';
+ else if (strcmp(suff, "gz" ) == 0)
+ what = 'g';
+ else if (strcmp(suff, "Z" ) == 0)
+ what = 'Z';
+ else if (strcmp(suff, "bz2" ) == 0)
+ what = 'b';
+ else if (strcmp(suff, "lzma") == 0)
+ what = 'l';
+ else if (strcmp(suff, "xz" ) == 0)
+ what = 'x';
+ }
+
+ if (what == 'n' && *check == 'r') {
+ int olderr, fd;
+ struct stat st;
+ char m[5];
+ ext = malloc(sizeof(char)*(len + 5 + 1));
+ if (!ext)
+ goto out;
+ strcpy(ext, *path);
+ suff = (ext+len);
+
+ olderr = errno;
+ if (stat(strcat(ext, ".gz"), &st) == 0) {
+ what = 'g';
+ goto skip;
+ }
+ *suff = '\0';
+ if (stat(strcat(ext, ".bz2"), &st) == 0) {
+ what = 'b';
+ goto skip;
+ }
+ *suff = '\0';
+ if (stat(strcat(ext, ".z"), &st) == 0) {
+ what = 'z';
+ goto skip;
+ }
+ *suff = '\0';
+ if (stat(strcat(ext, ".Z"), &st) == 0) {
+ what = 'Z';
+ goto skip;
+ }
+ *suff = '\0';
+ if (stat(strcat(ext, ".lzma"), &st) == 0) {
+ what = 'l';
+ goto skip;
+ }
+ *suff = '\0';
+ if (stat(strcat(ext, ".xz"), &st) == 0) {
+ what = 'x';
+ goto skip;
+ }
+ *suff = '\0';
+
+ if ((fd = open(ext, O_RDONLY|O_NOCTTY)) < 0)
+ goto skip;
+ if (read(fd, m, sizeof(m)) == sizeof(m)) {
+ if (m[0] == '\037' && m[1] == '\213')
+ what = 'g';
+ if (m[0] == '\037' && m[1] == '\235')
+ what = 'Z';
+ if (m[0] == '\037' && m[1] == '\236')
+ what = 'z';
+ else if (m[0] == 'B' && m[1] == 'Z' && m[2] == 'h')
+ what = 'b';
+ else if (m[0] == ']' && m[1] == '\0' && m[2] == '\0' && m[3] == '\200') /* weak!! */
+ what = 'l';
+ else if (m[0] == '\377' && m[1] == 'L' && m[2] == 'Z' && m[3] == 'M' && m[4] == 'A')
+ what = 'l';
+ else if (m[0] == '\375' && m[1] == '7' && m[2] == 'z' && m[3] == 'X' && m[4] == 'Z')
+ what = 'x';
+ }
+ close(fd);
+ skip:
+ errno = olderr;
+ }
+out:
+ *path = ext;
+ return what;
+}
+
+FILE * fzopen(const char * path, const char * mode)
+{
+ FILE * ret = (FILE *)0;
+ char * check = (char*)0, * ext = (char*)0;
+ size_t n = 0, len;
+ unsigned int i;
+ char what = 'n';
+
+ if (!mode || !(n = strlen(mode))) {
+ errno = EINVAL;
+ goto out;
+ }
+
+ if (!(check = (char*)malloc(n*sizeof(char))))
+ goto out;
+
+ /* No append mode possible */
+ switch (*mode) {
+ case 'r': check[0] = 'r'; break;
+ case 'w': check[0] = 'w'; break;
+ default: errno = EINVAL; goto out;
+ }
+
+ for (i = 1; i < n; i++) {
+ /* We can only open for reading OR writing but NOT for both */
+ switch (mode[i]) {
+ case '\0': break;
+ case '+': errno = EINVAL; goto out;
+ case 'b': case 'x': check[i] = mode[i]; continue;
+ /* Ingore switches for gzopen() */
+ case 'f': case 'h': check[i] = '\0'; continue;
+ default: check[i] = '\0'; continue;
+ }
+ break;
+ }
+
+ if (!path || !(len = strlen(path))) {
+ errno = EINVAL;
+ goto out;
+ }
+
+ ext = (char *)path;
+ what = autodetect(&ext, check);
+
+ switch (what) {
+ case 'g':
+ case 'z': /* Is this correct? Old gzip magic */
+#if defined(HAS_ZLIB_H)
+ {
+ gzFile cookie;
+
+ if (&gzopen == NULL) {
+ errno = ENOSYS;
+ goto out;
+ }
+
+ if (!(cookie = gzopen(ext, mode))) {
+ if (!errno)
+ errno = ENOMEM;
+ goto out;
+ }
+
+ if (!(ret = fopencookie((void*)cookie, check, ioz))) {
+ gzclose(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+# ifndef LIBIO_IS_FIXED
+ if (ret->_fileno < 0)
+ ret->_fileno = 0;
+# endif
+ }
+#else /* !HAS_ZLIB_H */
+ errno = ENOTSUP;
+#endif /* !HAS_ZLIB_H */
+ break;
+ case 'Z':
+ {
+ lzwfile_t *__restrict cookie;
+ if (*mode != 'r') {
+ errno = ENOTSUP;
+ goto out;
+ }
+
+ if (posix_memalign((void*)&cookie, sizeof(void*), alignof(lzwfile_t)+strsize(ext)+strsize(mode)) != 0)
+ goto out;
+ memset(cookie, 0, alignof(lzwfile_t)+strsize(ext)+strsize(mode));
+
+ cookie->fd = -1;
+ cookie->mode = ((char*)cookie)+alignof(lzwfile_t);
+ cookie->path = cookie->mode + strsize(mode);
+ strcpy(cookie->mode, mode);
+ strcpy(cookie->path, ext);
+
+ if (!(cookie->file = openlzw(ext, mode))) {
+ free(cookie);
+ if (!errno)
+ errno = ENOMEM;
+ goto out;
+ }
+
+ if (!(ret = fopencookie((void*)cookie, check, iolzw))) {
+ closelzw(cookie->file);
+ free(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+# ifndef LIBIO_IS_FIXED
+ if (ret->_fileno < 0)
+ ret->_fileno = 0;
+# endif
+ }
+ break;
+ case 'b':
+#if defined(HAS_BZLIB_H)
+ {
+ bzfile_t *__restrict cookie;
+ int level = 5;
+
+ if (&BZ2_bzopen == NULL) {
+ errno = ENOSYS;
+ goto out;
+ }
+
+ if (posix_memalign((void*)&cookie, sizeof(void*), alignof(bzfile_t)+strsize(ext)+strsize(mode)) != 0)
+ goto out;
+ memset(cookie, 0, alignof(bzfile_t)+strsize(ext)+strsize(mode));
+
+ for (i = 1; i < n; i++) {
+ if (mode[i] >= '0' && mode[i] <= '9') {
+ level = (int)mode[i];
+ break;
+ }
+ }
+
+ cookie->fd = -1;
+ cookie->mode = ((char*)cookie)+alignof(bzfile_t);
+ cookie->path = cookie->mode+strsize(mode);
+ strcpy(cookie->mode, mode);
+ strcpy(cookie->path, ext);
+
+ if (!(cookie->file = BZ2_bzopen(ext, mode))) {
+ free(cookie);
+ if (!errno)
+ errno = ENOMEM;
+ goto out;
+ }
+
+ if (!(ret = fopencookie((void*)cookie, check, iobz))) {
+ BZ2_bzclose(cookie->file);
+ free(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+# ifndef LIBIO_IS_FIXED
+ if (ret->_fileno < 0)
+ ret->_fileno = 0;
+# endif
+ }
+#else /* !HAS_BZLIB_H */
+ errno = ENOTSUP;
+#endif /* !HAS_BZLIB_H */
+ break;
+#if defined(HAS_LZMA_H)
+ case 'l':
+ case 'x':
+ {
+ int level = LZMA_PRESET_DEFAULT;
+ lzfile_t *__restrict cookie;
+ lzma_ret lret;
+
+ if (&lzma_auto_decoder == NULL) {
+ errno = ENOSYS;
+ goto out;
+ }
+
+ if (posix_memalign((void*)&cookie, sizeof(void*), alignof(lzfile_t)) != 0)
+ goto out;
+ memset(cookie, 0, alignof(lzfile_t));
+
+ if ((cookie->file = fopen(ext, check)) == NULL) {
+ free(cookie);
+ goto out;
+ }
+
+ for (i = 1; i < n; i++) {
+ if (mode[i] >= '0' && mode[i] <= '9') {
+ level = (int)mode[i];
+ break;
+ }
+ }
+
+ cookie->eof = 0;
+ cookie->what = what;
+ cookie->strm = (lzma_stream)LZMA_STREAM_INIT;
+ cookie->level = level;
+ cookie->encoding = (check[0] == 'w') ? 1 : 0;
+ lret = lzmaopen(&cookie->strm, check[0], what, level);
+
+ if (lret != LZMA_OK) {
+ fclose(cookie->file);
+ free(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+ if (!(ret = fopencookie((void*)cookie, check, iolzma))) {
+ lzma_end(&cookie->strm);
+ fclose(cookie->file);
+ free(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+# ifndef LIBIO_IS_FIXED
+ if (ret->_fileno < 0)
+ ret->_fileno = 0;
+# endif
+ }
+ break;
+#else /* !HAS_LZMA_H */
+ case 'x':
+ errno = ENOTSUP;
+ break;
+ case 'l':
+# if defined(HAS_LZMADEC_H)
+ {
+ lzmadec_FILE* cookie;
+
+ if (*mode != 'r') {
+ errno = ENOTSUP;
+ goto out;
+ }
+
+ if (&lzmadec_open == NULL) {
+ errno = ENOSYS;
+ goto out;
+ }
+
+ if (!(cookie = lzmadec_open(ext))) {
+ if (!errno)
+ errno = ENOMEM;
+ goto out;
+ }
+
+ if (!(ret = fopencookie((void*)cookie, check, iolzma))) {
+ lzmadec_close(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+# ifndef LIBIO_IS_FIXED
+ if (ret->_fileno < 0)
+ ret->_fileno = 0;
+# endif
+ }
+# else /* !HAS_LZMADEC_H */
+ errno = ENOTSUP;
+# endif /* !HAS_LZMADEC_H */
+#endif /* !HAS_LZMA_H */
+ break;
+ default:
+ ret = fopen(ext, mode);
+ break;
+ }
+
+out:
+ if (check)
+ free(check);
+ if (ext && ext != path)
+ free(ext);
+
+ return ret;
+}
+
+FILE * fdzopen(int fildes, const char * mode, const char *what)
+{
+ FILE * ret = (FILE *)0;
+ char * check = (char*)0;
+ size_t n = 0;
+ unsigned int i;
+
+ if (!mode || !(n = strlen(mode))) {
+ errno = EINVAL;
+ goto out;
+ }
+
+ if (!(check = (char*)malloc(n*sizeof(char))))
+ goto out;
+
+ /* No append mode possible */
+ switch (*mode) {
+ case 'r': check[0] = 'r'; break;
+ case 'w': check[0] = 'w'; break;
+ default: errno = EINVAL; goto out;
+ }
+
+ for (i = 1; i < n; i++) {
+ /* We can only open for reading OR writing but NOT for both */
+ switch (mode[i]) {
+ case '\0': break;
+ case '+': errno = EINVAL; goto out;
+ case 'b': case 'x': check[i] = mode[i]; continue;
+ /* Ingore switches for gzopen() */
+ case 'f': case 'h': check[i] = '\0'; continue;
+ default: check[i] = '\0'; continue;
+ }
+ break;
+ }
+
+ switch (*what) {
+ case 'g':
+ case 'z': /* Is this correct? Old gzip magic */
+#if defined(HAS_ZLIB_H)
+ {
+ gzFile cookie;
+
+ if (&gzdopen == NULL) {
+ errno = ENOSYS;
+ goto out;
+ }
+
+ if (!(cookie = gzdopen(fildes, mode))) {
+ if (!errno)
+ errno = ENOMEM;
+ goto out;
+ }
+
+ if (!(ret = fopencookie((void*)cookie, check, ioz))) {
+ gzclose(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+# ifndef LIBIO_IS_FIXED
+ if (ret->_fileno < 0)
+ ret->_fileno = 0;
+# endif
+ }
+#else /* !HAS_ZLIB_H */
+ errno = ENOTSUP;
+#endif /* !HAS_ZLIB_H */
+ break;
+ case 'Z':
+ {
+ lzwfile_t *__restrict cookie;
+ if (*mode != 'r') {
+ errno = ENOTSUP;
+ goto out;
+ }
+
+ if (posix_memalign((void*)&cookie, sizeof(void*), alignof(lzwfile_t)+strsize(mode)) != 0)
+ goto out;
+ memset(cookie, 0, alignof(lzwfile_t)+strsize(mode));
+
+ cookie->fd = fildes;
+ cookie->mode = ((char*)cookie)+alignof(lzwfile_t);
+ strcpy(cookie->mode, mode);
+
+ if (!(cookie->file = dopenlzw(fildes, mode))) {
+ free(cookie);
+ if (!errno)
+ errno = ENOMEM;
+ goto out;
+ }
+
+ if (!(ret = fopencookie((void*)cookie, check, iolzw))) {
+ closelzw(cookie->file);
+ free(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+# ifndef LIBIO_IS_FIXED
+ if (ret->_fileno < 0)
+ ret->_fileno = 0;
+# endif
+ }
+ break;
+ case 'b':
+#if defined(HAS_BZLIB_H)
+ {
+ bzfile_t *__restrict cookie;
+ int level = 5;
+
+ if (&BZ2_bzdopen == NULL) {
+ errno = ENOSYS;
+ goto out;
+ }
+
+ if (posix_memalign((void*)&cookie, sizeof(void*), alignof(bzfile_t)+strsize(mode)) != 0)
+ goto out;
+ memset(cookie, 0, alignof(bzfile_t)+strsize(mode));
+
+ for (i = 1; i < n; i++) {
+ if (mode[i] >= '0' && mode[i] <= '9') {
+ level = (int)mode[i];
+ break;
+ }
+ }
+
+ cookie->fd = fildes;
+ cookie->mode = ((char*)cookie)+alignof(bzfile_t);
+ strcpy(cookie->mode, mode);
+
+ if (cookie->mode == (char*)0) {
+ free(cookie);
+ goto out;
+ }
+ if (!(cookie->file = BZ2_bzdopen(fildes, mode))) {
+ free(cookie);
+ if (!errno)
+ errno = ENOMEM;
+ goto out;
+ }
+
+ if (!(ret = fopencookie((void*)cookie, check, iobz))) {
+ BZ2_bzclose(cookie->file);
+ free(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+# ifndef LIBIO_IS_FIXED
+ if (ret->_fileno < 0)
+ ret->_fileno = 0;
+# endif
+ }
+#else /* !HAS_BZLIB_H */
+ errno = ENOTSUP;
+#endif /* !HAS_BZLIB_H */
+ break;
+#if defined(HAS_LZMA_H)
+ case 'l':
+ case 'x':
+ {
+ int level = LZMA_PRESET_DEFAULT;
+ lzfile_t *__restrict cookie;
+ lzma_ret lret;
+
+ if (&lzma_auto_decoder == NULL) {
+ errno = ENOSYS;
+ goto out;
+ }
+
+ if (posix_memalign((void*)&cookie, sizeof(void*), alignof(lzfile_t)) != 0)
+ goto out;
+ memset(cookie, 0, alignof(lzfile_t));
+
+ if ((cookie->file = fdopen(fildes, check)) == NULL) {
+ free(cookie);
+ goto out;
+ }
+
+ for (i = 1; i < n; i++) {
+ if (mode[i] >= '0' && mode[i] <= '9') {
+ level = (int)mode[i];
+ break;
+ }
+ }
+
+ cookie->eof = 0;
+ cookie->what = *what;
+ cookie->strm = (lzma_stream)LZMA_STREAM_INIT;
+ cookie->level = level;
+ cookie->encoding = (check[0] == 'w') ? 1 : 0;
+ lret = lzmaopen(&cookie->strm, check[0], *what, level);
+ if (lret != LZMA_OK) {
+ fclose(cookie->file);
+ free(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+ if (!(ret = fopencookie((void*)cookie, check, iolzma))) {
+ lzma_end(&cookie->strm);
+ fclose(cookie->file);
+ free(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+# ifndef LIBIO_IS_FIXED
+ if (ret->_fileno < 0)
+ ret->_fileno = 0;
+# endif
+ }
+ break;
+#else /* !HAS_LZMA_H */
+ case 'x':
+ errno = ENOTSUP;
+ break;
+ case 'l':
+# if defined(HAS_LZMADEC_H)
+ {
+ lzmadec_FILE* cookie;
+
+ if (*mode != 'r') {
+ errno = ENOTSUP;
+ goto out;
+ }
+
+ if (&lzmadec_open == NULL) {
+ errno = ENOSYS;
+ goto out;
+ }
+
+ if (!(cookie = lzmadec_dopen(fildes))) {
+ if (!errno)
+ errno = ENOMEM;
+ goto out;
+ }
+
+ if (!(ret = fopencookie((void*)cookie, check, iolzma))) {
+ lzmadec_close(cookie);
+ errno = EINVAL;
+ goto out;
+ }
+# ifndef LIBIO_IS_FIXED
+ if (ret->_fileno < 0)
+ ret->_fileno = 0;
+# endif
+ }
+# else /* !HAS_LZMADEC_H */
+ errno = ENOTSUP;
+# endif /* !HAS_LZMADEC_H */
+#endif /* !HAS_LZMA_H */
+ break;
+ default:
+ ret = fdopen(fildes, mode);
+ break;
+ }
+
+out:
+ if (check)
+ free(check);
+ return ret;
+}
diff --git a/zio.h.in b/zio.h.in
new file mode 100644
index 0000000..78f5b22
--- /dev/null
+++ b/zio.h.in
@@ -0,0 +1,33 @@
+/*
+ * zio.h Provide an streamable interface to gziped/bzip2ed files
+ *
+ * Copyright 2004 Werner Fink, 2004 SuSE LINUX AG, Germany.
+ *
+ * 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.
+ *
+ * Author: Werner Fink <werner@suse.de>
+ */
+
+#ifndef _ZIO_H
+#define _ZIO_H
+
+#include <stdio.h>
+#define ZIO_VERSION @@VERSION@@
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * This function can open a gziped file for reading OR writing, but
+ * NOT both (not `+' possible) NOR can it open for appending (no `a').
+ */
+extern FILE *fzopen __P((__const char *__restrict, __const char *__restrict));
+extern FILE *fdzopen __P((int, __const char *__restrict mode, __const char *__restrict));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZIO_H */
diff --git a/zio.map b/zio.map
new file mode 100644
index 0000000..a77c3aa
--- /dev/null
+++ b/zio.map
@@ -0,0 +1,7 @@
+{
+global:
+ fzopen;
+ fdzopen;
+local:
+ *;
+};
diff --git a/zioP.h b/zioP.h
new file mode 100644
index 0000000..b6d85cb
--- /dev/null
+++ b/zioP.h
@@ -0,0 +1,165 @@
+/*
+ * zioP.h Internal header for libzio, including required
+ * standard glibc header, zlib.h, and bzlib.h.
+ * Making the used libz and bzlib functions weak symbols.
+ *
+ * Copyright 2004 Werner Fink, 2004 SuSE LINUX AG, Germany.
+ * Copyright 2006 Werner Fink, 2006 SuSE Products GmbH, Germany.
+ *
+ * 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.
+ *
+ * Author: Werner Fink <werner@suse.de>
+ */
+
+#ifndef _ZIO_P_H
+#define _ZIO_P_H
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#ifdef HAVE_LIBIO_H
+# include <libio.h>
+#endif
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#ifndef unused
+# define unused __attribute__((__unused__))
+#endif
+#ifndef nonnull
+# define nonnull(parm) __attribute__((__nonnull__ parm))
+#endif
+#ifndef wur
+# define wur __attribute__((__warn_unused_result__))
+#endif
+#define alignof(type) (sizeof(type)+(sizeof(type)%sizeof(void*)))
+#define strsize(str) ((strlen(str)+1)*sizeof(char))
+
+#if !defined(HAVE_FOPENCOOKIE) && !defined(HAVE_FUNOPEN)
+# error Requires fopencookie(3GNU) or funopen(3BSD)
+#endif
+
+#if defined(HAVE_LIBIO_H) || defined(HAVE_FOPENCOOKIE)
+# if defined __GLIBC__ && __GLIBC__ > 1
+# undef LIBIO_IS_FIXED
+# if __GLIBC__ > 2 || (__GLIBC__ >= 2 && __GLIBC_MINOR__ > 0)
+# define LIBIO_IS_FIXED
+# endif
+# else
+# error The libzio requires the GLIBC
+# endif
+#endif
+
+#if defined __GNUC__
+# if defined __USE_ISOC99
+# define _cat_pragma(exp) _Pragma(#exp)
+# define _weak_pragma(exp) _cat_pragma(weak name)
+# else
+# define _weak_pragma(exp)
+# endif
+# define _declare(name) __extension__ extern __typeof__(name) name
+# define weak_symbol(name) _weak_pragma(name) _declare(name) __attribute__((weak))
+#else
+# error The libzio requires the GCC
+#endif
+
+#if defined(HAS_ZLIB_H)
+# include <zlib.h>
+# ifndef NO_WEAK
+weak_symbol(gzopen);
+weak_symbol(gzdopen);
+weak_symbol(gzread);
+weak_symbol(gzwrite);
+weak_symbol(gzseek);
+weak_symbol(gzflush);
+weak_symbol(gzclose);
+# endif
+#endif
+
+#if defined(HAS_BZLIB_H)
+# include <bzlib.h>
+# ifndef NO_WEAK
+weak_symbol(BZ2_bzopen);
+weak_symbol(BZ2_bzdopen);
+weak_symbol(BZ2_bzread);
+weak_symbol(BZ2_bzwrite);
+/* no BZ2_bzseek */
+weak_symbol(BZ2_bzflush);
+weak_symbol(BZ2_bzclose);
+# endif
+#endif
+
+#if defined(HAS_LZMA_H)
+# include <stdint.h>
+# include <lzma.h>
+# ifndef NO_WEAK
+weak_symbol(lzma_easy_encoder);
+weak_symbol(lzma_lzma_preset);
+weak_symbol(lzma_alone_encoder);
+weak_symbol(lzma_auto_decoder);
+weak_symbol(lzma_code);
+weak_symbol(lzma_end);
+# endif
+#else /* !HAS_LZMA_H */
+# if defined(HAS_LZMADEC_H)
+# include <stdint.h>
+# include <lzmadec.h>
+# ifndef NO_WEAK
+weak_symbol(lzmadec_open);
+weak_symbol(lzmadec_dopen);
+weak_symbol(lzmadec_read);
+/* no lzmadec_write() */
+weak_symbol(lzmadec_seek);
+weak_symbol(lzmadec_close);
+/* no lzmadec_flush() */
+# endif
+# endif
+#endif /* !HAS_LZMA_H */
+
+#if defined(HAVE_FOPENCOOKIE)
+# undef HAVE_FUNOPEN
+__extension__ typedef off_t zio_off_t;
+__extension__ typedef int zio_int_t;
+# if !defined(LIBIO_IS_FIXED)
+__extension__ typedef _IO_cookie_io_functions_t cookie_io_functions_t;
+__extension__ typedef ssize_t cookie_read_function_t __P ((void *, char *, size_t));
+__extension__ typedef ssize_t cookie_write_function_t __P ((void *, const char *, size_t));
+__extension__ typedef int cookie_seek_function_t __P ((void *, off_t, int));
+__extension__ typedef int cookie_close_function_t __P ((void *));
+# endif
+#endif
+#if defined(HAVE_FUNOPEN)
+__extension__ typedef size_t zio_off_t;
+__extension__ typedef fpos_t zio_int_t;
+__extension__ typedef int cookie_read_function_t __P ((void *, char *, int));
+__extension__ typedef int cookie_write_function_t __P ((void *, const char *, int));
+__extension__ typedef fpos_t cookie_seek_function_t __P ((void *, fpos_t, int));
+__extension__ typedef int cookie_close_function_t __P ((void *));
+__extension__ typedef struct
+{
+ cookie_read_function_t *read;
+ cookie_write_function_t *write;
+ cookie_seek_function_t *seek;
+ cookie_close_function_t *close;
+} cookie_io_functions_t;
+static __inline__ FILE *fopencookie(void *__restrict,
+ const char *__restrict,
+ cookie_io_functions_t) nonnull((1,2)) wur;
+static __inline__ FILE *fopencookie(void *__restrict cookie,
+ const char *__restrict mode unused,
+ cookie_io_functions_t io_funcs)
+{
+ return funopen(cookie, io_funcs.read, io_funcs.write, io_funcs.seek, io_funcs.close);
+}
+#endif
+#endif /* _ZIO_P_H */