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

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