00001
00008 #include <QByteArray>
00009 #include <zlib.h>
00010 #include <iostream>
00011 #include <QTemporaryFile>
00012
00013 #ifdef Q_OS_WIN
00014 # include <QSysInfo>
00015 #endif
00016
00017 #include "core/tar.h"
00018 #include "core/archive.h"
00019
00030 const int CAArchive::CHUNK = 16384;
00031 const char* CAArchive::VERSION = "Canorus Archive v0.5";
00032
00036 CAArchive::CAArchive()
00037 :_err(false)
00038 {
00039 _tar = new CATar();
00040 }
00041
00045 CAArchive::CAArchive(QIODevice& arch)
00046 :_err(false)
00047 {
00048 parse(arch);
00049 }
00050
00054 CAArchive::~CAArchive()
00055 {
00056 delete _tar;
00057 }
00058
00062 void CAArchive::parse(QIODevice& arch)
00063 {
00064 bool close = false;
00065 int ret;
00066 z_stream strm;
00067 QTemporaryFile tar;
00068 QBuffer in, out;
00069 gz_header header = {0};
00070
00071 in.buffer().resize(CHUNK);
00072 out.buffer().resize(CHUNK);
00073 tar.open();
00074
00075 if(!arch.isOpen()) {
00076 if(!arch.open(QIODevice::ReadOnly)) {
00077 _err = -1;
00078 return;
00079 }
00080 close = true;
00081 }
00082
00083 header.os = getOS();
00084 header.comment = new unsigned char[21];
00085 header.comm_max = 21;
00086
00087
00088 arch.reset();
00089 strm.zalloc = Z_NULL;
00090 strm.zfree = Z_NULL;
00091 strm.opaque = Z_NULL;
00092 strm.avail_in = 0;
00093 strm.next_in = Z_NULL;
00094 ret = inflateInit2(&strm, 31);
00095 ret = (ret == Z_OK) ? inflateGetHeader(&strm, &header) : ret;
00096 if(ret != Z_OK)
00097 {
00098 delete[] header.comment;
00099 inflateEnd(&strm);
00100 if(close)
00101 arch.close();
00102 return;
00103 }
00104
00105
00106 do {
00107 strm.avail_in = arch.read(in.buffer().data(), CHUNK);
00108 if(strm.avail_in == 0)
00109 break;
00110 strm.next_in = (unsigned char*)in.buffer().data();
00111 do {
00112 strm.avail_out = CHUNK;
00113 strm.next_out = (unsigned char*)out.buffer().data();
00114 ret = inflate(&strm, Z_NO_FLUSH);
00115 if((ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) ||
00116 tar.write(out.buffer().data(), CHUNK - strm.avail_out) != CHUNK - strm.avail_out) {
00117
00118 _err = true;
00119 break;
00120 }
00121 } while (strm.avail_out == 0);
00122 } while(ret != Z_STREAM_END && !_err);
00123 inflateEnd(&strm);
00124
00125 if(ret != Z_STREAM_END)
00126 _err = true;
00127
00128 if(!_err) {
00129
00130
00131 tar.reset();
00132 _tar = new CATar(tar);
00133 }
00134
00135 delete[] header.comment;
00136 if(close)
00137 arch.close();
00138 }
00139
00145 qint64 CAArchive::write(QIODevice& dest)
00146 {
00147 bool close = false;
00148 int ret, flush;
00149 qint64 total = 0, read;
00150 z_stream strm;
00151 gz_header header = {0};
00152 QBuffer in, out;
00153
00154 if(!dest.isOpen())
00155 {
00156 if(!dest.open(QIODevice::WriteOnly))
00157 return -1;
00158 close = true;
00159 }
00160
00161 if(!dest.isWritable() || error())
00162 {
00163 if(close)
00164 dest.close();
00165 return -1;
00166 }
00167
00168 header.os = getOS();
00169 header.comment = new unsigned char[strlen(VERSION)+1];
00170 strcpy((char*)header.comment, VERSION);
00171
00172 in.open(QIODevice::ReadWrite);
00173 out.open(QIODevice::ReadWrite);
00174 in.buffer().resize(CHUNK);
00175 out.buffer().resize(CHUNK);
00176 strm.zalloc = Z_NULL;
00177 strm.zfree = Z_NULL;
00178 strm.opaque = Z_NULL;
00179 ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
00180 ret = (ret == Z_OK) ? deflateSetHeader(&strm, &header) : ret;
00181 if(ret != Z_OK)
00182 {
00183 deflateEnd(&strm);
00184 delete[] header.comment;
00185 if(close)
00186 dest.close();
00187 in.close();
00188 out.close();
00189 return -1;
00190 }
00191
00192
00193 do {
00194 in.reset();
00195 ret = _tar->write(in, CHUNK);
00196 if(ret == -1)
00197 {
00198 _err = true;
00199 break;
00200 }
00201 flush = _tar->eof(in) ? Z_FINISH : Z_NO_FLUSH;
00202 strm.avail_in = ret;
00203 strm.next_in = (unsigned char*)in.buffer().data();
00204 do {
00205 strm.avail_out = CHUNK;
00206 strm.next_out = (unsigned char*)out.buffer().data();
00207 ret = deflate(&strm, flush);
00208 if(ret == Z_STREAM_ERROR)
00209 _err = true;
00210 read = (!_err) ? dest.write(out.buffer().data(), CHUNK - strm.avail_out) : 0;
00211 if(_err || (read != CHUNK - strm.avail_out)) {
00212 _err = true;
00213 break;
00214 }
00215 total += read;
00216 } while(strm.avail_out == 0);
00217 if(strm.avail_in != 0)
00218 _err = true;
00219 } while (flush != Z_FINISH && !_err);
00220
00221 deflateEnd(&strm);
00222 if(ret != Z_STREAM_END)
00223 _err = true;
00224
00225 delete[] header.comment;
00226 if(close)
00227 dest.close();
00228 in.close();
00229 out.close();
00230 return (_err) ? -1 : total;
00231 }
00232
00238 int CAArchive::getOS()
00239 {
00240 #ifdef Q_WS_WIN
00241 if(QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)
00242 return 11;
00243 else
00244 return 0;
00245 #elif defined(Q_WS_X11) // Mac or Linux/Unix/FreeBSD/...
00246 return 3;
00247 #else
00248 return 255;
00249 #endif
00250 }