Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
114 andreas 1
/*
2
 * Copyright (C) 2019 by Andreas Theofilu <andreas@theosys.at>
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, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
18
 
19
#include <iostream>
20
#include <fstream>
21
#if __GNUC__ < 9
22
#include <experimental/filesystem>
23
#else
24
#include <filesystem>
25
#endif
26
#include "expand.h"
27
#include <assert.h>
28
 
29
using namespace std;
30
namespace fs = std::filesystem;
31
 
32
void Expand::setFileName (const string &fn)
33
{
34
	fname.assign(fn);
35
}
36
 
37
int Expand::unzip()
38
{
39
	if (fname.empty())
40
		return -1;
41
 
42
	string target(fname+".temp");
43
	FILE *source, *dest;
44
 
45
	source = fopen(fname.c_str(), "rb");
46
 
47
	if (!source)
48
	{
49
		cerr << "Error opening file" << fname << "!" << endl;
50
		return -1;
51
	}
52
 
53
	dest = fopen(target.c_str(), "wb");
54
 
55
	if (!dest)
56
	{
57
		fclose(source);
58
		cerr << "Error creating the temporary file " << target << "!" << endl;
59
		return -1;
60
	}
61
 
62
	int ret;
63
	unsigned have;
64
	z_stream strm;
65
	unsigned char in[CHUNK];
66
	unsigned char out[CHUNK];
67
 
68
	// allocate inflate state
69
	strm.zalloc = Z_NULL;
70
	strm.zfree = Z_NULL;
71
	strm.opaque = Z_NULL;
72
	strm.avail_in = 0;
73
	strm.next_in = Z_NULL;
74
	ret = inflateInit2(&strm, 32+MAX_WBITS);
75
 
76
	if (ret != Z_OK)
77
	{
78
		zerr(ret);
79
		fclose(source);
80
		fclose(dest);
81
		fs::remove(target);
82
		return ret;
83
	}
84
 
85
	do
86
	{
87
		strm.avail_in = fread(in, 1, CHUNK, source);
88
 
89
		if (ferror(source))
90
		{
91
			(void)inflateEnd(&strm);
92
			cerr << "Error reading from file " << fname << "!" << endl;
93
			fclose(source);
94
			fclose(dest);
95
			fs::remove(target);
96
			return Z_ERRNO;
97
		}
98
 
99
		if (strm.avail_in == 0)
100
			break;
101
 
102
		strm.next_in = in;
103
		// run inflate() on input until output buffer not full
104
        do
105
		{
106
			strm.avail_out = CHUNK;
107
			strm.next_out = out;
108
			ret = inflate(&strm, Z_NO_FLUSH);
109
			assert(ret != Z_STREAM_ERROR);	// state not clobbered
110
 
111
			switch (ret)
112
			{
113
				case Z_NEED_DICT:
114
					ret = Z_DATA_ERROR;		// and fall through
115
                // fall through
116
				case Z_DATA_ERROR:
117
				case Z_MEM_ERROR:
118
					(void)inflateEnd(&strm);
119
					fclose(source);
120
					fclose(dest);
121
					fs::remove(target);
122
					zerr(ret);
123
					return ret;
124
			}
125
 
126
			have = CHUNK - strm.avail_out;
127
 
128
			if (fwrite(out, 1, have, dest) != have || ferror(dest))
129
			{
130
				(void)inflateEnd(&strm);
131
				cerr << "Error on writing to file " << target << "!" << endl;
132
				fclose(source);
133
				fclose(dest);
134
				fs::remove(target);
135
				return Z_ERRNO;
136
			}
137
		}
138
		while (strm.avail_out == 0);
139
		// done when inflate() says it's done
140
	}
141
	while (ret != Z_STREAM_END);
142
	// clean up and return
143
	(void)inflateEnd(&strm);
144
	fclose(source);
145
	fclose(dest);
146
	fs::remove(fname);
147
	fs::rename(target, fname);
148
	return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
149
}
150
 
151
void Expand::zerr(int ret)
152
{
153
    switch (ret)
154
	{
155
		case Z_ERRNO:
156
			cerr << "Error reading or writing a file!" << endl;
157
		break;
158
 
159
		case Z_STREAM_ERROR:
160
			cerr << "invalid compression level" << endl;
161
		break;
162
 
163
		case Z_DATA_ERROR:
164
			cerr << "invalid or incomplete deflate data" << endl;
165
		break;
166
 
167
		case Z_MEM_ERROR:
168
			cerr << "out of memory" << endl;
169
		break;
170
 
171
		case Z_VERSION_ERROR:
172
			cerr << "zlib version mismatch!" << endl;
173
		break;
174
 
175
		default:
176
			if (ret != Z_OK)
177
				cerr << "Unknown error " << to_string(ret) << "!" << endl;
178
    }
179
}