summaryrefslogtreecommitdiff
path: root/lib/qt-tar-xz/QXzDecode.cpp
blob: 6aa13bba63eab9c52aec762f5e2c00e2ceb97752 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/** \file QXzDecode.cpp
\brief To decompress a xz stream
\author alpha_one_x86
\version 0.3
\date 2010
\licence GPL3, see the file COPYING */

#include "QXzDecode.h"
#include <QDebug>
extern "C" {
#include "xz.h"
}

static uint8_t in[BUFSIZ];
static uint8_t out[BUFSIZ];

QXzDecode::QXzDecode(QByteArray data,quint64 maxSize)
{
	error="Unknow error";
	this->data=data;
	this->maxSize=maxSize;
	isDecoded=false;
}

bool QXzDecode::decodeStream(QDataStream *stream_xz_decode_in,QDataStream *stream_xz_decode_out)
{
	isDecoded=false;
	struct xz_buf b;
	struct xz_dec *s;
	enum xz_ret ret;

	xz_crc32_init();

	/*
	 * Support up to 64 MiB dictionary. The actually needed memory
	 * is allocated once the headers have been parsed.
	 */
	s = xz_dec_init(XZ_DYNALLOC, 1 << 26);
	if (s == NULL) {
		error=tr("Memory allocation failed");
		xz_dec_end(s);
		return isDecoded;
	}

	b.in = in;
	b.in_pos = 0;
	b.in_size = 0;
	b.out = out;
	b.out_pos = 0;
	b.out_size = BUFSIZ;

	while (true) {
		//input of data
		if (b.in_pos == b.in_size) {
			b.in_size = stream_xz_decode_in->readRawData((char *)in,sizeof(in));
			b.in_pos = 0;
		}

		ret = xz_dec_run(s, &b);

		//output of data
		if (b.out_pos == sizeof(out))
		{
			if (stream_xz_decode_out->writeRawData((char *)out,b.out_pos) != (int)b.out_pos)
			{
				error=tr("Write error");
				xz_dec_end(s);
				return isDecoded;
			}
			b.out_pos = 0;
		}

		if (ret == XZ_OK)
			continue;

#ifdef XZ_DEC_ANY_CHECK
		if (ret == XZ_UNSUPPORTED_CHECK) {
			continue;
		}
#endif

		if (stream_xz_decode_out->writeRawData((char *)out,b.out_pos) != (int)b.out_pos)
		{
			error=tr("Write error");
			xz_dec_end(s);
			return isDecoded;
		}

		switch (ret) {
		case XZ_STREAM_END:
			xz_dec_end(s);
			isDecoded=true;
			return isDecoded;
		case XZ_MEM_ERROR:
			error=tr("Memory allocation failed");
			xz_dec_end(s);
			return isDecoded;
		case XZ_MEMLIMIT_ERROR:
			error=tr("Memory usage limit reached");
			xz_dec_end(s);
			return isDecoded;
		case XZ_FORMAT_ERROR:
			error=tr("Not a .xz file");
			xz_dec_end(s);
			return isDecoded;
		case XZ_OPTIONS_ERROR:
			error=tr("Unsupported options in the .xz headers");
			xz_dec_end(s);
			return isDecoded;
		case XZ_DATA_ERROR:
		case XZ_BUF_ERROR:
			error=tr("The file is corrupted");
			xz_dec_end(s);
			return isDecoded;
		default:
			error=tr("Bug!");
			xz_dec_end(s);
			return isDecoded;
		}
	}
}

bool QXzDecode::decode()
{
	if(data.size() < 32) // check the minimal size
		error=tr("The input data is too short");
	QByteArray outputData;
	QDataStream stream_xz_decode_in(&data,QIODevice::ReadOnly);
	QDataStream stream_xz_decode_out(&outputData,QIODevice::WriteOnly);
	int returnVal=decodeStream(&stream_xz_decode_in,&stream_xz_decode_out);
	data=outputData;
	return returnVal;
}

QByteArray QXzDecode::decodedData()
{
	if(isDecoded)
		return data;
	else
		return QByteArray();
}

QString QXzDecode::errorString()
{
	return error;
}