Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

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