source: libcaca/trunk/cucul/file.c @ 2536

Last change on this file since 2536 was 2536, checked in by Sam Hocevar, 11 years ago
  • cucul/file.c: fix a typo causing build failures when zlib is not here.
File size: 5.9 KB
Line 
1/*
2 *  libcucul      Canvas for ultrafast compositing of Unicode letters
3 *  Copyright (c) 2006-2007 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id$
7 *
8 *  This library 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#if !defined __KERNEL__
22#   include <stdio.h>
23#   include <stdlib.h>
24#   include <string.h>
25#   if defined HAVE_ZLIB_H
26#       include <zlib.h>
27#       define READSIZE  128 /* Read buffer size */
28#       define WRITESIZE 128 /* Inflate buffer size */
29#   endif
30#endif
31
32#include "cucul.h"
33#include "cucul_internals.h"
34
35#if !defined __KERNEL__ && defined HAVE_ZLIB_H
36static int zipread(cucul_file_t *, void *, unsigned int);
37#endif
38
39#if !defined __KERNEL__
40struct cucul_file
41{
42#   if defined HAVE_ZLIB_H
43    uint8_t read_buffer[READSIZE];
44    z_stream stream;
45    gzFile gz;
46    int eof, zip, total;
47#   endif
48    FILE *f;
49    int readonly;
50};
51#endif
52
53cucul_file_t *cucul_file_open(char const *path, const char *mode)
54{
55#if defined __KERNEL__
56    seterrno(ENOSYS);
57    return NULL;
58#else
59    cucul_file_t *fp = malloc(sizeof(*fp));
60
61    fp->readonly = !!strchr(mode, 'r');
62
63#   if defined HAVE_ZLIB_H
64    uint8_t buf[4];
65    unsigned int skip_size = 0;
66
67    fp->gz = gzopen(path, fp->readonly ? "rb" : "wb");
68    if(!fp->gz)
69    {
70        free(fp);
71        return NULL;
72    }
73
74    fp->eof = 0;
75    fp->zip = 0;
76    fp->total = 0;
77
78    if(fp->readonly)
79    {
80        /* Parse ZIP file and go to start of first file */
81        gzread(fp->gz, buf, 4);
82        if(memcmp(buf, "PK\3\4", 4))
83        {
84            gzseek(fp->gz, 0, SEEK_SET);
85            return fp;
86        }
87
88        fp->zip = 1;
89
90        gzseek(fp->gz, 22, SEEK_CUR);
91
92        gzread(fp->gz, buf, 2); /* Filename size */
93        skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
94        gzread(fp->gz, buf, 2); /* Extra field size */
95        skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
96
97        gzseek(fp->gz, skip_size, SEEK_CUR);
98
99        /* Initialise inflate stream */
100        fp->stream.total_out = 0;
101        fp->stream.zalloc = NULL;
102        fp->stream.zfree = NULL;
103        fp->stream.opaque = NULL;
104        fp->stream.next_in = NULL;
105        fp->stream.avail_in = 0;
106
107        if(inflateInit2(&fp->stream, -MAX_WBITS))
108        {
109            free(fp);
110            gzclose(fp->gz);
111            return NULL;
112        }
113    }
114#   else
115    fp->f = fopen(path, mode);
116
117    if(!fp->f)
118    {
119        free(fp);
120        return NULL;
121    }
122#   endif
123
124    return fp;
125#endif
126}
127
128int cucul_file_close(cucul_file_t *fp)
129{
130#if defined __KERNEL__
131    seterrno(ENOSYS);
132    return 0;
133#elif defined HAVE_ZLIB_H
134    gzFile gz = fp->gz;
135    if(fp->zip)
136        inflateEnd(&fp->stream);
137    free(fp);
138    return gzclose(gz);
139#else
140    FILE *f = fp->f;
141    free(fp);
142    return fclose(f);
143#endif
144}
145
146uint64_t cucul_file_tell(cucul_file_t *fp)
147{
148#if defined __KERNEL__
149    seterrno(ENOSYS);
150    return 0;
151#elif defined HAVE_ZLIB_H
152    if(fp->zip)
153        return fp->total;
154    return gztell(fp->gz);
155#else
156    return ftell(fp->f);
157#endif
158}
159
160size_t cucul_file_read(cucul_file_t *fp, void *ptr, size_t size)
161{
162#if defined __KERNEL__
163    seterrno(ENOSYS);
164    return 0;
165#elif defined HAVE_ZLIB_H
166    if(fp->zip)
167        return zipread(fp, ptr, size);
168    return gzread(fp->gz, ptr, size);
169#else
170    return fread(ptr, 1, size, fp->f);
171#endif
172}
173
174size_t cucul_file_write(cucul_file_t *fp, const void *ptr, size_t size)
175{
176#if defined __KERNEL__
177    seterrno(ENOSYS);
178    return 0;
179#else
180    if(fp->readonly)
181        return 0;
182
183#   if defined HAVE_ZLIB_H
184    if(fp->zip)
185    {
186        /* FIXME: zip files are not supported */
187        seterrno(ENOSYS);
188        return 0;
189    }
190    return gzwrite(fp->gz, ptr, size);
191#   else
192    return fwrite(ptr, 1, size, fp->f);
193#   endif
194#endif
195}
196
197char *cucul_file_gets(cucul_file_t *fp, char *s, int size)
198{
199#if defined __KERNEL__
200    seterrno(ENOSYS);
201    return NULL;
202#elif defined HAVE_ZLIB_H
203    if(fp->zip)
204    {
205        int i;
206
207        for(i = 0; i < size; i++)
208        {
209            int ret = zipread(fp, s + i, 1);
210
211            if(ret < 0)
212                return NULL;
213
214            if(ret == 0 || s[i] == '\n')
215            {
216                if(i + 1 < size)
217                    s[i + 1] = '\0';
218                return s;
219            }
220        }
221
222        return s;
223    }
224
225    return gzgets(fp->gz, s, size);
226#else
227    return fgets(s, size, fp->f);
228#endif
229}
230
231int cucul_file_eof(cucul_file_t *fp)
232{
233#if defined __KERNEL__
234    return 1;
235#elif defined HAVE_ZLIB_H
236    return fp->zip ? fp->eof : gzeof(fp->gz);
237#else
238    return feof(fp->f);
239#endif
240}
241
242#if !defined __KERNEL__ && defined HAVE_ZLIB_H
243static int zipread(cucul_file_t *fp, void *buf, unsigned int len)
244{
245    unsigned int total_read = 0;
246
247    if(len == 0)
248        return 0;
249
250    fp->stream.next_out = buf;
251    fp->stream.avail_out = len;
252
253    while(fp->stream.avail_out > 0)
254    {
255        unsigned int tmp;
256        int ret = 0;
257
258        if(fp->stream.avail_in == 0 && !gzeof(fp->gz))
259        {
260            int bytes_read;
261
262            bytes_read = gzread(fp->gz, fp->read_buffer, READSIZE);
263            if(bytes_read < 0)
264                return -1;
265
266            fp->stream.next_in = fp->read_buffer;
267            fp->stream.avail_in = bytes_read;
268        }
269
270        tmp = fp->stream.total_out;
271        ret = inflate(&fp->stream, Z_SYNC_FLUSH);
272        total_read += fp->stream.total_out - tmp;
273
274        if(ret == Z_STREAM_END)
275        {
276            fp->eof = 1;
277            fp->total += total_read;
278            return total_read;
279        }
280
281        if(ret != Z_OK)
282            return ret;
283    }
284
285    fp->total += total_read;
286    return total_read;
287}
288#endif
289
Note: See TracBrowser for help on using the repository browser.