local gzFile gz_open()

in zlibWrapper/gzlib.c [94:270]


local gzFile gz_open(path, fd, mode)
    const void *path;
    int fd;
    const char *mode;
{
    gz_statep state;
    z_size_t len;
    int oflag;
#ifdef O_CLOEXEC
    int cloexec = 0;
#endif
#ifdef O_EXCL
    int exclusive = 0;
#endif

    /* check input */
    if (path == NULL)
        return NULL;

    /* allocate gzFile structure to return */
    state.state = (gz_state*)malloc(sizeof(gz_state));
    if (state.state == NULL)
        return NULL;
    state.state->size = 0;            /* no buffers allocated yet */
    state.state->want = GZBUFSIZE;    /* requested buffer size */
    state.state->msg = NULL;          /* no error message yet */

    /* interpret mode */
    state.state->mode = GZ_NONE;
    state.state->level = Z_DEFAULT_COMPRESSION;
    state.state->strategy = Z_DEFAULT_STRATEGY;
    state.state->direct = 0;
    while (*mode) {
        if (*mode >= '0' && *mode <= '9')
            state.state->level = *mode - '0';
        else
            switch (*mode) {
            case 'r':
                state.state->mode = GZ_READ;
                break;
#ifndef NO_GZCOMPRESS
            case 'w':
                state.state->mode = GZ_WRITE;
                break;
            case 'a':
                state.state->mode = GZ_APPEND;
                break;
#endif
            case '+':       /* can't read and write at the same time */
                free(state.state);
                return NULL;
            case 'b':       /* ignore -- will request binary anyway */
                break;
#ifdef O_CLOEXEC
            case 'e':
                cloexec = 1;
                break;
#endif
#ifdef O_EXCL
            case 'x':
                exclusive = 1;
                break;
#endif
            case 'f':
                state.state->strategy = Z_FILTERED;
                break;
            case 'h':
                state.state->strategy = Z_HUFFMAN_ONLY;
                break;
            case 'R':
                state.state->strategy = Z_RLE;
                break;
            case 'F':
                state.state->strategy = Z_FIXED;
                break;
            case 'T':
                state.state->direct = 1;
                break;
            default:        /* could consider as an error, but just ignore */
                ;
            }
        mode++;
    }

    /* must provide an "r", "w", or "a" */
    if (state.state->mode == GZ_NONE) {
        free(state.state);
        return NULL;
    }

    /* can't force transparent read */
    if (state.state->mode == GZ_READ) {
        if (state.state->direct) {
            free(state.state);
            return NULL;
        }
        state.state->direct = 1;      /* for empty file */
    }

    /* save the path name for error messages */
#ifdef WIDECHAR
    if (fd == -2) {
        len = wcstombs(NULL, path, 0);
        if (len == (z_size_t)-1)
            len = 0;
    }
    else
#endif
        len = strlen((const char *)path);
    state.state->path = (char *)malloc(len + 1);
    if (state.state->path == NULL) {
        free(state.state);
        return NULL;
    }
#ifdef WIDECHAR
    if (fd == -2)
        if (len)
            wcstombs(state.state->path, path, len + 1);
        else
            *(state.state->path) = 0;
    else
#endif
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
        (void)snprintf(state.state->path, len + 1, "%s", (const char *)path);
#else
        strcpy(state.state->path, (const char*)path);
#endif

    /* compute the flags for open() */
    oflag =
#ifdef O_LARGEFILE
        O_LARGEFILE |
#endif
#ifdef O_BINARY
        O_BINARY |
#endif
#ifdef O_CLOEXEC
        (cloexec ? O_CLOEXEC : 0) |
#endif
        (state.state->mode == GZ_READ ?
         O_RDONLY :
         (O_WRONLY | O_CREAT |
#ifdef O_EXCL
          (exclusive ? O_EXCL : 0) |
#endif
          (state.state->mode == GZ_WRITE ?
           O_TRUNC :
           O_APPEND)));

    /* open the file with the appropriate flags (or just use fd) */
    state.state->fd = fd > -1 ? fd : (
#ifdef WIDECHAR
        fd == -2 ? _wopen(path, oflag, 0666) :
#endif
        open((const char *)path, oflag, 0666));
    if (state.state->fd == -1) {
        free(state.state->path);
        free(state.state);
        return NULL;
    }
    if (state.state->mode == GZ_APPEND) {
        LSEEK(state.state->fd, 0, SEEK_END);  /* so gzoffset() is correct */
        state.state->mode = GZ_WRITE;         /* simplify later checks */
    }

    /* save the current position for rewinding (only if reading) */
    if (state.state->mode == GZ_READ) {
        state.state->start = LSEEK(state.state->fd, 0, SEEK_CUR);
        if (state.state->start == -1) state.state->start = 0;
    }

    /* initialize stream */
    gz_reset(state);

    /* return stream */
    return state.file;
}