
/*
 * 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
 */

#include <zzip/lib.h>           /* exported... */
#include <zlib.h>

#include <string.h>
#include <errno.h>

#include <zzip/file.h>

/* *INDENT-OFF* */
static struct errlistentry { int code; const char* mesg; } 
errlist[] = 
{
    { ZZIP_NO_ERROR,        "No error" },
    { ZZIP_OUTOFMEM,        
      "could not get temporary memory for internal structures" },
    { ZZIP_DIR_OPEN,        "Failed to open zip-file %s" },
    { ZZIP_DIR_STAT,        "Failed to fstat zip-file %s" },
    { ZZIP_DIR_SEEK,        "Failed to lseek zip-file %s" },
    { ZZIP_DIR_READ,        "Failed to read zip-file %s"},  
    { ZZIP_DIR_TOO_SHORT,   "zip-file %s too short" },
    { ZZIP_DIR_EDH_MISSING, "zip-file central directory not found" },
    { ZZIP_DIRSIZE,         "Directory size too big..." },
    { ZZIP_ENOENT,          "No such file found in zip-file %s" },
    { ZZIP_UNSUPP_COMPR,    "Unsupported compression format" },
    { ZZIP_CORRUPTED,       "Zipfile corrupted" }, 
    { ZZIP_UNDEF,           "Some undefined error occurred" },
    { ZZIP_DIR_LARGEFILE,   "Directory is largefile variant" },
    { 0, 0 },
};
/* *INDENT-ON* */


#define errlistSIZE (sizeof(errlist)/sizeof(*errlist))

/**
 * returns the static string for the given error code. The
 * error code can be either a normal system error (a
 * positive error code will flag this), it can be => libz
 * error code (a small negative error code will flag this)
 * or it can be an error code from => libzzip, which is an
 * negative value lower than => ZZIP_ERROR
 */
zzip_char_t *
zzip_strerror(int errcode)
{
    if (errcode < ZZIP_ERROR && errcode > ZZIP_ERROR - 32)
    {
        struct errlistentry *err = errlist;

        for (; err->mesg; err++)
        {
            if (err->code == errcode)
                return err->mesg;
        }
        errcode = EINVAL;
    }

    if (errcode < 0)
    {
        if (errcode == -1)
            return strerror(errcode);
        else
            return zError(errcode);
    }

    return strerror(errcode);
}

/** => zzip_strerror
 * This function fetches the errorcode from the => DIR-handle and 
 * runs it through => zzip_strerror to obtain the static string
 * describing the error.
 */
zzip_char_t *
zzip_strerror_of(ZZIP_DIR * dir)
{
    if (! dir)
        return strerror(errno);
    return zzip_strerror(dir->errcode);
}

/* *INDENT-OFF* */
static struct errnolistentry { int code; int e_no; } 
errnolist[] =
{
    { Z_STREAM_ERROR, EPIPE },
    { Z_DATA_ERROR, ESPIPE },
    { Z_MEM_ERROR, ENOMEM },
    { Z_BUF_ERROR, EMFILE },
    { Z_VERSION_ERROR, ENOEXEC },
      
    { ZZIP_DIR_OPEN, ENOTDIR },
    { ZZIP_DIR_STAT, EREMOTE },
    { ZZIP_DIR_SEEK, ESPIPE },
#  ifdef ESTRPIPE
    { ZZIP_DIR_READ, ESTRPIPE},  
#  else
    { ZZIP_DIR_READ, EPIPE},  
#  endif
    { ZZIP_DIR_TOO_SHORT, ENOEXEC },
#  ifdef ENOMEDIUM
    { ZZIP_DIR_EDH_MISSING, ENOMEDIUM },
#  else
    { ZZIP_DIR_EDH_MISSING, EIO },
#  endif
    { ZZIP_DIRSIZE, EFBIG },
    { ZZIP_OUTOFMEM, ENOMEM },
    { ZZIP_ENOENT, ENOENT },
#  ifdef EPFNOSUPPORT
    { ZZIP_UNSUPP_COMPR, EPFNOSUPPORT },
#  else
    { ZZIP_UNSUPP_COMPR, EACCES },
#  endif 
# ifdef EILSEQ
    { ZZIP_CORRUPTED, EILSEQ }, 
# else
    { ZZIP_CORRUPTED, ELOOP }, 
# endif
    { ZZIP_UNDEF, EINVAL },
    { 0, 0 },
};    
/* *INDENT-ON* */

/**
 * map the error code to a system error code. This is used
 * for the drop-in replacement functions to return a value
 * that can be interpreted correctly by code sections that
 * are unaware of the fact they their => open(2) call had been
 * diverted to a file inside a zip-archive.
 */
int
zzip_errno(int errcode)
{
    if (errcode >= -1)
    {
        return errno;
    } else
    {
        struct errnolistentry *err = errnolist;

        for (; err->code; err++)
        {
            if (err->code == errcode)
                return err->e_no;
        }
        return EINVAL;
    }
}

/* 
 * Local variables:
 * c-file-style: "stroustrup"
 * End:
 */
