1 /*
2  * Author:      William Chia-Wei Cheng (bill.cheng@acm.org)
3  *
4  * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5  *
6  * This file may be distributed under the terms of the Q Public License
7  * as defined by Trolltech AS of Norway and appearing in the file
8  * LICENSE.QPL included in the packaging of this file.
9  *
10  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11  * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  * @(#)$Header: /mm2/home/cvs/bc-src/tgif/z_intrf.c,v 1.11 2011/06/18 04:44:51 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_Z_INTRF_C_
22 
23 #include "tgifdefs.h"
24 
25 #if (!defined(_NO_ZLIB) || defined(HAVE_LIBZ))
26 #include <zlib.h>
27 #endif /* (!defined(_NO_ZLIB) || defined(HAVE_LIBZ)) */
28 
29 #include "dialog.e"
30 #include "file.e"
31 #include "msg.e"
32 #include "setup.e"
33 #include "strtbl.e"
34 #include "util.e"
35 #include "z_intrf.e"
36 
37 /* --------------------- Utility Functions --------------------- */
38 
39 static
ByteStuff(buf_in,buf_len,buf_out,pn_buf_out)40 void ByteStuff(buf_in, buf_len, buf_out, pn_buf_out)
41    unsigned char *buf_in, *buf_out;
42    unsigned int buf_len, *pn_buf_out;
43 {
44    int i=0, count=0;
45 
46    for (i=0; i < buf_len; i++, buf_in++) {
47       switch (*buf_in) {
48       case '\0':
49          *buf_out++ = ((unsigned char)0xff);
50          *buf_out++ = ((unsigned char)0x30);
51          count += 2;
52          break;
53       case ((unsigned char)0xff):
54          *buf_out++ = ((unsigned char)0xff);
55          *buf_out++ = ((unsigned char)0xff);
56          count += 2;
57          break;
58       default:
59          *buf_out++ = *buf_in;
60          count++;
61          break;
62       }
63    }
64    if (pn_buf_out != NULL) *pn_buf_out = count;
65 }
66 
67 static
ByteUnStuff(buf_in,buf_len,buf_out,pn_buf_out,pn_has_left_over)68 int ByteUnStuff(buf_in, buf_len, buf_out, pn_buf_out, pn_has_left_over)
69    unsigned char *buf_in, *buf_out;
70    int buf_len, *pn_buf_out, *pn_has_left_over;
71 {
72    int i=0, count=0;
73 
74    if (*pn_has_left_over) {
75       if (buf_len == 0) return TRUE;
76       switch (*buf_in) {
77       case ((unsigned char)0x30):
78          *buf_out++ = ((unsigned char)'\0');
79          count++;
80          buf_in++;
81          break;
82       case ((unsigned char)0xff):
83          *buf_out++ = ((unsigned char)0xff);
84          count++;
85          buf_in++;
86          break;
87       default: return FALSE;
88       }
89       *pn_has_left_over = FALSE;
90    }
91    for (i=count; i < buf_len; i++, buf_in++) {
92       if (*buf_in == ((unsigned char)0xff)) {
93          i++;
94          buf_in++;
95          if (i >= buf_len) {
96             *pn_has_left_over = TRUE;
97             if (pn_buf_out != NULL) *pn_buf_out = count;
98             return TRUE;
99          }
100          switch (*buf_in) {
101          case ((unsigned char)0x30):
102             *buf_out++ = ((unsigned char)'\0');
103             count++;
104             break;
105          case ((unsigned char)0xff):
106             *buf_out++ = ((unsigned char)0xff);
107             count++;
108             break;
109          default: return FALSE;
110          }
111       } else {
112          *buf_out++ = *buf_in;
113          count++;
114       }
115    }
116    if (pn_buf_out != NULL) *pn_buf_out = count;
117 
118    return TRUE;
119 }
120 
121 /* --------------------- HasZlibSupport() --------------------- */
122 
HasZlibSupport()123 int HasZlibSupport()
124 {
125 #if (!defined(_NO_ZLIB) || defined(HAVE_LIBZ))
126    return TRUE;
127 #else /* ~(!defined(_NO_ZLIB) || defined(HAVE_LIBZ)) */
128    return FALSE;
129 #endif /* (!defined(_NO_ZLIB) || defined(HAVE_LIBZ)) */
130 }
131 
132 /* --------------------- DeflateFile() --------------------- */
133 
DeflateFile(fname,deflated_fname)134 int DeflateFile(fname, deflated_fname)
135    char *fname, *deflated_fname;
136    /* no byte stuffing */
137 {
138 #if (!defined(_NO_ZLIB) || defined(HAVE_LIBZ))
139    int level=Z_DEFAULT_COMPRESSION;
140    int ret=0, flush=0;
141    unsigned int block_sz=0x4000;
142    unsigned int have=0;
143    z_stream strm;
144    FILE *in_fp=NULL, *out_fp=NULL;
145    unsigned char in[0x4000], out[0x4000];
146    int bytes_left=0, input_size=0;
147    struct stat stat_buf;
148    ProgressInfo pi;
149 
150    if ((in_fp=fopen(fname, "r")) == NULL) {
151       FailToOpenMessage(fname, "r", NULL);
152       return FALSE;
153    }
154    if (fstat(fileno(in_fp), &stat_buf) != 0) {
155       fclose(in_fp);
156       sprintf(gszMsgBox, TgLoadString(STID_FAIL_TO_FSTAT_ABORT_COPY), fname);
157       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
158       return FALSE;
159    }
160    bytes_left = input_size = stat_buf.st_size;
161    if ((out_fp=fopen(deflated_fname, "w")) == NULL) {
162       fclose(in_fp);
163       FailToOpenMessage(deflated_fname, "w", NULL);
164       return FALSE;
165    }
166    /* allocate deflate state */
167    memset(&strm, 0, sizeof(strm));
168    strm.zalloc = Z_NULL;
169    strm.zfree = Z_NULL;
170    strm.opaque = Z_NULL;
171    ret = deflateInit(&strm, level);
172    if (ret != Z_OK) {
173       ZlibError(ret, TRUE);
174       return FALSE;
175    }
176    BeginProgress(&pi, input_size);
177    do {
178       int bytes_to_read=min(block_sz, bytes_left);
179 
180       strm.avail_in = fread(in, 1, bytes_to_read, in_fp);
181       if (ferror(in_fp)) {
182          (void)deflateEnd(&strm);
183          ZlibError(ret, TRUE);
184          return FALSE;
185       }
186       bytes_left -= bytes_to_read;
187 
188       flush = (bytes_left == 0) ? Z_FINISH : Z_NO_FLUSH;
189       strm.next_in = in;
190 
191       UpdateProgress(&pi, input_size-bytes_left);
192       /*
193        * run deflate() on input until output buffer not full, finish compression
194        *       if all of in_fp has been read in or in_buf is exhausted
195        */
196       do {
197          strm.avail_out = block_sz;
198          strm.next_out = out;
199          ret = deflate(&strm, flush);    /* no bad return value */
200          TgAssert(ret != Z_STREAM_ERROR,
201                "deflate() returns Z_STREAM_ERROR in DeflateFile()", NULL);
202                /* make sure that state is not clobbered */
203          have = block_sz - strm.avail_out;
204 
205          if (fwrite(out, 1, have, out_fp) != have || ferror(out_fp)) {
206             (void)deflateEnd(&strm);
207             ZlibError(ret, TRUE);
208             return FALSE;
209          }
210       } while (strm.avail_out == 0);
211       TgAssert(strm.avail_in == 0,
212             "un-deflated data left in input buffer in DeflateFile()", NULL);
213             /* make sure that all input are used */
214 
215       /* done when last data in file processed */
216    } while (flush != Z_FINISH);
217    EndProgress(&pi);
218 
219    TgAssert(ret == Z_STREAM_END,
220          "end-of-stream not detected in DeflateFile()", NULL);
221          /* make sure that stream is complete */
222    deflateEnd(&strm);
223    fclose(in_fp);
224    fclose(out_fp);
225 
226    return TRUE;
227 #else /* ~(!defined(_NO_ZLIB) || defined(HAVE_LIBZ)) */
228    return FALSE;
229 #endif /* (!defined(_NO_ZLIB) || defined(HAVE_LIBZ)) */
230 }
231 
232 /* --------------------- DoDeflate() --------------------- */
233 
DoDeflate(in_fp,in_buf,bytes_left,out_fp,use_def_compression,use_byte_stuffing,pn_rc)234 int DoDeflate(in_fp, in_buf, bytes_left, out_fp, use_def_compression, use_byte_stuffing, pn_rc)
235    /*
236     * This function is adapted from <URL:http://www.zlib.net/zpipe.c>
237     *
238     * zpipe.c - example of proper use of zlib's inflate() and deflate()
239     * Not copyrighted -- provided to the public domain
240     * Version 1.4  11 December 2005  Mark Adler
241     */
242    FILE *in_fp, *out_fp;
243    char *in_buf;
244    int bytes_left, use_byte_stuffing, *pn_rc;
245    int use_def_compression; /* always use Z_DEFAULT_COMPRESSION */
246 {
247 #if (!defined(_NO_ZLIB) || defined(HAVE_LIBZ))
248    int level=Z_DEFAULT_COMPRESSION;
249    int ret=0, flush=0;
250    unsigned int block_sz=0x4000;
251    unsigned int have=0;
252    z_stream strm;
253    unsigned char in[0x4000], out[0x4000];
254 
255    TgAssert(in_fp == NULL || in_buf == NULL,
256          "in_fp and in_buf cannot be both NULL in DoDeflate()", NULL);
257    /* allocate deflate state */
258    memset(&strm, 0, sizeof(strm));
259    strm.zalloc = Z_NULL;
260    strm.zfree = Z_NULL;
261    strm.opaque = Z_NULL;
262    ret = deflateInit(&strm, level);
263    if (ret != Z_OK) {
264       if (pn_rc != NULL) *pn_rc = ret;
265       return FALSE;
266    }
267    if (in_fp != NULL) rewind(in_fp);
268    rewind(out_fp);
269    do {
270       int bytes_to_read=min(block_sz, bytes_left);
271 
272       if (in_fp != NULL) {
273          strm.avail_in = fread(in, 1, bytes_to_read, in_fp);
274          if (ferror(in_fp)) {
275             (void)deflateEnd(&strm);
276             if (pn_rc != NULL) *pn_rc = Z_ERRNO;
277             return FALSE;
278          }
279       } else {
280          memcpy(in, in_buf, bytes_to_read);
281          strm.avail_in = bytes_to_read;
282       }
283       bytes_left -= bytes_to_read;
284 
285       flush = (bytes_left == 0) ? Z_FINISH : Z_NO_FLUSH;
286       strm.next_in = in;
287 
288       /*
289        * run deflate() on input until output buffer not full, finish compression
290        *       if all of in_fp has been read in or in_buf is exhausted
291        */
292       do {
293          strm.avail_out = block_sz;
294          strm.next_out = out;
295          ret = deflate(&strm, flush);    /* no bad return value */
296          TgAssert(ret != Z_STREAM_ERROR,
297                "deflate() returns Z_STREAM_ERROR in DoDeflate()", NULL);
298                /* make sure that state is not clobbered */
299          have = block_sz - strm.avail_out;
300 
301          if (use_byte_stuffing) {
302             unsigned int have2=0;
303             unsigned char out2[0x8000];
304 
305             have2 = 0;
306             ByteStuff(out, have, out2, &have2);
307             if (fwrite(out2, 1, have2, out_fp) != have2 || ferror(out_fp)) {
308                (void)deflateEnd(&strm);
309                if (pn_rc != NULL) *pn_rc = Z_ERRNO;
310                return FALSE;
311             }
312          } else {
313             if (fwrite(out, 1, have, out_fp) != have || ferror(out_fp)) {
314                (void)deflateEnd(&strm);
315                if (pn_rc != NULL) *pn_rc = Z_ERRNO;
316                return FALSE;
317             }
318          }
319       } while (strm.avail_out == 0);
320       TgAssert(strm.avail_in == 0,
321             "un-deflated data left in input buffer in DoDeflate()", NULL);
322             /* make sure that all input are used */
323 
324       /* done when last data in file processed */
325    } while (flush != Z_FINISH);
326 
327    TgAssert(ret == Z_STREAM_END,
328          "end-of-stream not detected in DoDeflate()", NULL);
329          /* make sure that stream is complete */
330    deflateEnd(&strm);
331 
332    return TRUE;
333 #else /* ~(!defined(_NO_ZLIB) || defined(HAVE_LIBZ)) */
334    return FALSE;
335 #endif /* (!defined(_NO_ZLIB) || defined(HAVE_LIBZ)) */
336 }
337 
338 /* --------------------- DoInflate() --------------------- */
339 
DoInflate(in_buf,bytes_left,out_fp,use_byte_unstuffing,pn_rc)340 int DoInflate(in_buf, bytes_left, out_fp, use_byte_unstuffing, pn_rc)
341    /*
342     * This function is adapted from <URL:http://www.zlib.net/zpipe.c>
343     *
344     * zpipe.c - example of proper use of zlib's inflate() and deflate()
345     * Not copyrighted -- provided to the public domain
346     * Version 1.4  11 December 2005  Mark Adler
347     */
348    char *in_buf;
349    int bytes_left, use_byte_unstuffing, *pn_rc;
350    FILE *out_fp;
351 {
352 #if (!defined(_NO_ZLIB) || defined(HAVE_LIBZ))
353    int ret=0, has_left_over=FALSE;
354    unsigned int block_sz=0x4000;
355    unsigned int have=0;
356    z_stream strm;
357    unsigned char in[0x4000], out[0x4000];
358 
359    /* allocate inflate state */
360    memset(&strm, 0, sizeof(strm));
361    strm.zalloc = Z_NULL;
362    strm.zfree = Z_NULL;
363    strm.opaque = Z_NULL;
364    strm.avail_in = 0;
365    strm.next_in = Z_NULL;
366    ret = inflateInit(&strm);
367    if (ret != Z_OK) {
368       if (pn_rc != NULL) *pn_rc = ret;
369       return FALSE;
370    }
371    rewind(out_fp);
372    /* decompress until deflate stream ends or end of file */
373    do {
374       int bytes_to_read=min(block_sz, bytes_left), bytes_to_read2=0;
375       unsigned char in2[0x4000];
376 
377       if (bytes_to_read == 0) break;
378       memcpy(in, in_buf, bytes_to_read);
379 
380       bytes_left -= bytes_to_read;
381       in_buf += bytes_to_read;
382 
383       if (use_byte_unstuffing) {
384          if (!ByteUnStuff(in, bytes_to_read, in2, &bytes_to_read2,
385                &has_left_over)) {
386             (void)inflateEnd(&strm);
387             if (pn_rc != NULL) *pn_rc = Z_DATA_ERROR;
388             return FALSE;
389          }
390          strm.avail_in = bytes_to_read2;
391          strm.next_in = in2;
392       } else {
393          strm.avail_in = bytes_to_read;
394          strm.next_in = in;
395       }
396       /* run inflate() on input until output buffer not full */
397       do {
398          strm.avail_out = block_sz;
399          strm.next_out = out;
400          ret = inflate(&strm, Z_NO_FLUSH);
401          TgAssert(ret != Z_STREAM_ERROR,
402                "inflate() returns Z_STREAM_ERROR in DoInflate()", NULL);
403                /* make sure that state is not clobbered */
404          switch (ret) {
405          case Z_NEED_DICT:
406             ret = Z_DATA_ERROR;     /* and fall through */
407          case Z_DATA_ERROR:
408          case Z_MEM_ERROR:
409             (void)inflateEnd(&strm);
410             if (pn_rc != NULL) *pn_rc = ret;
411             return FALSE;
412          }
413          have = block_sz - strm.avail_out;
414 
415          if (fwrite(out, 1, have, out_fp) != have || ferror(out_fp)) {
416             (void)inflateEnd(&strm);
417             if (pn_rc != NULL) *pn_rc = Z_ERRNO;
418             return FALSE;
419          }
420       } while (strm.avail_out == 0);
421 
422       /* done when inflate() says it's done */
423    } while (ret != Z_STREAM_END);
424 
425    if (has_left_over) {
426       (void)inflateEnd(&strm);
427       if (pn_rc != NULL) *pn_rc = Z_DATA_ERROR;
428       return FALSE;
429    }
430    /* clean up and return */
431    inflateEnd(&strm);
432 
433    if (ret == Z_STREAM_END) {
434       return TRUE;
435    }
436    if (pn_rc != NULL) *pn_rc = Z_DATA_ERROR;
437    return FALSE;
438 #else /* ~(!defined(_NO_ZLIB) || defined(HAVE_LIBZ)) */
439    return FALSE;
440 #endif /* (!defined(_NO_ZLIB) || defined(HAVE_LIBZ)) */
441 }
442 
443 /* --------------------- InflateInit() --------------------- */
444 
445 /* --------------------- ZlibError() --------------------- */
446 
ZlibError(status,deflate)447 void ZlibError(status, deflate)
448    int status, deflate;
449 {
450 #if (!defined(_NO_ZLIB) || defined(HAVE_LIBZ))
451    char buf[MAXSTRING];
452 
453    switch (status) {
454    case Z_ERRNO:
455       snprintf(buf, sizeof(buf), "%s-%s.",
456             "File I/O error during z",
457             deflate ? "compression" : "decompression");
458       break;
459    case Z_STREAM_ERROR:
460       snprintf(buf, sizeof(buf), "%s-%s.",
461             "Invalid compression level used for z",
462             deflate ? "compression" : "decompression");
463       break;
464    case Z_DATA_ERROR:
465       snprintf(buf, sizeof(buf), "%s-%s.",
466             "Corrupted data encountered during z",
467             deflate ? "compression" : "decompression");
468       break;
469    case Z_MEM_ERROR:
470       snprintf(buf, sizeof(buf), "%s-%s.", "Out of memory during z",
471             deflate ? "compression" : "decompression");
472       break;
473    case Z_VERSION_ERROR:
474       snprintf(buf, sizeof(buf), "%s-%s.", "Zlib version mismatch for z",
475             deflate ? "compression" : "decompression");
476       break;
477    }
478    if (deflate) {
479       snprintf(gszMsgBox, sizeof(gszMsgBox), "%s\n\n%s", buf,
480             "Continue without z-compression.");
481    } else {
482       UtilStrCpyN(gszMsgBox, sizeof(gszMsgBox), buf);
483    }
484    if (PRTGIF && !cmdLineOpenDisplay) {
485       fprintf(stderr, "%s\n", gszMsgBox);
486    } else {
487       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
488    }
489 #endif /* (!defined(_NO_ZLIB) || defined(HAVE_LIBZ)) */
490 }
491 
492