gui: Allow File|Open to select an encoding for system files.
[pspp] / src / libpspp / inflate.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2011, 2013 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17
18 #include <config.h>
19
20 #include "inflate.h"
21
22 #include <xalloc.h>
23 #include <zlib.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include "zip-reader.h"
27
28 #include "str.h"
29
30 #include "gettext.h"
31 #define _(msgid) gettext (msgid)
32 #define N_(msgid) (msgid)
33
34 #define UCOMPSIZE 4096
35
36 struct inflator
37 {
38   z_stream zss;
39   int state;
40   unsigned char ucomp[UCOMPSIZE];
41   size_t bytes_uncomp;
42   size_t ucomp_bytes_read;
43
44   /* Two bitfields as defined by RFC1950 */
45   uint16_t cmf_flg ;
46 };
47
48 void
49 inflate_finish (struct zip_member *zm)
50 {
51   struct inflator *inf = zm->aux;
52
53   inflateEnd (&inf->zss);
54
55   free (inf);
56 }
57
58 bool
59 inflate_init (struct zip_member *zm)
60 {
61   int r;
62   struct inflator *inf = xzalloc (sizeof *inf);
63   
64   uint16_t flg = 0 ; 
65   uint16_t cmf = 0x8; /* Always 8 for inflate */
66
67   const uint16_t cinfo = 7;  /* log_2(Window size) - 8 */
68
69   cmf |= cinfo << 4;     /* Put cinfo into the high nibble */
70
71   /* make these into a 16 bit word */
72   inf->cmf_flg = (cmf << 8 ) | flg;
73
74   /* Set the check bits */
75   inf->cmf_flg += 31 - (inf->cmf_flg % 31);
76   assert (inf->cmf_flg % 31 == 0);
77
78   inf->zss.next_in = Z_NULL;
79   inf->zss.avail_in = 0;
80   inf->zss.zalloc = Z_NULL;
81   inf->zss.zfree  = Z_NULL;
82   inf->zss.opaque = Z_NULL;
83   r = inflateInit (&inf->zss);
84
85   if ( Z_OK != r)
86     {
87       ds_put_format (zm->errs, _("Cannot initialize inflator: %s"), zError (r));
88       return false;
89     }
90
91   zm->aux = inf;
92
93   return true;
94 }
95
96
97 int
98 inflate_read (struct zip_member *zm, void *buf, size_t n)
99 {
100   int r;
101   struct inflator *inf = zm->aux;
102
103   if (inf->zss.avail_in == 0)
104     {
105       int bytes_read;
106       int bytes_to_read;
107       int pad = 0;
108
109       if ( inf->state == 0)
110         {
111           inf->ucomp[1] = inf->cmf_flg ;
112           inf->ucomp[0] = inf->cmf_flg >> 8 ;
113
114           pad = 2;
115           inf->state++;
116         }
117
118       bytes_to_read = zm->comp_size - inf->ucomp_bytes_read;
119       
120       if (bytes_to_read == 0)
121         return 0;
122
123       if (bytes_to_read > UCOMPSIZE)
124         bytes_to_read = UCOMPSIZE;
125
126       bytes_read = fread (inf->ucomp + pad, 1, bytes_to_read - pad, zm->fp);
127
128       inf->ucomp_bytes_read += bytes_read;
129
130       inf->zss.avail_in = bytes_read + pad;
131       inf->zss.next_in = inf->ucomp;
132     }
133   inf->zss.avail_out = n;
134   inf->zss.next_out = buf;
135
136   r = inflate (&inf->zss, Z_NO_FLUSH);
137   if ( Z_OK == r)
138     {
139       return n - inf->zss.avail_out;
140     }
141   
142   ds_put_format (zm->errs, _("Error inflating: %s"), zError (r));
143
144   return -1;
145 }