Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

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