Subversion Repositories tpanel

Rev

Rev 446 | Details | Compare with Previous | Last modification | View Log | RSS feed

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