diff options
author | Anas Nashif <anas.nashif@intel.com> | 2012-11-04 12:13:45 -0800 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2012-11-04 12:13:45 -0800 |
commit | 8085c3ee0d3e83e7693c162c10e4bc367c23518b (patch) | |
tree | e092f95b6503969974b6fc9e6473a7162207d1f4 | |
download | libzio-8085c3ee0d3e83e7693c162c10e4bc367c23518b.tar.gz libzio-8085c3ee0d3e83e7693c162c10e4bc367c23518b.tar.bz2 libzio-8085c3ee0d3e83e7693c162c10e4bc367c23518b.zip |
Imported Upstream version 0.99upstream/0.99
-rw-r--r-- | COPYING | 340 | ||||
-rw-r--r-- | Makefile | 133 | ||||
-rw-r--r-- | README | 50 | ||||
-rw-r--r-- | fzopen.3.in | 342 | ||||
-rw-r--r-- | lzw.h | 123 | ||||
-rw-r--r-- | tests.c | 28 | ||||
-rw-r--r-- | testt.c | 33 | ||||
-rw-r--r-- | unlzw.c | 464 | ||||
-rw-r--r-- | zio.c | 1208 | ||||
-rw-r--r-- | zio.h.in | 33 | ||||
-rw-r--r-- | zio.map | 7 | ||||
-rw-r--r-- | zioP.h | 165 |
12 files changed, 2926 insertions, 0 deletions
@@ -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) @@ -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> @@ -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); @@ -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; +} @@ -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; +} @@ -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 @@ -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 */ @@ -0,0 +1,7 @@ +{ +global: + fzopen; + fdzopen; +local: + *; +}; @@ -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 */ |