This commit was generated by cvs2svn to compensate for changes in r93, which
authorGuido Draheim <guidod@gmx.de>
Mon, 18 Aug 2003 12:59:04 +0000 (12:59 +0000)
committerGuido Draheim <guidod@gmx.de>
Mon, 18 Aug 2003 12:59:04 +0000 (12:59 +0000)
included commits to RCS files with non-trunk default branches.

docs/zzip-xor.htm [new file with mode: 0644]
zzip/__dirent.h [new file with mode: 0644]
zzip/__mmap.h [new file with mode: 0644]
zzip/dir.c [new file with mode: 0644]
zzip/err.c [new file with mode: 0644]
zzip/file.h [new file with mode: 0644]
zzip/format.h [new file with mode: 0644]
zzip/info.c [new file with mode: 0644]
zzip/lib.h [new file with mode: 0644]
zzip/stat.c [new file with mode: 0644]

diff --git a/docs/zzip-xor.htm b/docs/zzip-xor.htm
new file mode 100644 (file)
index 0000000..9eb8e25
--- /dev/null
@@ -0,0 +1,154 @@
+<h2> ZIP Obfuscation </h2>       Using obfuscations like XOR.
+
+<!--border--> <date> 15. July 2002 </date>
+
+<h3> The EXT/IO calls </h3>
+
+<P>
+  You really should read the section about the
+  <a href="zzip-extio.html">EXT/IO feature</a> of the zziplib since the
+  obfuscation routines are built on top of it. In order to use obfuscation,
+  you will generally need to use all the three additional argument that
+  can be passsed to _open_ext_io functions. For the XOR-example, only one
+  IO-handler is modified being the read()-call that will simply xor each
+  data byte upon read with a specific value. It two advantages - doing an
+  xor twice does yield the same data, so as a developer you do not have
+  to wonder about the encryption/decryption pair, and it is a stateless
+  obfuscation that does not need to know about the current position
+  within the zip-datafile or zippedfile-datatream.
+</P><P>
+  The examples provided just use a simple routine for xoring data that
+  is defined in all the three of the example programs: <pre>
+      static int xor_value = 0x55;
+      static zzip_ssize_t xor_read (int f, void* p, zzip_size_t l)
+      {
+          zzip_size_t r = read(f, p, l);
+         zzip_size_t i;     char* q = p;
+          for (x=0; x &lt; r; x++) q[x] ^= xor_value;
+          return r;
+      }
+  </pre>
+  and place this routine into the io-handlers after initializing
+  the structure: <pre>
+    zzip_init_io (&amp;xor_handlers, 0); xor_handlers.read = &amp;xor_read;
+  </pre>
+</P>
+
+<h3> The examples </h3>
+
+<P>
+  There are three example programs. The first one is
+  <a href="zzxorcopy.c">zzxorcopy.c</a> which actually is not a zziplib 
+  based program. It just opens a file via stdio, loops through all data bytes 
+  it can read thereby xor'ing it, and writes it out to the output file. A 
+  call like <code><nobr>"zzxorcopy file.zip file.dat"</nobr></code> will
+  create an obfuscated dat-file from a zip-file that has been possibly
+  create with the normal infozip tools or any other archive program to
+  generate a zip-file. The output dat-file is not recognized by normal
+  zip-enabled apps - the filemagic is obfuscated too. This output
+  dat-file however is subject to the other two example programs.
+</P><P>
+  The <a href="zzxordir.c">zzxordir.c</a> program will open such an obfuscated
+  zip file and decode the central directory of that zip. Everything is
+  still there in just the way it can be shown with the normal unzip
+  programs and routines. And the <a href="zzxorcat.c">zzxorcat.c</a> program 
+  can extract data from this obfuscated zip - and print it un-obfuscated
+  to the screen. These example programs can help you jumpstart with
+  your own set of obfuscator routines, possibly more complex ones.
+</P><P>
+  By the way, just compare those with their non-xor counterparts that
+  you can find in <a href="zzdir.c">zzdir.c</a> and 
+  <a href="zzxorcat.c">zzxorcat.c</a>. Notice that the difference is
+  in the setup part until the _open_ call after which one can just
+  use the normal zzip_ routines on that obfuscated file. This is
+  great for developing since you can start of with the magic-wrappers
+  working on real-files then slowly turning to pack-files that hold
+  most of the data and finally ending with a zip-only and obfuscated
+  dat-file for your project.
+</P>
+
+<h3> Some rationale </h3>
+
+<P>
+  Some people might ask why not adding standard zip-encryption. Well,
+  first of all the standard zip-encryption has not been strong enough
+  for modern computers, and there are hacker tools that even a 
+  half-literate computer-user can use to crack the password of a
+  zip-archive. Furthermore, adding real encryption is a heavy weight
+  that many people do not need, see the last argument for seeing the
+  standard one is useless anyway, and adding a non-standard one 
+  should not be the case of the standard zziplib either, ye know.
+</P><P>
+  On the other hand, obfuscation is a means to fear off half-literates
+  just as well - there are no premade tools for the obfuscation you
+  can invent from the xor examples. And a hacker that can de-obfuscate
+  such a dat-file is able to dissassemble your program as well thereby
+  going to see your decryption routine <em>and</em> the decryption key.
+  Although there is a difference, it just ranges on about times and
+  exprience, not magnitudes. Remember the old saying: you can irritate
+  some people for some time but not irritate all people for all the time.
+  As for encryption of artwork and AI scripts in games and applications,
+  just keep in mind that the final recipient has the decryption key on
+  his system anyway, just obfuscated. So each such encryption is nothing
+  more than just a clever form of obfuscation, nothing mathemetical strong.
+</P><P>
+  Some other people might ask why to obfuscate anyway. Well, the reason
+  is theft. Even people who write opensource free software generally
+  like to get some reward for what they do, some fame or atleast some 
+  sweet dream to have helped the world go a bit easier in the future.
+  As for program text this is quite natural for the programmers who
+  pick up some code from somewhere else - it happens that most of them
+  have gone through some formation and they know how hard it is to get
+  even some lines of code out of your brain. This is not the case for
+  some artwork and AI parameters, people do not have much respect for
+  those - they just pick it up, put it under their umbrella, and 
+  that's it - they even claim they could have done that themselves,
+  and in most cases it is that they never have been really trying to
+  do it and think of it as being comparable to that action-art they've
+  seen on TV. 
+</P><P>
+  Just be sure that there is nothing wrong with obfuscating
+  things for a binary distribution of your program even for the
+  opensource case - the program text itself is an obfuscation in its
+  source form when being compiled into cpu instructions. Still, the
+  interested people can get hold of the source code since you provide
+  it somewhere and actually the original programmers like to hear 
+  from literate people who could help with modifying the project. The
+  same is true for you artwork and AI scripts, the interested people
+  can still see them in the opensource project material, but only
+  those will look who dare to, not just the halfwit next door. 
+</P><P>
+  Well, you do not need to that on the other hand - ID software has
+  shown that it can be very helpful since people will start to
+  write new maps and new bots, pack them and publish them. An open
+  data format is a form of attraction for people who can use a 
+  graphics program and an editor but who do not know how to program.
+  And if you use obfuscation within an opensource program, it is
+  surely enought to just use the xor-format presented here, so that
+  it easy for third people to get involved if they want to, they
+  just have to rewrite their new datapacks with zzxorcopy, and
+  that's it.
+</P><P>
+  As for the non-opensource projects, be aware that there are
+  some ways to even staticlink the zziplib into your project, so
+  you can even hide that you used zip tools to create your dat files.
+  This is well enough for anyone to do - as soon as a hacker will
+  get to the point to notice you used a zip format, he would have
+  had found any other deobfusation or decryption routine as well.
+  If you are frightened, just encrypt the executable with tools
+  you bought from somewhere else. On the other hand, should there
+  be problems or bugs, you have an easier time to find them when
+  they could be caused by your dat entries, and it is again easy
+  to send a fixup file to your clients, since the command line
+  tools are just a breeze compared with some other anti-hacking
+  tools you'll find on the market.
+</P><P>
+  Well, hope this is enough rationale to tell you that I do not
+  see a need to implement anything more than obfuscation within
+  zziplib - if you need real encryption, use real encryption
+  software and its fileformat that supports it, not zip files.
+</P>
+
+<p align="right"><small><small>
+<a href="copying.html">staticlinking?</a>
+</small></small></p>
diff --git a/zzip/__dirent.h b/zzip/__dirent.h
new file mode 100644 (file)
index 0000000..fc3e08f
--- /dev/null
@@ -0,0 +1,393 @@
+#ifndef ZZIP_INTERNAL_DIRENT_H
+#define ZZIP_INTERNAL_DIRENT_H
+#include <zzip/conf.h>
+
+/*
+ * DO NOT USE THIS CODE.
+ *
+ * It is an internal header file for zziplib that carries some inline
+ * functions (or just static members) and a few defines, simply to be
+ * able to reuse these across - and have everything in a specific place.
+ *
+ * Copyright (c) 2002,2003 Guido Draheim
+ *          All rights reserved,
+ *          use under the restrictions of the 
+ *          Lesser GNU General Public License
+ *          or alternatively the restrictions 
+ *          of the Mozilla Public License 1.1
+ */
+
+#ifdef ZZIP_HAVE_DIRENT_H
+#define USE_DIRENT 1
+
+#define _zzip_opendir   opendir
+#define _zzip_readdir   readdir
+#define _zzip_closedir  closedir
+#define _zzip_rewinddir rewinddir
+#define _zzip_telldir   telldir
+#define _zzip_seekdir   seekdir
+#define _zzip_DIR       DIR
+
+#include <dirent.h>
+
+#elif defined ZZIP_HAVE_WINBASE_H
+#define USE_DIRENT 2
+
+#define _zzip_opendir   win32_opendir
+#define _zzip_readdir   win32_readdir
+#define _zzip_closedir  win32_closedir
+#define _zzip_rewinddir win32_rewinddir
+#define _zzip_telldir   win32_telldir
+#define _zzip_seekdir   win32_seekdir
+#define _zzip_DIR       DIR
+
+/*
+ * DIRENT.H (formerly DIRLIB.H)
+ *
+ * by M. J. Weinstein   Released to public domain 1-Jan-89
+ *
+ * Because I have heard that this feature (opendir, readdir, closedir)
+ * it so useful for programmers coming from UNIX or attempting to port
+ * UNIX code, and because it is reasonably light weight, I have included
+ * it in the Mingw32 package. I have also added an implementation of
+ * rewinddir, seekdir and telldir.
+ *   - Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  This code is distributed in the hope that is will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAMED. This includeds but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#include <io.h>
+
+struct dirent
+{
+       long            d_ino;          /* Always zero. */
+       unsigned short  d_reclen;       /* Always zero. */
+       unsigned short  d_namlen;       /* Length of name in d_name. */
+       char*           d_name;         /* File name. */
+       /* NOTE: The name in the dirent structure points to the name in the
+        *       finddata_t structure in the DIR. */
+};
+
+/*
+ * This is an internal data structure. Good programmers will not use it
+ * except as an argument to one of the functions below.
+ */
+typedef struct
+{
+       /* disk transfer area for this dir */
+       struct _finddata_t      dd_dta;
+
+       /* dirent struct to return from dir (NOTE: this makes this thread
+        * safe as long as only one thread uses a particular DIR struct at
+        * a time) */
+       struct dirent           dd_dir;
+
+       /* _findnext handle */
+       long                    dd_handle;
+
+       /*
+         * Status of search:
+        *   0 = not started yet (next entry to read is first entry)
+        *  -1 = off the end
+        *   positive = 0 based index of next entry
+        */
+       short                   dd_stat;
+
+       /* given path for dir with search pattern (struct is extended) */
+       char                    dd_name[1];
+} DIR;
+
+/*
+ * dirent.c
+ *
+ * Derived from DIRLIB.C by Matt J. Weinstein 
+ * This note appears in the DIRLIB.H
+ * DIRLIB.H by M. J. Weinstein   Released to public domain 1-Jan-89
+ *
+ * Updated by Jeremy Bettis <jeremy@hksys.com>
+ * Significantly revised and rewinddir, seekdir and telldir added by Colin
+ * Peters <colin@fu.is.saga-u.ac.jp>
+ */
+
+#include <direct.h>
+#include <errno.h>
+#include <io.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#define win32_SUFFIX   "*"
+#define        win32_SLASH     "\\"
+
+#ifndef S_ISDIR
+#define S_ISDIR(m)     ((m & S_IFMT) == S_IFDIR)       /* is a directory */
+#endif  S_ISDIR
+
+
+/*
+  opendir
+
+  Returns a pointer to a DIR structure appropriately filled in to begin
+  searching a directory.
+*/
+static DIR*
+win32_opendir (const char *szPath)
+{
+    DIR        *nd;
+    struct _stat statDir;
+
+    errno = 0;
+    
+    if (!szPath) {
+       errno = EFAULT;
+       return (DIR *) 0;
+    }
+
+    if (szPath[0] == '\0') {
+       errno = ENOTDIR;
+       return (DIR *) 0;
+    }
+    
+    /* Attempt to determine if the given path really is a directory. */
+    if (_stat (szPath, &statDir)) {
+       /* Error, stat should have set an error value. */
+       return (DIR *) 0;
+    }
+    
+    if (!S_ISDIR (statDir.st_mode)) {
+       /* Error, stat reports not a directory. */
+       errno = ENOTDIR;
+       return (DIR *) 0;
+    }
+
+    /* Allocate enough space to store DIR structure and the complete *
+       directory path given. */
+    nd = (DIR *) calloc (1, sizeof (DIR) + strlen (szPath) 
+                        + strlen (win32_SLASH) + strlen (win32_SUFFIX));
+    
+    if (!nd) {
+       /* Error, out of memory. */
+       errno = ENOMEM;
+       return (DIR *) 0;
+    }
+
+    /* Create the search expression. */
+    strcpy (nd->dd_name, szPath);
+    
+    /* Add on a slash if the path does not end with one. */
+    if (nd->dd_name[0] != '\0' &&
+       nd->dd_name[strlen (nd->dd_name) - 1] != '/' &&
+       nd->dd_name[strlen (nd->dd_name) - 1] != '\\') {
+       strcat (nd->dd_name, win32_SLASH);
+    }
+    
+    /* Add on the search pattern */
+    strcat (nd->dd_name, win32_SUFFIX);
+    
+    /* Initialize handle to -1 so that a premature closedir doesn't try * to
+       call _findclose on it. */
+    nd->dd_handle = -1;
+    
+    /* Initialize the status. */
+    nd->dd_stat = 0;
+    
+    /* Initialize the dirent structure. ino and reclen are invalid under *
+       Win32, and name simply points at the appropriate part of the *
+       findfirst_t structure. */
+    nd->dd_dir.d_ino = 0;
+    nd->dd_dir.d_reclen = 0;
+    nd->dd_dir.d_namlen = 0;
+    nd->dd_dir.d_name = nd->dd_dta.name;
+    
+    return nd;
+}
+
+/*
+  readdir
+
+  Return a pointer to a dirent structure filled with the information on the
+  next entry in the directory.
+*/
+static struct dirent *
+win32_readdir (DIR * dirp)
+{
+    errno = 0;
+    
+    /* Check for valid DIR struct. */
+    if (!dirp) {
+       errno = EFAULT;
+       return (struct dirent *) 0;
+    }
+    
+    if (dirp->dd_dir.d_name != dirp->dd_dta.name) {
+       /* The structure does not seem to be set up correctly. */
+       errno = EINVAL;
+       return (struct dirent *) 0;
+    }
+
+    if (dirp->dd_stat < 0) {
+       /* We have already returned all files in the directory * (or the
+          structure has an invalid dd_stat). */
+       return (struct dirent *) 0;
+    } else if (dirp->dd_stat == 0) {
+       /* We haven't started the search yet. */
+       /* Start the search */
+       dirp->dd_handle = _findfirst (dirp->dd_name, &(dirp->dd_dta));
+       
+       if (dirp->dd_handle == -1) {
+           /* Whoops! Seems there are no files in that * directory. */
+           dirp->dd_stat = -1;
+       } else {
+           dirp->dd_stat = 1;
+       }
+    } else {
+       /* Get the next search entry. */
+       if (_findnext (dirp->dd_handle, &(dirp->dd_dta))) {
+           /* We are off the end or otherwise error. */
+           _findclose (dirp->dd_handle);
+           dirp->dd_handle = -1;
+           dirp->dd_stat = -1;
+       } else {
+           /* Update the status to indicate the correct * number. */
+           dirp->dd_stat++;
+       }
+    }
+    
+    if (dirp->dd_stat > 0) {
+       /* Successfully got an entry. Everything about the file is * already
+          appropriately filled in except the length of the * file name. */
+       dirp->dd_dir.d_namlen = (unsigned short) strlen (dirp->dd_dir.d_name);
+       return &dirp->dd_dir;
+    }
+    
+    return (struct dirent *) 0;
+}
+
+/*
+  closedir
+
+  Frees up resources allocated by opendir.
+*/
+static int
+win32_closedir (DIR * dirp)
+{
+    int         rc;
+
+    errno = 0;
+    rc = 0;
+
+    if (!dirp) {
+       errno = EFAULT;
+       return -1;
+    }
+    
+    if (dirp->dd_handle != -1) {
+       rc = _findclose (dirp->dd_handle);
+    }
+    
+    /* Delete the dir structure. */
+    free (dirp);
+    
+    return rc;
+}
+
+/*
+  rewinddir
+
+  Return to the beginning of the directory "stream". We simply call findclose
+  and then reset things like an opendir.
+*/
+static void
+win32_rewinddir (DIR * dirp)
+{
+    errno = 0;
+
+    if (!dirp) {
+       errno = EFAULT;
+       return;
+    }
+    
+    if (dirp->dd_handle != -1) {
+       _findclose (dirp->dd_handle);
+    }
+    
+    dirp->dd_handle = -1;
+    dirp->dd_stat = 0;
+}
+
+/*
+  telldir
+
+  Returns the "position" in the "directory stream" which can be used with
+  seekdir to go back to an old entry. We simply return the value in stat.
+*/
+static long
+win32_telldir (DIR * dirp)
+{
+    errno = 0;
+
+    if (!dirp) {
+       errno = EFAULT;
+       return -1;
+    }
+    return dirp->dd_stat;
+}
+
+/*
+  seekdir
+
+  Seek to an entry previously returned by telldir. We rewind the directory
+  and call readdir repeatedly until either dd_stat is the position number
+  or -1 (off the end). This is not perfect, in that the directory may
+  have changed while we weren't looking. But that is probably the case with
+  any such system.
+*/
+static void
+win32_seekdir (DIR * dirp, long lPos)
+{
+    errno = 0;
+    
+    if (!dirp) {
+       errno = EFAULT;
+       return;
+    }
+    
+    if (lPos < -1) {
+       /* Seeking to an invalid position. */
+       errno = EINVAL;
+       return;
+    } else if (lPos == -1) {
+       /* Seek past end. */
+       if (dirp->dd_handle != -1) {
+           _findclose (dirp->dd_handle);
+       }
+       dirp->dd_handle = -1;
+       dirp->dd_stat = -1;
+    } else {
+       /* Rewind and read forward to the appropriate index. */
+       win32_rewinddir (dirp);
+       
+       while ((dirp->dd_stat < lPos) && win32_readdir (dirp));
+    }
+}
+
+#else
+#define USE_DIRENT 0
+
+#define _zzip_opendir(_N_) 0
+#define _zzip_readdir(_D_) 0
+#define _zzip_closedir(_D_) /* omit return code */
+#define _zzip_rewinddir(_D_)
+#define _zzip_telldir(_D_) 0
+#define _zzip_seekdir(_D_,_V_) /* omit return code */
+#define _zzip_DIR void*
+
+/* end of DIRENT implementation */
+#endif
+
+/* once */
+#endif
diff --git a/zzip/__mmap.h b/zzip/__mmap.h
new file mode 100644 (file)
index 0000000..d43d279
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef __ZZIP_INTERNAL_MMAP_H
+#define __ZZIP_INTERNAL_MMAP_H
+#include <zzip/conf.h>
+
+/*
+ * DO NOT USE THIS CODE.
+ *
+ * It is an internal header file for zziplib that carries some inline
+ * functions (or just static members) and a few defines, simply to be
+ * able to reuse these across - and have everything in a specific place.
+ *
+ * Copyright (c) 2002,2003 Guido Draheim
+ *          All rights reserved,
+ *          use under the restrictions of the 
+ *          Lesser GNU General Public License
+ *          or alternatively the restrictions 
+ *          of the Mozilla Public License 1.1
+ */
+
+#ifdef _USE_MMAP
+#if    defined ZZIP_HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#define USE_POSIX_MMAP 1
+#elif defined ZZIP_HAVE_WINBASE_H || defined WIN32
+#include <windows.h>
+#define USE_WIN32_MMAP 1
+#else
+#undef _USE_MMAP
+#endif
+#endif
+
+/* -------------- specify MMAP function imports --------------------------- */
+
+#if     defined  USE_POSIX_MMAP
+#define USE_MMAP 1
+
+#define _zzip_mmap(user, fd, offs, len) \
+              mmap (0, len, PROT_READ, MAP_SHARED, fd, offs)
+#define _zzip_munmap(user, ptr, len) \
+              munmap (ptr, len)
+#define _zzip_getpagesize(user) getpagesize()
+
+#ifndef MAP_FAILED /* hpux10.20 does not have it */
+#define MAP_FAILED ((void*)(-1))
+#endif
+
+#elif   defined USE_WIN32_MMAP
+#define USE_MMAP 1
+#ifndef MAP_FAILED
+#define MAP_FAILED 0
+#endif
+/* we (ab)use the "*user" variable to store the FileMapping handle */
+                 /* which assumes (sizeof(long) == sizeof(HANDLE)) */
+
+static size_t win32_getpagesize ()
+{ 
+    SYSTEM_INFO si; GetSystemInfo (&si); 
+    return si.dwAllocationGranularity; 
+}
+static void*  win32_mmap (long* user, int fd, zzip_off_t offs, size_t len)
+{
+    if (! user || *user != 1) /* || offs % getpagesize() */
+       return 0;
+  {
+    HANDLE hFile = (HANDLE)_get_osfhandle(fd);
+    if (hFile)
+       *user = (int) CreateFileMapping (hFile, 0, PAGE_READONLY, 0, 0, NULL);
+    if (*user)
+    {
+       char* p = 0;
+       p = MapViewOfFile(*(HANDLE*)user, FILE_MAP_READ, 0, offs, len);
+       if (p) return p + offs;
+       CloseHandle (*(HANDLE*)user); *user = 1;
+    } 
+    return MAP_FAILED;
+  }
+}
+static void win32_munmap (long* user, char* fd_map, size_t len)
+{
+    UnmapViewOfFile (fd_map);
+    CloseHandle (*(HANDLE*)user); *user = 1;
+}
+
+#define _zzip_mmap(user, fd, offs, len) \
+        win32_mmap ((long*) &(user), fd, offs, len)
+#define _zzip_munmap(user, ptr, len) \
+        win32_munmap ((long*) &(user), ptr, len)
+#define _zzip_getpagesize(user) win32_getpagesize()
+
+#else   /* disable */
+#define USE_MMAP 0
+/* USE_MAP is intentional: we expect the compiler to do some "code removal"
+ * on any source code enclosed in if (USE_MMAP) {...}   i.e. the unreachable
+ * branch of an if (0) {....} is not emitted to the final object binary. */
+
+#ifndef MAP_FAILED
+#define MAP_FAILED  0
+#endif
+
+#define _zzip_mmap(user, fd, offs, len) (MAP_FAILED)
+#define _zzip_munmap(user, ptr, len) {}
+#define _zzip_getpagesize(user) 1
+
+#endif /* USE_MMAP defines */
+
+
+#endif
diff --git a/zzip/dir.c b/zzip/dir.c
new file mode 100644 (file)
index 0000000..aaf874e
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * Author: 
+ *     Guido Draheim <guidod@gmx.de>
+ *
+ *     Copyright (c) 1999,2000,2001,2002,2003 Guido Draheim
+ *         All rights reserved,
+ *         use under the restrictions of the
+ *         Lesser GNU General Public License
+ *          or alternatively the restrictions 
+ *          of the Mozilla Public License 1.1
+ */
+
+#include <zzip/lib.h>                                   /* exported... */
+#include <zzip/file.h>
+#include <stddef.h> /*offsetof*/
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef ZZIP_HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#else
+#include <stdio.h>
+#endif
+
+#include <zzip/__dirent.h>
+
+#ifndef offsetof
+#pragma warning had to DEFINE offsetof as it was not in stddef.h
+#define offsetof(T,M) ((unsigned)(& ((T*)0)->M))
+#endif
+
+#ifdef ZZIP_HAVE_SYS_STAT_H
+/* MSVC does have IFbitmask but not the corresponding IStests */
+# if !defined S_ISDIR && defined S_IFDIR
+# define S_ISDIR(_X_) ((_X_) & S_IFDIR)
+# endif
+# if !defined S_ISREG && defined S_IFREG
+# define S_ISREG(_X_) ((_X_) & S_IFREG)
+# endif
+#endif
+
+/** 
+ * This function is the equivalent of a => rewinddir(2) for a realdir or
+ * the zipfile in place of a directory. The ZZIP_DIR handle returned from
+ * => zzip_opendir has a flag saying realdir or zipfile. As for a zipfile,
+ * the filenames will include the filesubpath, so take care.
+ */
+void 
+zzip_rewinddir(ZZIP_DIR * dir)
+{
+    if (! dir) return;
+
+    if (USE_DIRENT && dir->realdir) 
+    {
+        _zzip_rewinddir(dir->realdir);
+        return;
+    }
+
+    if (dir->hdr0)
+        dir->hdr = dir->hdr0;
+    else
+        dir->hdr = 0;
+}
+
+#if ! USE_DIRENT
+#define real_readdir(_X_) 1
+#else
+static int
+real_readdir(ZZIP_DIR* dir)
+{
+    struct stat st = { 0 };
+    char filename[PATH_MAX];
+    struct dirent* dirent = _zzip_readdir(dir->realdir);
+    if (! dirent) return 0;
+
+    dir->dirent.d_name = dirent->d_name;
+    strcpy(filename, dir->realname);
+    strcat(filename, "/");
+    strcat(filename, dirent->d_name);
+
+    if (stat(filename, &st) == -1)
+        return -1;
+
+    dir->dirent.d_csize = dir->dirent.st_size = st.st_size;
+
+    if (st.st_mode)
+    {
+        if (! S_ISREG(st.st_mode))
+        {
+            dir->dirent.d_compr = st.st_mode;
+            dir->dirent.d_compr |= 0x80000000; 
+           /* makes it effectively negative, 
+            * but can still be fed to S_ISXXX(x) */
+        }else
+        {
+            dir->dirent.d_compr = 0; /* stored */
+        }
+    }else
+    {
+            dir->dirent.d_compr = 0; /* stored */
+    }
+
+    return 1;
+}
+#endif
+
+/**
+ * This function is the equivalent of a => readdir(2) for a realdir 
+ * or a zipfile referenced by the ZZIP_DIR returned from => zzip_opendir.
+ *
+ * The ZZIP_DIR handle (as returned by => zzip_opendir) contains a few more 
+ * entries than being copied into the ZZIP_DIRENT. The only valid fields in
+ * a ZZIP_DIRENT are d_name (the file name), d_compr (compression), d_csize
+ * (compressed size), st_size (uncompressed size).
+ */
+ZZIP_DIRENT* 
+zzip_readdir(ZZIP_DIR * dir)
+{
+    if (! dir) { errno=EBADF; return 0; }
+
+    if (USE_DIRENT && dir->realdir)
+    {
+        if (! real_readdir(dir))
+            return 0;
+    }else
+    {
+        if (! dir->hdr) return 0;
+
+        dir->dirent.d_name  = dir->hdr->d_name;
+        dir->dirent.d_compr = dir->hdr->d_compr;
+
+        dir->dirent.d_csize = dir->hdr->d_csize;
+        dir->dirent.st_size = dir->hdr->d_usize;
+
+        if (! dir->hdr->d_reclen) dir->hdr = 0;
+        else  dir->hdr = (struct zzip_dir_hdr *)
+                 ((char *)dir->hdr + dir->hdr->d_reclen);
+    }
+    return &dir->dirent;
+}
+
+/** => zzip_rewinddir
+ * This function is the equivalent of => telldir(2) for a realdir or zipfile.
+ */
+zzip_off_t 
+zzip_telldir(ZZIP_DIR* dir)
+{
+    if (! dir) { errno=EBADF; return -1; }
+
+    if (USE_DIRENT && dir->realdir)
+    {
+        return _zzip_telldir(dir->realdir);
+    }else
+    {
+       return ((zzip_off_t) ((char*) dir->hdr - (char*) dir->hdr0));
+    }
+}
+
+/** => zzip_rewinddir
+ * This function is the equivalent of => seekdir(2) for a realdir or zipfile.
+ */
+void
+zzip_seekdir(ZZIP_DIR* dir, zzip_off_t offset)
+{
+    if (! dir) return; 
+    
+    if (USE_DIRENT && dir->realdir)
+    {
+        _zzip_seekdir(dir->realdir, offset);
+    }else
+    {
+       dir->hdr = (struct zzip_dir_hdr*) 
+           (dir->hdr0 ? (char*) dir->hdr0 + (size_t) offset : 0);
+    }
+}
+
+#if defined ZZIP_LARGEFILE_RENAME && defined EOVERFLOW && defined PIC
+#undef zzip_seekdir /* zzip_seekdir64 */
+#undef zzip_telldir /* zzip_telldir64 */
+
+long   zzip_telldir(ZZIP_DIR* dir) 
+{ 
+    off_t off = zzip_telldir64 (dir); 
+    long offs = off;
+    if (offs != off) { errno = EOVERFLOW; return -1; }
+    return offs;
+}
+
+void   zzip_seekdir(ZZIP_DIR* dir, long offset) 
+{ 
+    zzip_seekdir64 (dir, offset); 
+}
+#endif
+
+/**
+ * This function is the equivalent of => opendir(3) for a realdir or zipfile.
+ * <p>
+ * This function has some magic - if the given argument-path
+ * is a directory, it will wrap a real => opendir(3) into the ZZIP_DIR
+ * structure. Otherwise it will divert to => zzip_dir_open which 
+ * can also attach a ".zip" extension if needed to find the archive.
+ * <p>
+ * the error-code is mapped to => errno(3).
+ */
+ZZIP_DIR* 
+zzip_opendir(zzip_char_t* filename)
+{
+    return zzip_opendir_ext_io (filename, 0, 0, 0);
+}
+
+/** => zzip_opendir
+ * This function uses explicit ext and io instead of the internal 
+ * defaults, setting them to zero is equivalent to => zzip_opendir
+ */
+ZZIP_DIR* 
+zzip_opendir_ext_io(zzip_char_t* filename, int o_modes,
+                   zzip_strings_t* ext, zzip_plugin_io_t io)
+{
+    zzip_error_t e;
+    ZZIP_DIR* dir;
+
+#  ifdef ZZIP_HAVE_SYS_STAT_H
+    struct stat st;
+#  endif
+
+    if (o_modes & (ZZIP_PREFERZIP|ZZIP_ONLYZIP)) goto try_zzip;
+ try_real:
+
+#  ifdef ZZIP_HAVE_SYS_STAT_H
+    if (stat(filename, &st) >= 0 && S_ISDIR(st.st_mode)
+    ){
+       if (USE_DIRENT)
+       {
+           _zzip_DIR* realdir = _zzip_opendir(filename);
+           if (realdir)
+           {
+               if (! (dir = (ZZIP_DIR *)calloc(1, sizeof (*dir))))
+               { 
+                   _zzip_closedir(realdir); 
+                   return 0; 
+               }else
+               { 
+                   dir->realdir = realdir; 
+                   dir->realname = strdup(filename);
+                   return dir; 
+               }
+           }
+        }
+        return 0;
+    }
+#  endif /* HAVE_SYS_STAT_H */
+
+ try_zzip:
+    dir = zzip_dir_open_ext_io (filename, &e, ext, io);
+    if (! dir && (o_modes & ZZIP_PREFERZIP)) goto try_real;
+    if (e) errno = zzip_errno(e); 
+    return dir;
+}
+
+/**
+ * This function is the equivalent of => closedir(3) for a realdir or zipfile.
+ * <p>
+ * This function is magic - if the given arg-ZZIP_DIR
+ * is a real directory, it will call the real => closedir(3) and then
+ * free the wrapping ZZIP_DIR structure. Otherwise it will divert 
+ * to => zzip_dir_close which will free the ZZIP_DIR structure.
+ */
+int
+zzip_closedir(ZZIP_DIR* dir)
+{
+    if (! dir) { errno = EBADF; return -1; }
+
+    if (USE_DIRENT && dir->realdir)
+    {
+        _zzip_closedir(dir->realdir);
+        free(dir->realname);
+        free(dir);
+        return 0;
+    }else
+    {
+        zzip_dir_close(dir);
+        return 0;
+    }
+}
+
+/* 
+ * Local variables:
+ * c-file-style: "stroustrup"
+ * End:
+ */
diff --git a/zzip/err.c b/zzip/err.c
new file mode 100644 (file)
index 0000000..299c44e
--- /dev/null
@@ -0,0 +1,154 @@
+/*\r
+ * Author: \r
+ *      Guido Draheim <guidod@gmx.de>\r
+ *      Tomi Ollila <Tomi.Ollila@iki.fi>\r
+ *\r
+ *      Copyright (c) 1999,2000,2001,2002,2003 Guido Draheim\r
+ *          All rights reserved,\r
+ *          use under the restrictions of the\r
+ *          Lesser GNU General Public License\r
+ *          or alternatively the restrictions \r
+ *          of the Mozilla Public License 1.1\r
+ */\r
+\r
+#include <zzip/lib.h>                                    /* exported... */\r
+#include <zlib.h>\r
+\r
+#include <string.h>\r
+#include <errno.h>\r
+\r
+#include <zzip/file.h>\r
+\r
+static struct errlistentry { int code; const char* mesg; } \r
+errlist[] = \r
+{\r
+    { ZZIP_NO_ERROR, "No error" },\r
+    { ZZIP_OUTOFMEM, "could not get temporary memory for internal structures" },\r
+    { ZZIP_DIR_OPEN, "Failed to open zip-file %s" },\r
+    { ZZIP_DIR_STAT, "Failed to fstat zip-file %s" },\r
+    { ZZIP_DIR_SEEK, "Failed to lseek zip-file %s" },\r
+    { ZZIP_DIR_READ, "Failed to read zip-file %s"},  \r
+    { ZZIP_DIR_TOO_SHORT,   "zip-file %s too short" },\r
+    { ZZIP_DIR_EDH_MISSING, "zip-file central directory not found" },\r
+    { ZZIP_DIRSIZE, "Directory size too big..." },\r
+    { ZZIP_ENOENT, "No such file found in zip-file %s" },\r
+    { ZZIP_UNSUPP_COMPR, "Unsupported compression format" },\r
+    { ZZIP_CORRUPTED, "Zipfile corrupted" }, \r
+    { ZZIP_UNDEF,      "Some undefined error occurred" },\r
+    { 0, 0 },\r
+};\r
+\r
+#define errlistSIZE (sizeof(errlist)/sizeof(*errlist))\r
+\r
+/**\r
+ * returns the static string for the given error code. The\r
+ * error code can be either a normal system error (a\r
+ * positive error code will flag this), it can be => libz\r
+ * error code (a small negative error code will flag this)\r
+ * or it can be an error code from => libzzip, which is an\r
+ * negative value lower than => ZZIP_ERROR\r
+ */\r
+zzip_char_t* \r
+zzip_strerror(int errcode)\r
+{\r
+  if (errcode < ZZIP_ERROR && errcode > ZZIP_ERROR-32)\r
+  {\r
+      struct errlistentry* err = errlist;\r
+      for (; err->mesg ; err++)\r
+      {\r
+          if (err->code == errcode) \r
+              return err->mesg; \r
+      }\r
+      errcode = EINVAL;\r
+  }\r
+\r
+  if (errcode < 0)\r
+  {\r
+      if (errcode == -1)\r
+          return strerror(errcode);\r
+      else\r
+          return zError(errcode);\r
+  }\r
+  \r
+  return strerror (errcode);\r
+}\r
+\r
+/** => zzip_strerror\r
+ * This function fetches the errorcode from the => DIR-handle and \r
+ * runs it through => zzip_strerror to obtain the static string\r
+ * describing the error.\r
+ */\r
+zzip_char_t* \r
+zzip_strerror_of(ZZIP_DIR* dir)\r
+{\r
+    if (! dir) return strerror (errno);\r
+    return zzip_strerror(dir->errcode);\r
+}\r
+\r
+static struct errnolistentry { int code; int e_no; } \r
+errnolist[] =\r
+{\r
+    { Z_STREAM_ERROR, EPIPE },\r
+    { Z_DATA_ERROR, ESPIPE },\r
+    { Z_MEM_ERROR, ENOMEM },\r
+    { Z_BUF_ERROR, EMFILE },\r
+    { Z_VERSION_ERROR, ENOEXEC },\r
+      \r
+    { ZZIP_DIR_OPEN, ENOTDIR },\r
+    { ZZIP_DIR_STAT, EREMOTE },\r
+    { ZZIP_DIR_SEEK, ESPIPE },\r
+#  ifdef ESTRPIPE\r
+    { ZZIP_DIR_READ, ESTRPIPE},  \r
+#  else\r
+    { ZZIP_DIR_READ, EPIPE},  \r
+#  endif\r
+    { ZZIP_DIR_TOO_SHORT, ENOEXEC },\r
+#  ifdef ENOMEDIUM\r
+    { ZZIP_DIR_EDH_MISSING, ENOMEDIUM },\r
+#  else\r
+    { ZZIP_DIR_EDH_MISSING, EIO },\r
+#  endif\r
+    { ZZIP_DIRSIZE, EFBIG },\r
+    { ZZIP_OUTOFMEM, ENOMEM },\r
+    { ZZIP_ENOENT, ENOENT },\r
+#  ifdef EPFNOSUPPORT\r
+    { ZZIP_UNSUPP_COMPR, EPFNOSUPPORT },\r
+#  else\r
+    { ZZIP_UNSUPP_COMPR, EACCES },\r
+#  endif \r
+# ifdef EILSEQ\r
+    { ZZIP_CORRUPTED, EILSEQ }, \r
+# else\r
+    { ZZIP_CORRUPTED, ELOOP }, \r
+# endif\r
+    { ZZIP_UNDEF, EINVAL },\r
+    { 0, 0 },\r
+};    \r
+\r
+/**\r
+ * map the error code to a system error code. This is used\r
+ * for the drop-in replacement functions to return a value\r
+ * that can be interpreted correctly by code sections that\r
+ * are unaware of the fact they their => open(2) call had been\r
+ * diverted to a file inside a zip-archive.\r
+ */\r
+int\r
+zzip_errno(int errcode)\r
+{\r
+    if (errcode >= -1) return errno;\r
+    \r
+    {   struct errnolistentry* err = errnolist;\r
+        for (; err->code ; err++)\r
+        {\r
+            if (err->code == errcode) \r
+                return err->e_no; \r
+        }\r
+    }\r
+    return EINVAL;\r
+}\r
+\r
+/* \r
+ * Local variables:\r
+ * c-file-style: "stroustrup"\r
+ * End:\r
+ */\r
diff --git a/zzip/file.h b/zzip/file.h
new file mode 100644 (file)
index 0000000..e3b3497
--- /dev/null
@@ -0,0 +1,81 @@
+/*\r
+ * this is an internal header file - the structure contains two off_t\r
+ * atleast making it LARGEFILE_SENSITIVE on linux2 and solaris systems\r
+ * whereas about all functions just return a ZZIP_FILE* in zzip/zzip.h\r
+ *\r
+ * and so, this structure should be handled version-specific and\r
+ * subject to change - it had been kept binary-compatible for quite\r
+ * a while now so perhaps some program sources have errnously taken\r
+ * advantage of this file.\r
+ *\r
+ * Author: \r
+ *      Guido Draheim <guidod@gmx.de>\r
+ *      Tomi Ollila <Tomi.Ollila@tfi.net>\r
+ *\r
+ *      Copyright (c) 1999,2000,2001,2002 Guido Draheim\r
+ *          All rights reserved,\r
+ *          use under the restrictions of the\r
+ *          Lesser GNU General Public License\r
+ *          or alternatively the restrictions \r
+ *          of the Mozilla Public License 1.1\r
+ */\r
+\r
+#ifndef _ZZIP_FILE_H /* zzip-file.h */\r
+#define _ZZIP_FILE_H 1\r
+\r
+#ifndef ZZIP_32K\r
+#ifdef __GNUC__\r
+/* include zzip/lib.h beforehand in order to suppress the following warning */\r
+#warning zzip/file.h is an internal header, do not use it freely\r
+#endif\r
+#endif\r
+\r
+#include <zzip/lib.h>\r
+#include <zlib.h>\r
+\r
+#ifdef ZZIP_HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#else\r
+#include <stdio.h>\r
+# ifdef ZZIP_HAVE_SYS_TYPES_H\r
+# include <sys/types.h>\r
+# endif\r
+#endif\r
+\r
+#ifdef ZZIP_HAVE_SYS_PARAM_H\r
+#include <sys/param.h> /* PATH_MAX */\r
+#endif\r
+\r
+#ifndef PATH_MAX\r
+# ifdef  MAX_PATH /* windows */\r
+# define PATH_MAX MAX_PATH\r
+# else\r
+# define PATH_MAX 512\r
+# endif\r
+#endif\r
+/*\r
+ * ZZIP_FILE structure... currently no need to unionize, since structure needed\r
+ * for inflate is superset of structure needed for unstore.\r
+ *\r
+ * Don't make this public. Instead, create methods for needed operations.\r
+ */\r
+\r
+struct zzip_file\r
+{\r
+  struct zzip_dir* dir; \r
+  int fd;\r
+  int method;\r
+  zzip_size_t restlen;\r
+  zzip_size_t crestlen;\r
+  zzip_size_t usize;\r
+  zzip_size_t csize;\r
+  /* added dataoffset member - data offset from start of zipfile*/\r
+  zzip_off_t dataoffset;\r
+  char* buf32k;\r
+  zzip_off_t offset; /* offset from the start of zipfile... */\r
+  z_stream d_stream;\r
+  zzip_plugin_io_t io;\r
+};\r
+\r
+#endif /* _ZZIP_FILE_H */\r
+\r
diff --git a/zzip/format.h b/zzip/format.h
new file mode 100644 (file)
index 0000000..06ad5dd
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Author: 
+ *     Guido Draheim <guidod@gmx.de>
+ *
+ *     Copyright (c) 2000,2001,2002,2003 Guido Draheim
+ *         All rights reserved
+ *         use under the restrictions of the
+ *         Lesser GNU General Public License
+ *          or alternatively the restrictions 
+ *          of the Mozilla Public License 1.1
+ *
+ *  The information was taken from appnote-981119-iz.zip
+ *  at http://www.freesoftware.com/pub/infozip/doc/
+ *  which in turn is based on PKWARE's appnote.txt
+ */
+#ifndef _ZZIP_FORMAT_H /* zzipformat.h */
+#define _ZZIP_FORMAT_H
+#include <zzip/lib.h>
+/* we have ICO C 9X types defined */
+
+/* 
+ * Overall zipfile format 
+ *  [local file header + file data + data descriptr] ... [central directory] [EOD record] 
+ */
+# ifdef _MSC_VER
+# pragma pack(push, 1)
+# endif
+
+struct zzip_version 
+{ 
+    char   version[1]; 
+    char   ostype[1]; 
+} __attribute__((packed));
+
+struct zzip_dostime 
+{ 
+    char   time[2]; 
+    char   date[2]; 
+} __attribute__((packed)); 
+
+#define ZZIP_CHECKMAGIC(__p,__A,__B,__C,__D) \
+    ( (((char*)(__p))[0]==(__A)) && \
+      (((char*)(__p))[1]==(__B)) && \
+      (((char*)(__p))[2]==(__C)) && \
+      (((char*)(__p))[3]==(__D)) )
+
+/* A. Local file header */
+struct zzip_file_header
+{
+#   define ZZIP_FILE_HEADER_MAGIC 0x04034b50
+#   define ZZIP_FILE_HEADER_CHECKMAGIC(__p) ZZIP_CHECKMAGIC(__p,'P','K','\3','\4')
+    char   z_magic[4]; /* local file header signature (0x04034b50) */
+    struct zzip_version z_extract; /* version needed to extract */
+    char   z_flags[2]; /* general purpose bit flag */
+    char   z_compr[2]; /* compression method */
+    struct zzip_dostime z_dostime; /* last mod file time (dos format) */
+    char   z_crc32[4]; /* crc-32 */
+    char   z_csize[4]; /* compressed size */
+    char   z_usize[4]; /* uncompressed size */
+    char   z_namlen[2]; /* filename length (null if stdin) */
+    char   z_extras[2]; /* extra field length */
+    /* followed by filename (of variable size) */
+    /* followed by extra field (of variable size) */
+} __attribute__((packed));
+
+/* B. data descriptor 
+ * the data descriptor exists only if bit 3 of z_flags is set. It is byte aligned
+ * and immediately follows the last byte of compressed data. It is only used if
+ * the output media of the compressor was not seekable, eg. standard output.
+ */
+struct zzip_file_trailer
+{
+#   define ZZIP_FILE_TRAILER_MAGIC 0x08074B50
+#   define ZZIP_FILE_TRAILER_CHECKMAGIC(__p) ZZIP_CHECKMAGIC(__p,'P','K','\7','\8')
+    uint32_t z_magic; /* data descriptor signature (0x08074b50) */
+    uint32_t z_crc32; /* crc-32 */
+    uint32_t z_csize; /* compressed size */
+    uint32_t z_usize; /* uncompressed size */
+} __attribute__((packed));
+
+/* C. central directory structure:
+    [file header] . . . end of central dir record  
+*/
+
+/* directory file header 
+ * - a single entry including filename, extras and comment may not exceed 64k.
+ */
+
+struct zzip_root_dirent
+{
+#   define ZZIP_ROOT_DIRENT_MAGIC 0x02014b50
+#   define ZZIP_ROOT_DIRENT_CHECKMAGIC(__p) ZZIP_CHECKMAGIC(__p,'P','K','\1','\2')
+    char  z_magic[4];  /* central file header signature (0x02014b50) */
+    struct zzip_version z_encoder;  /* version made by */
+    struct zzip_version z_extract;  /* version need to extract */
+    char  z_flags[2];  /* general purpose bit flag */
+    char  z_compr[2];  /* compression method */
+    struct zzip_dostime z_dostime;  /* last mod file time&date (dos format) */
+    char  z_crc32[4];  /* crc-32 */
+    char  z_csize[4];  /* compressed size */
+    char  z_usize[4];  /* uncompressed size */
+    char  z_namlen[2]; /* filename length (null if stdin) */
+    char  z_extras[2];  /* extra field length */
+    char  z_comment[2]; /* file comment length */
+    char  z_diskstart[2]; /* disk number of start (if spanning zip over multiple disks) */
+    char  z_filetype[2];  /* internal file attributes, bit0 = ascii */
+    char  z_filemode[4];  /* extrnal file attributes, eg. msdos attrib byte */
+    char  z_off[4];    /* relative offset of local file header, seekval if singledisk */
+    /* followed by filename (of variable size) */
+    /* followed by extra field (of variable size) */
+    /* followed by file comment (of variable size) */
+} __attribute__((packed)); 
+
+/* end of central dir record */
+struct zzip_disk_trailer
+{
+#   define ZZIP_DISK_TRAILER_MAGIC 0x06054b50
+#   define ZZIP_DISK_TRAILER_CHECKMAGIC(__p) ZZIP_CHECKMAGIC(__p,'P','K','\5','\6')
+    char  z_magic[4]; /* end of central dir signature (0x06054b50) */
+    char  z_disk[2];  /* number of this disk */
+    char  z_finaldisk[2]; /* number of the disk with the start of the central dir */
+    char  z_entries[2]; /* total number of entries in the central dir on this disk */
+    char  z_finalentries[2]; /* total number of entries in the central dir */
+    char  z_rootsize[4]; /* size of the central directory */
+    char  z_rootseek[4]; /* offset of start of central directory with respect to *
+                          * the starting disk number */
+    char  z_comment[2];  /* zipfile comment length */
+    /* followed by zipfile comment (of variable size) */
+} __attribute__((packed));
+
+/* z_flags */
+#define ZZIP_IS_ENCRYPTED(p)    ((*(unsigned char*)p)&1)
+#define ZZIP_IS_COMPRLEVEL(p)  (((*(unsigned char*)p)>>1)&3)
+#define ZZIP_IS_STREAMED(p)    (((*(unsigned char*)p)>>3)&1)
+
+/* z_compr */
+#define ZZIP_IS_STORED          0
+#define ZZIP_IS_SHRUNK          1
+#define ZZIP_IS_REDUCEDx1       2
+#define ZZIP_IS_REDUCEDx2       3
+#define ZZIP_IS_REDUCEDx3       4
+#define ZZIP_IS_REDUCEDx4       5
+#define ZZIP_IS_IMPLODED        6
+#define ZZIP_IS_TOKENIZED       7
+#define ZZIP_IS_DEFLATED        8
+#define ZZIP_IS_DEFLATED_BETTER 9
+#define ZZIP_IS_IMPLODED_BETTER 10
+
+# ifdef _MSC_VER
+# pragma pack(pop)
+# endif
+
+#endif /* _ZZIPFORMAT_H */
+
+
+
+
diff --git a/zzip/info.c b/zzip/info.c
new file mode 100644 (file)
index 0000000..144b163
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Author: 
+ *      Guido Draheim <guidod@gmx.de>
+ *
+ * Copyright (c) 2000,2001,2002,2003 Guido Draheim
+ *          All rights reserved,
+ *          use under the restrictions of the
+ *          Lesser GNU General Public License
+ *          or alternatively the restrictions 
+ *          of the Mozilla Public License 1.1
+ */
+
+#include <zzip/lib.h>                                   /* exported... */
+#include <zzip/file.h>
+#include <zzip/format.h>
+
+#ifdef ZZIP_HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#else
+#include <stdlib.h>
+#include <stdio.h>
+#endif
+
+/** 
+ *  just returns dir->errcode of the ZZIP_DIR handle 
+ *  see: => zzip_dir_open, => zzip_diropen, => zzip_readdir, => zzip_dir_read
+ */
+int 
+zzip_error(ZZIP_DIR * dir)   
+{   
+    return dir->errcode; 
+}
+
+/** => zzip_error
+ *  This function just does dir->errcode = errcode 
+ */
+void 
+zzip_seterror(ZZIP_DIR * dir, int errcode)   
+{ dir->errcode = errcode; }
+
+/** 
+ * This function will just return fp->dir 
+ *
+ * If a ZZIP_FILE is contained within a zip-file that one will be a valid
+ * pointer, otherwise a NULL is returned and the ZZIP_FILE wraps a real file.
+ */
+ZZIP_DIR * 
+zzip_dirhandle(ZZIP_FILE * fp)   
+{ 
+    return fp->dir; 
+}
+
+/** => zzip_dirhandle
+ *  This function will just return dir->fd 
+ *
+ * If a ZZIP_DIR does point to a zipfile then the file-descriptor of that
+ * zipfile is returned, otherwise a NULL is returned and the ZZIP_DIR wraps 
+ * a real directory DIR (if you have dirent on your system).
+ */
+int 
+zzip_dirfd(ZZIP_DIR* dir)   
+{ 
+    return dir->fd; 
+}
+
+/**
+ * return static const string of the known compression methods, 
+ * otherwise just "zipped" is returned
+ */
+zzip_char_t*
+zzip_compr_str(int compr)
+{
+    switch(compr)
+    {
+    case ZZIP_IS_STORED:               return "stored";
+    case ZZIP_IS_SHRUNK:               return "shrunk";
+    case ZZIP_IS_REDUCEDx1:
+    case ZZIP_IS_REDUCEDx2:
+    case ZZIP_IS_REDUCEDx3:
+    case ZZIP_IS_REDUCEDx4:            return "reduced";
+    case ZZIP_IS_IMPLODED:             return "imploded";
+    case ZZIP_IS_TOKENIZED:            return "tokenized";
+    case ZZIP_IS_DEFLATED:             return "deflated";
+    case ZZIP_IS_DEFLATED_BETTER:      return "deflatedX";
+    case ZZIP_IS_IMPLODED_BETTER:      return "implodedX";
+    default:
+        if (0 < compr && compr < 256)   return "zipped"; 
+        else
+        {
+#      ifdef S_ISDIR
+            if (S_ISDIR(compr))                return "directory";
+#      endif
+#      ifdef S_ISCHR
+            if (S_ISCHR(compr))                return "is/chr";
+#      endif
+#      ifdef S_ISBLK
+            if (S_ISBLK(compr))                return "is/blk";
+#      endif
+#      ifdef S_ISFIFO
+            if (S_ISFIFO(compr))       return "is/fifo";
+#      endif
+#      ifdef S_ISSOCK
+            if (S_ISSOCK(compr))       return "is/sock";
+#      endif
+#      ifdef S_ISLNK
+            if (S_ISLNK(compr))                return "is/lnk";
+#      endif
+            return "special";
+        }
+    }/*switch*/
+}
+
+/** => zzip_file_real
+ * This function checks if the ZZIP_DIR-handle is wrapping 
+ * a real directory or a zip-archive. 
+ * Returns 1 for a stat'able directory, and 0 for a handle to zip-archive.
+ */ 
+int
+zzip_dir_real(ZZIP_DIR* dir)
+{
+    return dir->realdir != 0;
+}
+
+/**
+ * This function checks if the ZZIP_FILE-handle is wrapping 
+ * a real file or a zip-contained file. 
+ * Returns 1 for a stat'able file, and 0 for a file inside a zip-archive.
+ */
+int
+zzip_file_real(ZZIP_FILE* fp)
+{
+    return fp->dir == 0; /* ie. not dependent on a zip-arch-dir  */
+}
+
+/** => zzip_file_real
+ * This function returns the posix DIR* handle (if one exists).
+ * Check before with => zzip_dir_real if the
+ * the ZZIP_DIR points to a real directory.
+ */
+void*
+zzip_realdir(ZZIP_DIR* dir)
+{
+    return dir->realdir;
+}
+
+/** => zzip_file_real
+ * This function returns the posix file descriptor (if one exists).
+ * Check before with => zzip_file_real if the
+ * the ZZIP_FILE points to a real file.
+ */
+int
+zzip_realfd(ZZIP_FILE* fp)
+{
+    return fp->fd;
+}
+
+/* 
+ * Local variables:
+ * c-file-style: "stroustrup"
+ * End:
+ */
diff --git a/zzip/lib.h b/zzip/lib.h
new file mode 100644 (file)
index 0000000..8ff1333
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Author: 
+ *      Guido Draheim <guidod@gmx.de>
+ *      Tomi Ollila <Tomi.Ollila@iki.fi>
+ *
+ * Copyright (c) 1999,2000,2001,2002,2003 Guido Draheim
+ *          All rights reserved
+ *          use under the restrictions of the
+ *          Lesser GNU General Public License
+ *          or alternatively the restrictions 
+ *          of the Mozilla Public License 1.1
+ *
+ * This is the private header containing definitions that are not
+ * use by a libzzip user application. Writing an extension lib that
+ * uses libzzip will still want to include this. The extension
+ * write should make way to have the ISO C9X integer types defined.
+ */
+#ifndef _ZZIP_LIB_H /* zzip.h */
+#define _ZZIP_LIB_H
+
+#include <zzip/zzip.h>
+#include <zzip/plugin.h>
+#include <zzip/stdint.h>
+
+/*
+ * this structure cannot be wildly enlarged... (see zzip-zip.c)
+ */
+struct zzip_dir_hdr
+{
+    uint32_t    d_usize;        /* uncompressed size */
+    uint32_t    d_csize;        /* compressed size */
+    uint32_t    d_crc32;        /* the adler32-checksum */
+    uint32_t    d_off;          /* offset of file in zipfile */
+    uint16_t    d_reclen;       /* next dir_hdr structure offset */
+    uint16_t    d_namlen;       /* explicit namelen of d_name */
+    uint8_t     d_compr;        /* the compression type, 0 = store, 8 = inflate */
+    char        d_name[1];      /* the actual name of the entry, may contain DIRSEPs */
+};
+#define _ZZIP_DIRENT_HAVE_D_NAMLEN
+#define _ZZIP_DIRENT_HAVE_D_OFF
+#define _ZZIP_DIRENT_HAVE_D_RECLEN
+
+/*
+ * you shall not use this struct anywhere else than in zziplib sources.
+ */
+struct zzip_dir
+{
+    int fd;
+    int errcode; /* zzip_error_t */
+    long refcount;
+    struct {
+        struct zzip_file * fp;  /* reduce a lot of alloc/deallocations by */
+        char * buf32k;         /* caching one entry of these data structures */
+    } cache;
+    struct zzip_dir_hdr * hdr0;  /* zfi; */
+    struct zzip_dir_hdr * hdr;   /* zdp; directory pointer, for dirent stuff */
+    struct zzip_file * currentfp; /* last fp used... */
+    struct zzip_dirent dirent;
+    void*  realdir;               /* e.g. DIR* from posix dirent.h */
+    char*  realname;
+    zzip_strings_t* fileext;      /* list of fileext to test for */
+    zzip_plugin_io_t io;          /* vtable for io routines */
+}; 
+
+#define ZZIP_32K 32768
+
+/* try to open a zip-basename with default_fileext */
+int      __zzip_try_open (zzip_char_t* filename, int filemode,
+                          zzip_strings_t* ext, zzip_plugin_io_t io);
+
+ZZIP_DIR * 
+zzip_dir_fdopen(int fd, zzip_error_t * errcode_p);
+
+ZZIP_DIR* 
+zzip_dir_fdopen_ext_io(int fd, zzip_error_t * errorcode_p,
+                       zzip_strings_t* ext, const zzip_plugin_io_t io);
+
+ZZIP_DIR* /*depracated*/
+zzip_dir_alloc_ext_io (zzip_strings_t* ext, const zzip_plugin_io_t io);
+
+/* get 16/32 bits from little-endian zip-file to host byteorder */
+uint32_t __zzip_get32(unsigned char * s);
+uint16_t __zzip_get16(unsigned char * s);
+
+#ifdef __i386__
+#define ZZIP_GET32(x) (*(uint32_t*)(x))
+#define ZZIP_GET16(x) (*(uint16_t*)(x))
+#else
+#define ZZIP_GET32(x) (__zzip_get32(x))
+#define ZZIP_GET16(x) (__zzip_get16(x))
+#endif
+
+#endif /* _ZZIP_H */
+
diff --git a/zzip/stat.c b/zzip/stat.c
new file mode 100644 (file)
index 0000000..43b4bfc
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Author: 
+ *     Guido Draheim <guidod@gmx.de>
+ *     Tomi Ollila <Tomi.Ollila@iki.fi>
+ *
+ * Copyright (c) 1999,2000,2001,2002 Guido Draheim
+ *         All rights reserved,
+ *         use under the restrictions of the
+ *         Lesser GNU General Public License
+ *          or alternatively the restrictions 
+ *          of the Mozilla Public License 1.1
+ *
+ * Description:
+ *      although this file is defining a function called zzip_stat it
+ *      will not need a real stat(2) exported by the Operating System.
+ *      It will just try to fill the fields of the ZZIP_STAT structure
+ *      of 
+ */
+
+#include <zzip/lib.h>                                   /* exported...*/
+#include <string.h>
+
+/**
+ * obtain information about a filename in an opened zip-archive without 
+ * opening that file first. Mostly used to obtain the uncompressed 
+ * size of a file inside a zip-archive. see => zzip_dir_open.
+ */
+int 
+zzip_dir_stat(ZZIP_DIR * dir, zzip_char_t* name, ZZIP_STAT * zs, int flags)
+{
+    struct zzip_dir_hdr * hdr = dir->hdr0;
+    int (*cmp)(zzip_char_t*, zzip_char_t*);
+
+    cmp = (flags & ZZIP_CASEINSENSITIVE) ? strcasecmp : strcmp;
+
+    if (flags & ZZIP_IGNOREPATH)
+    {
+        char* n = strrchr(name, '/');
+        if (n)  name = n + 1;
+    }
+
+    if (hdr)
+    while (1)
+    {
+        register char* hdr_name = hdr->d_name;
+        if (flags & ZZIP_IGNOREPATH)
+        {
+            register char* n = strrchr(hdr_name, '/');
+            if (n)  hdr_name = n + 1;
+        }
+
+       if (! cmp(hdr_name, name))
+            break;
+
+       if (! hdr->d_reclen)
+       {
+            dir->errcode = ZZIP_ENOENT;
+            return -1;
+       }
+
+       hdr = (struct zzip_dir_hdr *) ((char *)hdr + hdr->d_reclen);
+    }
+
+    zs->d_compr = hdr->d_compr;
+    zs->d_csize = hdr->d_csize;
+    zs->st_size = hdr->d_usize;
+    zs->d_name  = hdr->d_name;
+
+    return 0;
+}
+
+/* 
+ * Local variables:
+ * c-file-style: "stroustrup"
+ * End:
+ */