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

Last change on this file since 2407 was 2407, checked in by Sam Hocevar, 14 years ago
  • Implement cucul_file_tell().
File size: 5.6 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    return NULL;
57#else
58    cucul_file_t *fp = malloc(sizeof(*fp));
59
60    fp->readonly = strchr(mode, 'r');
61
62#   if defined HAVE_ZLIB_H
63    uint8_t buf[4];
64    unsigned int skip_size = 0;
65
66    fp->gz = gzopen(path, fp->readonly ? "rb" : "wb");
67    if(!fp->gz)
68    {
69        free(fp);
70        return NULL;
71    }
72
73    fp->eof = 0;
74    fp->zip = 0;
75    fp->total = 0;
76
77    if(fp->readonly)
78    {
79        /* Parse ZIP file and go to start of first file */
80        gzread(fp->gz, buf, 4);
81        if(memcmp(buf, "PK\3\4", 4))
82        {
83            gzseek(fp->gz, 0, SEEK_SET);
84            return fp;
85        }
86
87        fp->zip = 1;
88
89        gzseek(fp->gz, 22, SEEK_CUR);
90
91        gzread(fp->gz, buf, 2); /* Filename size */
92        skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
93        gzread(fp->gz, buf, 2); /* Extra field size */
94        skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
95
96        gzseek(fp->gz, skip_size, SEEK_CUR);
97
98        /* Initialise inflate stream */
99        fp->stream.total_out = 0;
100        fp->stream.zalloc = NULL;
101        fp->stream.zfree = NULL;
102        fp->stream.opaque = NULL;
103        fp->stream.next_in = NULL;
104        fp->stream.avail_in = 0;
105
106        if(inflateInit2(&fp->stream, -MAX_WBITS))
107        {
108            free(fp);
109            gzclose(fp->gz);
110            return NULL;
111        }
112    }
113#   else
114    fp->f = fopen(path, fmode);
115
116    if(!fp->f)
117    {
118        free(fp);
119        return NULL;
120    }
121#   endif
122
123    return fp;
124#endif
125}
126
127int cucul_file_close(cucul_file_t *fp)
128{
129#if defined __KERNEL__
130    return 0;
131#elif defined HAVE_ZLIB_H
132    gzFile gz = fp->gz;
133    if(fp->zip)
134        inflateEnd(&fp->stream);
135    free(fp);
136    return gzclose(gz);
137#else
138    FILE *f = fp->f;
139    free(fp);
140    return fclose(f);
141#endif
142}
143
144uint64_t cucul_file_tell(cucul_file_t *fp)
145{
146#if defined __KERNEL__
147    return 0;
148#elif defined HAVE_ZLIB_H
149    if(fp->zip)
150        return fp->total;
151    return gztell(fp->gz);
152#else
153    return ftell(fp->f);
154#endif
155}
156
157size_t cucul_file_read(cucul_file_t *fp, void *ptr, size_t size)
158{
159#if defined __KERNEL__
160    return 0;
161#elif defined HAVE_ZLIB_H
162    if(fp->zip)
163        return zipread(fp, ptr, size);
164    return gzread(fp->gz, ptr, size);
165#else
166    return fread(ptr, 1, size, fp->f);
167#endif
168}
169
170size_t cucul_file_write(cucul_file_t *fp, const void *ptr, size_t size)
171{
172    if(fp->readonly)
173        return 0;
174
175#if defined __KERNEL__
176    return 0;
177#elif defined HAVE_ZLIB_H
178    /* FIXME: zip files are not supported */
179    return gzwrite(fp->gz, ptr, size);
180#else
181    return fwrite(ptr, 1, size, fp->f);
182#endif
183}
184
185char *cucul_file_gets(cucul_file_t *fp, char *s, int size)
186{
187#if defined __KERNEL__
188    return NULL;
189#elif defined HAVE_ZLIB_H
190    if(fp->zip)
191    {
192        int i;
193
194        for(i = 0; i < size; i++)
195        {
196            int ret = zipread(fp, s + i, 1);
197
198            if(ret < 0)
199                return NULL;
200
201            if(ret == 0 || s[i] == '\n')
202            {
203                if(i + 1 < size)
204                    s[i + 1] = '\0';
205                return s;
206            }
207        }
208
209        return s;
210    }
211
212    return gzgets(fp->gz, s, size);
213#else
214    return fgets(s, size, fp->f);
215#endif
216}
217
218int cucul_file_eof(cucul_file_t *fp)
219{
220#if defined __KERNEL__
221    return 1;
222#elif defined HAVE_ZLIB_H
223    return fp->zip ? fp->eof : gzeof(fp->gz);
224#else
225    return feof(fp->f);
226#endif
227}
228
229#if !defined __KERNEL__ && defined HAVE_ZLIB_H
230static int zipread(cucul_file_t *fp, void *buf, unsigned int len)
231{
232    unsigned int total_read = 0;
233
234    if(len == 0)
235        return 0;
236
237    fp->stream.next_out = buf;
238    fp->stream.avail_out = len;
239
240    while(fp->stream.avail_out > 0)
241    {
242        unsigned int tmp;
243        int ret = 0;
244
245        if(fp->stream.avail_in == 0 && !gzeof(fp->gz))
246        {
247            int bytes_read;
248
249            bytes_read = gzread(fp->gz, fp->read_buffer, READSIZE);
250            if(bytes_read < 0)
251                return -1;
252
253            fp->stream.next_in = fp->read_buffer;
254            fp->stream.avail_in = bytes_read;
255        }
256
257        tmp = fp->stream.total_out;
258        ret = inflate(&fp->stream, Z_SYNC_FLUSH);
259        total_read += fp->stream.total_out - tmp;
260
261        if(ret == Z_STREAM_END)
262        {
263            fp->eof = 1;
264            fp->total += total_read;
265            return total_read;
266        }
267
268        if(ret != Z_OK)
269            return ret;
270    }
271
272    fp->total += total_read;
273    return total_read;
274}
275#endif
276
Note: See TracBrowser for help on using the repository browser.