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