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

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