Rockbox Utility: Replace OSDaB Zip with QuaZip.

This change fixes problems with zip files created with newer zip utilities (a
known issue is the iLike theme). QuaZip also allows better feedback during
operations without changing the imported code. Additionally Rockbox Utility and
the Theme Editor are now both using QuaZip; currently Rockbox Utility uses a
copy of the sources, merging them later is planned.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29645 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Dominik Riebeling 2011-03-25 22:16:12 +00:00
parent 0258895faa
commit 8c1d114dcf
36 changed files with 5880 additions and 3485 deletions

View file

@ -1,66 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2008 by Dominik Riebeling
* $Id$
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "rbunzip.h"
#include <QtCore>
//! @brief extract archive to destination
UnZip::ErrorCode RbUnZip::extractArchive(const QString& dest)
{
qDebug() << "[UNZIP] extracting archive to" << dest;
QStringList files = this->fileList();
UnZip::ErrorCode error = Ok;
m_abortunzip = false;
int total = files.size();
for(int i = 0; i < total; i++) {
error = this->extractFile(files.at(i), dest, UnZip::ExtractPaths);
emit unzipProgress(i + 1, total);
QCoreApplication::processEvents(); // update UI
if(m_abortunzip)
error = SkipAll;
if(error != Ok)
break;
}
return error;
}
//! @brief abort an extractArchive() operation.
void RbUnZip::abortUnzip(void)
{
m_abortunzip = true;
}
//! @brief return total size of extracted files in archive.
qulonglong RbUnZip::totalSize(void)
{
QList<ZipEntry> l = this->entryList();
qulonglong total = 0;
int i = l.size();
while(i--)
total += l.at(i).uncompressedSize;
return total;
}

View file

@ -1,47 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2008 by Dominik Riebeling
* $Id$
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef RBUNZIP_H
#define RBUNZIP_H
#include <QtCore>
#include "zip/unzip.h"
#include "zip/zip.h"
class RbUnZip : public QObject, public UnZip
{
Q_OBJECT
public:
UnZip::ErrorCode extractArchive(const QString&);
qulonglong totalSize(void);
signals:
void unzipProgress(int, int);
public slots:
void abortUnzip(void);
private:
bool m_abortunzip;
};
#endif

View file

@ -1,65 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2008 by Dominik Wenger
* $Id$
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "rbzip.h"
#include <QtCore>
Zip::ErrorCode RbZip::createZip(QString zip,QString dir)
{
Zip::ErrorCode error = Ok;
m_curEntry = 1;
m_numEntrys=0;
QCoreApplication::processEvents();
// get number of entrys in dir
QDirIterator it(dir, QDirIterator::Subdirectories);
while (it.hasNext())
{
it.next();
m_numEntrys++;
QCoreApplication::processEvents();
}
//! create zip
error = Zip::createArchive(zip);
if(error != Ok)
return error;
//! add the content
error = Zip::addDirectory(dir);
if(error != Ok)
return error;
//! close zip
error = Zip::closeArchive();
return error;
}
void RbZip::progress()
{
m_curEntry++;
emit zipProgress(m_curEntry,m_numEntrys);
QCoreApplication::processEvents(); // update UI
}

View file

@ -1,45 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2008 by Dominik Wenger
* $Id$
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef RBZIP_H
#define RBZIP_H
#include <QtCore>
#include "zip/zip.h"
class RbZip : public QObject, public Zip
{
Q_OBJECT
public:
Zip::ErrorCode createZip(QString zip,QString dir);
virtual void progress();
signals:
void zipProgress(int, int);
private:
int m_curEntry;
int m_numEntrys;
};
#endif

View file

@ -19,8 +19,8 @@
#include <QtCore>
#include "zipinstaller.h"
#include "rbunzip.h"
#include "utils.h"
#include "ziputil.h"
ZipInstaller::ZipInstaller(QObject* parent): QObject(parent)
{
@ -132,39 +132,28 @@ void ZipInstaller::downloadDone(bool error)
emit logItem(tr("Extracting file."), LOGINFO);
QCoreApplication::processEvents();
UnZip::ErrorCode ec;
RbUnZip uz;
connect(&uz, SIGNAL(unzipProgress(int, int)), this, SIGNAL(logProgress(int, int)));
connect(this, SIGNAL(internalAborted()), &uz, SLOT(abortUnzip()));
ec = uz.openArchive(m_file);
if(ec != UnZip::Ok) {
emit logItem(tr("Opening archive failed: %1.")
.arg(uz.formatError(ec)),LOGERROR);
emit logProgress(1, 1);
emit done(true);
return;
}
ZipUtil zip(this);
connect(&zip, SIGNAL(logProgress(int, int)), this, SIGNAL(logProgress(int, int)));
connect(&zip, SIGNAL(logItem(QString, int)), this, SIGNAL(logItem(QString, int)));
zip.open(m_file, QuaZip::mdUnzip);
// check for free space. Make sure after installation will still be
// some room for operating (also includes calculation mistakes due to
// cluster sizes on the player).
if(Utils::filesystemFree(m_mountpoint) < (uz.totalSize() + 1000000)) {
if(Utils::filesystemFree(m_mountpoint)
< (zip.totalUncompressedSize() + 1000000)) {
emit logItem(tr("Not enough disk space! Aborting."), LOGERROR);
emit logProgress(1, 1);
emit done(true);
return;
}
ec = uz.extractArchive(m_mountpoint);
// TODO: better handling of aborted unzip operation.
if(ec != UnZip::Ok) {
emit logItem(tr("Extracting failed: %1.")
.arg(uz.formatError(ec)),LOGERROR);
zipContents = zip.files();
if(!zip.extractArchive(m_mountpoint)) {
emit logItem(tr("Extraction failed!"), LOGERROR);
emit logProgress(1, 1);
emit done(true);
return;
}
// prepare file list for log
zipContents = uz.fileList();
zip.close();
}
else {
// only copy the downloaded file to the output location / name
@ -185,7 +174,7 @@ void ZipInstaller::downloadDone(bool error)
}
// add file to log
zipContents.append( m_target);
zipContents.append(m_target);
}
emit logItem(tr("Creating installation log"),LOGINFO);

View file

@ -0,0 +1,261 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2011 Dominik Riebeling
* $Id$
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <QtCore>
#include <QDebug>
#include "ziputil.h"
#include "progressloggerinterface.h"
#include "quazip.h"
#include "quazipfile.h"
#include "quazipfileinfo.h"
ZipUtil::ZipUtil(QObject* parent) : QObject(parent)
{
m_zip = NULL;
}
ZipUtil::~ZipUtil()
{
if(m_zip) {
delete m_zip;
}
}
//! @brief open zip file.
//! @param zipfile path to zip file
//! @param mode open mode (see QuaZip::Mode)
//! @return true on success, false otherwise
bool ZipUtil::open(QString& zipfile, QuaZip::Mode mode)
{
m_zip = new QuaZip(zipfile);
return m_zip->open(mode);
}
//! @brief close zip file.
//! @return true on success, false otherwise
bool ZipUtil::close(void)
{
if(!m_zip) {
return false;
}
int error = UNZ_OK;
if(m_zip->isOpen()) {
m_zip->close();
error = m_zip->getZipError();
}
delete m_zip;
m_zip = NULL;
return (error == UNZ_OK) ? true : false;
}
//! @brief extract currently opened archive
//! @brief dest path to extract archive to
//! @return true on success, false otherwise
bool ZipUtil::extractArchive(QString& dest)
{
bool result = true;
if(!m_zip) {
return false;
}
QuaZipFile *currentFile = new QuaZipFile(m_zip);
int entries = m_zip->getEntriesCount();
int current = 0;
for(bool more = m_zip->goToFirstFile(); more; more = m_zip->goToNextFile())
{
++current;
// if the entry is a path ignore it. Path existence is ensured separately.
if(m_zip->getCurrentFileName().split("/").last() == "")
continue;
QString outfilename = dest + "/" + m_zip->getCurrentFileName();
QFile outputFile(outfilename);
// make sure the output path exists
if(!QDir().mkpath(QFileInfo(outfilename).absolutePath())) {
result = false;
emit logItem(tr("Creating output path failed"), LOGERROR);
qDebug() << "[ZipUtil] creating output path failed for:"
<< outfilename;
break;
}
if(!outputFile.open(QFile::WriteOnly)) {
result = false;
emit logItem(tr("Creating output file failed"), LOGERROR);
qDebug() << "[ZipUtil] creating output file failed:"
<< outfilename;
break;
}
currentFile->open(QIODevice::ReadOnly);
outputFile.write(currentFile->readAll());
if(currentFile->getZipError() != UNZ_OK) {
result = false;
emit logItem(tr("Error during Zip operation"), LOGERROR);
qDebug() << "[ZipUtil] QuaZip error:" << currentFile->getZipError()
<< "on file" << currentFile->getFileName();
break;
}
currentFile->close();
outputFile.close();
emit logProgress(current, entries);
}
delete currentFile;
emit logProgress(1, 1);
return result;
}
//! @brief append a folder to current archive
//! @param source source folder
//! @param basedir base folder for archive. Will get stripped from zip paths.
//! @return true on success, false otherwise
bool ZipUtil::appendDirToArchive(QString& source, QString& basedir)
{
bool result = true;
if(!m_zip || !m_zip->isOpen()) {
qDebug() << "[ZipUtil] Zip file not open!";
return false;
}
// get a list of all files and folders. Needed for progress info and avoids
// recursive calls.
QDirIterator iterator(source, QDirIterator::Subdirectories);
QStringList fileList;
while(iterator.hasNext()) {
iterator.next();
// skip folders, we can't add them.
if(!QFileInfo(iterator.filePath()).isDir()) {
fileList.append(iterator.filePath());
}
}
qDebug() << "[ZipUtil] Adding" << fileList.size() << "files to archive";
int max = fileList.size();
for(int i = 0; i < max; i++) {
QString current = fileList.at(i);
if(!appendFileToArchive(current, basedir)) {
qDebug() << "[ZipUtil] Error appending file" << current
<< "to archive" << m_zip->getZipName();
result = false;
break;
}
emit logProgress(i, max);
}
return result;
}
//! @brief append a single file to current archive
//!
bool ZipUtil::appendFileToArchive(QString& file, QString& basedir)
{
bool result = true;
if(!m_zip || !m_zip->isOpen()) {
qDebug() << "[ZipUtil] Zip file not open!";
return false;
}
// skip folders, we can't add them.
QFileInfo fileinfo(file);
if(fileinfo.isDir()) {
return false;
}
QString infile = fileinfo.canonicalFilePath();
QString newfile = infile;
newfile.remove(QDir(basedir).canonicalPath() + "/");
QuaZipFile fout(m_zip);
QFile fin(file);
if(!fin.open(QFile::ReadOnly)) {
qDebug() << "[ZipUtil] Could not open file for reading:" << file;
return false;
}
if(!fout.open(QIODevice::WriteOnly, QuaZipNewInfo(newfile, infile))) {
fin.close();
qDebug() << "[ZipUtil] Could not open file for writing:" << newfile;
return false;
}
result = (fout.write(fin.readAll()) < 0) ? false : true;
fin.close();
fout.close();
return result;
}
//! @brief calculate total size of extracted files
qint64 ZipUtil::totalUncompressedSize(void)
{
qint64 uncompressed = 0;
QList<QuaZipFileInfo> items = contentProperties();
if(items.size() == 0) {
return -1;
}
int max = items.size();
for(int i = 0; i < max; ++i) {
uncompressed += items.at(i).uncompressedSize;
}
qDebug() << "[ZipUtil] size of archive files uncompressed:" << uncompressed;
return uncompressed;
}
QStringList ZipUtil::files(void)
{
QList<QuaZipFileInfo> items = contentProperties();
QStringList fileList;
if(items.size() == 0) {
return fileList;
}
int max = items.size();
for(int i = 0; i < max; ++i) {
fileList.append(items.at(i).name);
}
return fileList;
}
QList<QuaZipFileInfo> ZipUtil::contentProperties()
{
QList<QuaZipFileInfo> items;
if(!m_zip || !m_zip->isOpen()) {
qDebug() << "[ZipUtil] Zip file not open!";
return items;
}
QuaZipFileInfo info;
QuaZipFile currentFile(m_zip);
for(bool more = m_zip->goToFirstFile(); more; more = m_zip->goToNextFile())
{
currentFile.getFileInfo(&info);
if(currentFile.getZipError() != UNZ_OK) {
qDebug() << "[ZipUtil] QuaZip error:" << currentFile.getZipError()
<< "on file" << currentFile.getFileName();
return QList<QuaZipFileInfo>();
}
items.append(info);
}
return items;
}

View file

@ -0,0 +1,54 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2011 Dominik Riebeling
* $Id$
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef ZIPUTIL_H
#define ZIPUTIL_H
#include <QtCore>
#include "quazip.h"
#include "quazipfile.h"
#include "quazipfileinfo.h"
class ZipUtil : public QObject
{
Q_OBJECT
public:
ZipUtil(QObject* parent);
~ZipUtil();
bool open(QString& zipfile, QuaZip::Mode mode);
bool close(void);
bool extractArchive(QString& dest);
bool appendDirToArchive(QString& source, QString& basedir);
bool appendFileToArchive(QString& file, QString& basedir);
qint64 totalUncompressedSize(void);
QStringList files(void);
signals:
void logProgress(int, int);
void logItem(QString, int);
private:
QList<QuaZipFileInfo> contentProperties();
QuaZip* m_zip;
QuaZipFile* m_file;
};
#endif