source: trunk/kitgen/zlib.c@ 197

Last change on this file since 197 was 175, checked in by demin, 12 years ago

initial commit

File size: 5.8 KB
Line 
1/* Written by Jean-Claude Wippler, as part of Tclkit.
2 * March 2003 - placed in the public domain by the author.
3 *
4 * Interface to the "zlib" compression library
5 */
6
7#include "zlib.h"
8#include <tcl.h>
9
10typedef struct {
11 z_stream stream;
12 Tcl_Obj *indata;
13} zlibstream;
14
15static int
16zstreamincmd(ClientData cd, Tcl_Interp *ip, int objc, Tcl_Obj *CONST objv[])
17{
18 zlibstream *zp = (zlibstream*) cd;
19 int count = 0;
20 int e, index;
21 Tcl_Obj *obj;
22
23 static CONST84 char* cmds[] = { "fill", "drain", NULL, };
24
25 if (objc < 2 || objc > 3) {
26 Tcl_WrongNumArgs(ip, 2, objv, "fill|drain data");
27 return TCL_ERROR;
28 }
29
30 if (Tcl_GetIndexFromObj(ip, objv[1], cmds, "option", 0, &index) != TCL_OK)
31 return TCL_ERROR;
32
33 switch (index) {
34
35 case 0: /* fill ?data? */
36 if (objc >= 3) {
37 Tcl_IncrRefCount(objv[2]);
38 Tcl_DecrRefCount(zp->indata);
39 zp->indata = objv[2];
40 zp->stream.next_in = Tcl_GetByteArrayFromObj(zp->indata,
41 (int*) &zp->stream.avail_in);
42 }
43 Tcl_SetObjResult(ip, Tcl_NewIntObj(zp->stream.avail_in));
44 break;
45
46 case 1: /* drain count */
47 if (objc != 3) {
48 Tcl_WrongNumArgs(ip, 2, objv, "count");
49 return TCL_ERROR;
50 }
51 if (Tcl_GetIntFromObj(ip, objv[2], &count) != TCL_OK)
52 return TCL_ERROR;
53 obj = Tcl_GetObjResult(ip);
54 Tcl_SetByteArrayLength(obj, count);
55 zp->stream.next_out = Tcl_GetByteArrayFromObj(obj,
56 (int*) &zp->stream.avail_out);
57 e = inflate(&zp->stream, Z_NO_FLUSH);
58 if (e != 0 && e != Z_STREAM_END) {
59 Tcl_SetResult(ip, (char*) zError(e), TCL_STATIC);
60 return TCL_ERROR;
61 }
62 Tcl_SetByteArrayLength(obj, count - zp->stream.avail_out);
63 break;
64 }
65 return TCL_OK;
66}
67
68void zstreamdelproc(ClientData cd)
69{
70 zlibstream *zp = (zlibstream*) cd;
71 inflateEnd(&zp->stream);
72 Tcl_DecrRefCount(zp->indata);
73 Tcl_Free((void*) zp);
74}
75
76static int
77ZlibCmd(ClientData dummy, Tcl_Interp *ip, int objc, Tcl_Obj *CONST objv[])
78{
79 int e = TCL_OK, index, dlen, wbits = -MAX_WBITS;
80 long flag;
81 Byte *data;
82 z_stream stream;
83 Tcl_Obj *obj = Tcl_GetObjResult(ip);
84
85 static CONST84 char* cmds[] = {
86 "adler32", "crc32", "compress", "deflate", "decompress", "inflate",
87 "sdecompress", "sinflate", NULL,
88 };
89
90 if (objc < 3 || objc > 4) {
91 Tcl_WrongNumArgs(ip, 1, objv, "option data ?...?");
92 return TCL_ERROR;
93 }
94
95 if (Tcl_GetIndexFromObj(ip, objv[1], cmds, "option", 0, &index) != TCL_OK ||
96 objc > 3 && Tcl_GetLongFromObj(ip, objv[3], &flag) != TCL_OK)
97 return TCL_ERROR;
98
99 data = Tcl_GetByteArrayFromObj(objv[2], &dlen);
100
101 switch (index) {
102
103 case 0: /* adler32 str ?start? -> checksum */
104 if (objc < 4)
105 flag = (long) adler32(0, 0, 0);
106 Tcl_SetLongObj(obj, (long) adler32((uLong) flag, data, dlen));
107 return TCL_OK;
108
109 case 1: /* crc32 str ?start? -> checksum */
110 if (objc < 4)
111 flag = (long) crc32(0, 0, 0);
112 Tcl_SetLongObj(obj, (long) crc32((uLong) flag, data, dlen));
113 return TCL_OK;
114
115 case 2: /* compress data ?level? -> data */
116 wbits = MAX_WBITS;
117 case 3: /* deflate data ?level? -> data */
118 if (objc < 4)
119 flag = Z_DEFAULT_COMPRESSION;
120
121 stream.avail_in = (uInt) dlen;
122 stream.next_in = data;
123
124 stream.avail_out = (uInt) dlen + dlen / 1000 + 12;
125 Tcl_SetByteArrayLength(obj, stream.avail_out);
126 stream.next_out = Tcl_GetByteArrayFromObj(obj, NULL);
127
128 stream.zalloc = 0;
129 stream.zfree = 0;
130 stream.opaque = 0;
131
132 e = deflateInit2(&stream, (int) flag, Z_DEFLATED, wbits,
133 MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
134 if (e != Z_OK)
135 break;
136
137 e = deflate(&stream, Z_FINISH);
138 if (e != Z_STREAM_END) {
139 deflateEnd(&stream);
140 if (e == Z_OK) e = Z_BUF_ERROR;
141 } else
142 e = deflateEnd(&stream);
143 break;
144
145 case 4: /* decompress data ?bufsize? -> data */
146 wbits = MAX_WBITS;
147 case 5: /* inflate data ?bufsize? -> data */
148 {
149 if (flag < 1) {
150 Tcl_SetResult(ip, "invalid buffer size", TCL_STATIC);
151 return TCL_ERROR;
152 }
153
154 if (objc < 4)
155 flag = 16 * 1024;
156
157 for (;;) {
158 stream.zalloc = 0;
159 stream.zfree = 0;
160
161 /* +1 because ZLIB can "over-request" input (but ignore it) */
162 stream.avail_in = (uInt) dlen + 1;
163 stream.next_in = data;
164
165 stream.avail_out = (uInt) flag;
166 Tcl_SetByteArrayLength(obj, stream.avail_out);
167 stream.next_out = Tcl_GetByteArrayFromObj(obj, NULL);
168
169 /* Negative value suppresses ZLIB header */
170 e = inflateInit2(&stream, wbits);
171 if (e == Z_OK) {
172 e = inflate(&stream, Z_FINISH);
173 if (e != Z_STREAM_END) {
174 inflateEnd(&stream);
175 if (e == Z_OK) e = Z_BUF_ERROR;
176 } else
177 e = inflateEnd(&stream);
178 }
179
180 if (e == Z_OK || e != Z_BUF_ERROR) break;
181
182 Tcl_SetByteArrayLength(obj, 0);
183 flag *= 2;
184 }
185
186 break;
187 }
188
189 case 6: /* sdecompress cmdname -> */
190 wbits = MAX_WBITS;
191 case 7: /* sinflate cmdname -> */
192 {
193 zlibstream *zp = (zlibstream*) Tcl_Alloc(sizeof (zlibstream));
194 zp->indata = Tcl_NewObj();
195 Tcl_IncrRefCount(zp->indata);
196 zp->stream.zalloc = 0;
197 zp->stream.zfree = 0;
198 zp->stream.opaque = 0;
199 zp->stream.next_in = 0;
200 zp->stream.avail_in = 0;
201 inflateInit2(&zp->stream, wbits);
202 Tcl_CreateObjCommand(ip, Tcl_GetStringFromObj(objv[2], 0), zstreamincmd,
203 (ClientData) zp, zstreamdelproc);
204 return TCL_OK;
205 }
206 }
207
208 if (e != Z_OK) {
209 Tcl_SetResult(ip, (char*) zError(e), TCL_STATIC);
210 return TCL_ERROR;
211 }
212
213 Tcl_SetByteArrayLength(obj, stream.total_out);
214 return TCL_OK;
215}
216
217int Zlib_Init(Tcl_Interp *interp)
218{
219 Tcl_CreateObjCommand(interp, "zlib", ZlibCmd, 0, 0);
220 return Tcl_PkgProvide( interp, "zlib", "1.1");
221}
Note: See TracBrowser for help on using the repository browser.