1 #pragma prototyped
2
3 /*
4 * gzip encoder/decoder
5 */
6
7 #include <codex.h>
8 #include <zlib.h>
9 #include <ctype.h>
10
11 #define MINLEVEL 1
12 #define MAXLEVEL 9
13
14 #define X(x) #x
15 #define S(x) X(x)
16
17 typedef struct State_s
18 {
19 Codex_t* codex;
20 gzFile* gz;
21 int crc;
22 int level;
23 } State_t;
24
25 static int
gzip_ident(Codexmeth_t * meth,const void * head,size_t headsize,char * name,size_t namesize)26 gzip_ident(Codexmeth_t* meth, const void* head, size_t headsize, char* name, size_t namesize)
27 {
28 unsigned char* h = (unsigned char*)head;
29
30 if (headsize >= 3 && h[0] == 0x1f && h[1] == 0x8b)
31 {
32 strncopy(name, meth->name, namesize);
33 return 1;
34 }
35 return 0;
36 }
37
38 static int
gzip_open(Codex_t * p,char * const args[],Codexnum_t flags)39 gzip_open(Codex_t* p, char* const args[], Codexnum_t flags)
40 {
41 register State_t* state;
42 const char* s;
43 char* e;
44 int i;
45 int v;
46 int crc = 1;
47 int level = MAXLEVEL;
48
49 i = 2;
50 while (s = args[i++])
51 {
52 if (isdigit(*s))
53 v = strton(s, &e, NiL, 0);
54 else
55 {
56 e = (char*)s;
57 if (e[0] == 'n' && e[1] == 'o')
58 {
59 e += 2;
60 v = 0;
61 }
62 else
63 v = 1;
64 }
65 if (!*e)
66 {
67 if (v < MINLEVEL || v > MAXLEVEL)
68 {
69 if (p->disc->errorf)
70 (*p->disc->errorf)(NiL, p->disc, 2, "%s: compression level must be in [%d..%d]", s, MINLEVEL, MAXLEVEL);
71 return -1;
72 }
73 level = v;
74 }
75 else if (!streq(e, "crc"))
76 crc = v;
77 else
78 {
79 if (p->disc->errorf)
80 (*p->disc->errorf)(NiL, p->disc, 2, "%s: unknown option", s);
81 return -1;
82 }
83 }
84 if (!(p->op = sfopen(NiL, "/dev/null", (p->flags & CODEX_DECODE) ? "r" : "w")))
85 {
86 if (p->disc->errorf)
87 (*p->disc->errorf)(NiL, p->disc, 2, "cannot swap main stream");
88 return -1;
89 }
90 sfswap(p->op, p->sp);
91 if (!(state = newof(0, State_t, 1, 0)))
92 {
93 if (p->disc->errorf)
94 (*p->disc->errorf)(NiL, p->disc, 2, "out of space");
95 return -1;
96 }
97 state->codex = p;
98 state->crc = crc;
99 state->level = level;
100 p->data = state;
101 return 0;
102 }
103
104 static int
gzip_init(Codex_t * p)105 gzip_init(Codex_t* p)
106 {
107 State_t* state = (State_t*)p->data;
108 char* m;
109 char mode[8];
110
111 m = mode;
112 if (p->flags & CODEX_ENCODE)
113 *m++ = 'w';
114 else
115 *m++ = 'r';
116 *m++ = 'b';
117 if (!state->crc)
118 *m++ = 'c';
119 *m++ = 'o';
120 *m++ = '0' + state->level;
121 *m = 0;
122 return (state->gz = gzfopen(p->op, mode)) ? 0 : -1;
123 }
124
125 static int
gzip_done(Codex_t * p)126 gzip_done(Codex_t* p)
127 {
128 State_t* state = (State_t*)p->data;
129 int r;
130
131 r = gzclose(state->gz) ? -1 : 0;
132 free(state);
133 return r;
134 }
135
136 static ssize_t
gzip_read(Sfio_t * f,Void_t * buf,size_t n,Sfdisc_t * dp)137 gzip_read(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* dp)
138 {
139 return gzread(((State_t*)CODEX(dp)->data)->gz, buf, n);
140 }
141
142 static ssize_t
gzip_write(Sfio_t * f,const Void_t * buf,size_t n,Sfdisc_t * dp)143 gzip_write(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* dp)
144 {
145 return gzwrite(((State_t*)CODEX(dp)->data)->gz, buf, n);
146 }
147
148 Codexmeth_t codex_gzip =
149 {
150 "gzip",
151 "gzip compression. The first parameter is the compression level,"
152 " " S(MINLEVEL) ":least, " S(MAXLEVEL) ":most(default). nocrc disables crc checks.",
153 0,
154 CODEX_DECODE|CODEX_ENCODE|CODEX_COMPRESS,
155 0,
156 gzip_ident,
157 gzip_open,
158 0,
159 gzip_init,
160 gzip_done,
161 gzip_read,
162 gzip_write,
163 0,
164 0,
165 0,
166 0,
167 0,
168 CODEXNEXT(gzip)
169 };
170
171 CODEXLIB(gzip)
172