source: toilet/trunk/src/io.c @ 2263

Last change on this file since 2263 was 1469, checked in by Sam Hocevar, 16 years ago
  • Fix build for systems with no zlib-devel.
  • Property svn:keywords set to Id
File size: 4.3 KB
Line 
1/*
2 *  TOIlet        The Other Implementation’s letters
3 *  Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: io.c 1469 2006-12-14 21:38:06Z sam $
7 *
8 *  This program is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15/*
16 * This file contains functions for compressed file I/O.
17 */
18
19#include "config.h"
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <stdint.h>
24#include <string.h>
25
26#if defined HAVE_ZLIB_H
27#   include <zlib.h>
28#   define READSIZE  128 /* Read buffer size */
29#   define WRITESIZE 128 /* Inflate buffer size */
30#endif
31
32#include "io.h"
33
34#if defined HAVE_ZLIB_H
35static int zipread(TOIFILE *, void *, unsigned int);
36#endif
37
38struct toifile
39{
40#if defined HAVE_ZLIB_H
41    unsigned char read_buffer[READSIZE];
42    z_stream stream;
43    gzFile gz;
44    int eof, zip;
45#endif
46    FILE *f;
47};
48
49TOIFILE *toiopen(char const *path, const char *mode)
50{
51    TOIFILE *toif = malloc(sizeof(*toif));
52
53#if defined HAVE_ZLIB_H
54    uint8_t buf[4];
55    unsigned int skip_size = 0;
56
57    toif->gz = gzopen(path, "rb");
58    if(!toif->gz)
59    {
60        free(toif);
61        return NULL;
62    }
63
64    toif->eof = 0;
65    toif->zip = 0;
66
67    /* Parse ZIP file and go to start of first file */
68    gzread(toif->gz, buf, 4);
69    if(memcmp(buf, "PK\3\4", 4))
70    {
71        gzseek(toif->gz, 0, SEEK_SET);
72        return toif;
73    }
74
75    toif->zip = 1;
76
77    gzseek(toif->gz, 22, SEEK_CUR);
78
79    gzread(toif->gz, buf, 2); /* Filename size */
80    skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
81    gzread(toif->gz, buf, 2); /* Extra field size */
82    skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
83
84    gzseek(toif->gz, skip_size, SEEK_CUR);
85
86    /* Initialise inflate stream */
87    toif->stream.total_out = 0;
88    toif->stream.zalloc = NULL;
89    toif->stream.zfree = NULL;
90    toif->stream.opaque = NULL;
91    toif->stream.next_in = NULL;
92    toif->stream.avail_in = 0;
93
94    if(inflateInit2(&toif->stream, -MAX_WBITS))
95    {
96        free(toif);
97        gzclose(toif->gz);
98        return NULL;
99    }
100#else
101    toif->f = fopen(path, mode);
102
103    if(!toif->f)
104    {
105        free(toif);
106        return NULL;
107    }
108#endif
109
110    return toif;
111}
112
113int toiclose(TOIFILE *toif)
114{
115#if defined HAVE_ZLIB_H
116    gzFile gz = toif->gz;
117    if(toif->zip)
118        inflateEnd(&toif->stream);
119    free(toif);
120    return gzclose(gz);
121#else
122    FILE *f = toif->f;
123    free(toif);
124    return fclose(f);
125#endif
126}
127
128int toieof(TOIFILE *toif)
129{
130#if defined HAVE_ZLIB_H
131    return toif->zip ? toif->eof : gzeof(toif->gz);
132#else
133    return feof(toif->f);
134#endif
135}
136
137char *toigets(char *s, int size, TOIFILE *toif)
138{
139#if defined HAVE_ZLIB_H
140    if(toif->zip)
141    {
142        int i;
143
144        for(i = 0; i < size; i++)
145        {
146            int ret = zipread(toif, s + i, 1);
147
148            if(ret < 0)
149                return NULL;
150
151            if(ret == 0 || s[i] == '\n')
152            {
153                if(i + 1 < size)
154                    s[i + 1] = '\0';
155                return s;
156            }
157        }
158
159        return s;
160    }
161
162    return gzgets(toif->gz, s, size);
163#else
164    return fgets(s, size, toif->f);
165#endif
166}
167
168#if defined HAVE_ZLIB_H
169static int zipread(TOIFILE *toif, void *buf, unsigned int len)
170{
171    unsigned int total_read = 0;
172
173    if(len == 0)
174        return 0;
175
176    toif->stream.next_out = buf;
177    toif->stream.avail_out = len;
178
179    while(toif->stream.avail_out > 0)
180    {
181        unsigned int tmp;
182        int ret = 0;
183
184        if(toif->stream.avail_in == 0 && !gzeof(toif->gz))
185        {
186            int bytes_read;
187
188            bytes_read = gzread(toif->gz, toif->read_buffer, READSIZE);
189            if(bytes_read < 0)
190                return -1;
191
192            toif->stream.next_in = toif->read_buffer;
193            toif->stream.avail_in = bytes_read;
194        }
195
196        tmp = toif->stream.total_out;
197        ret = inflate(&toif->stream, Z_SYNC_FLUSH);
198        total_read += toif->stream.total_out - tmp;
199
200        if(ret == Z_STREAM_END)
201        {
202            toif->eof = 1;
203            return total_read;
204        }
205
206        if(ret != Z_OK)
207            return ret;
208    }
209
210    return total_read;
211}
212#endif
213
Note: See TracBrowser for help on using the repository browser.