/media/hdb5/canorusNightlyBuildSystem/trunk/src/core/archive.cpp

Go to the documentation of this file.
00001 
00008 #include <QByteArray>
00009 #include <zlib.h> 
00010 #include <iostream> //dbg
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; // _tar is invalid.
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         // decompress
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) //clean up, set error and return
00097         {
00098                 delete[] header.comment;
00099                 inflateEnd(&strm);
00100                 if(close)
00101                         arch.close();
00102                 return;
00103         }
00104 
00105         // decompress until deflate stream ends or EOF 
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) || // buffer error is not fatal
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                 // If version checking is ever needed on this level (i.e. the archive format itself), use this:
00130                 // int cmp = qstrcmp((char*)header.comment, VERSION);
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         //compress until EOF
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; // rfc 1952: "NTFS filesystem (NT)"
00243         else
00244                 return 0; // rfc 1952: "FAT filesystem (MS-DOS, OS/2, NT/Win32"
00245 #elif defined(Q_WS_X11) // Mac or Linux/Unix/FreeBSD/...
00246         return 3;  // rfc 1952: "Unix". That what gzip does on Darwin (though there's 7 for "Macintosh").
00247 #else
00248         return 255; // rfc 1952: "unknown".
00249 #endif
00250 }

Generated on Sat Feb 9 13:06:25 2008 for Canorus by  doxygen 1.5.3