Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

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