From 6375c47f036a4992ecb4bc3023a0fedbdc2356e0 Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Mon, 11 Mar 2013 18:57:11 +0100 Subject: Add support for CAB archives to rbutil Change-Id: Ia8b4953343caf8bc2b3c5a6cfd53c921c6d082b1 Reviewed-on: http://gerrit.rockbox.org/418 Reviewed-by: Dominik Riebeling --- rbutil/rbutilqt/base/archiveutil.cpp | 30 +++++ rbutil/rbutilqt/base/archiveutil.h | 41 +++++++ rbutil/rbutilqt/base/bootloaderinstallbase.cpp | 37 +++++- rbutil/rbutilqt/base/mspackutil.cpp | 163 +++++++++++++++++++++++++ rbutil/rbutilqt/base/mspackutil.h | 51 ++++++++ rbutil/rbutilqt/base/ziputil.cpp | 4 +- rbutil/rbutilqt/base/ziputil.h | 9 +- rbutil/rbutilqt/rbutilqt.pri | 29 ++++- 8 files changed, 350 insertions(+), 14 deletions(-) create mode 100644 rbutil/rbutilqt/base/archiveutil.cpp create mode 100644 rbutil/rbutilqt/base/archiveutil.h create mode 100644 rbutil/rbutilqt/base/mspackutil.cpp create mode 100644 rbutil/rbutilqt/base/mspackutil.h diff --git a/rbutil/rbutilqt/base/archiveutil.cpp b/rbutil/rbutilqt/base/archiveutil.cpp new file mode 100644 index 0000000000..d5f0a12471 --- /dev/null +++ b/rbutil/rbutilqt/base/archiveutil.cpp @@ -0,0 +1,30 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2013 Amaury Pouly + * + * 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 +#include +#include "archiveutil.h" + +ArchiveUtil::ArchiveUtil(QObject* parent) + :QObject(parent) +{ +} + +ArchiveUtil::~ArchiveUtil() +{ +} diff --git a/rbutil/rbutilqt/base/archiveutil.h b/rbutil/rbutilqt/base/archiveutil.h new file mode 100644 index 0000000000..76616728c3 --- /dev/null +++ b/rbutil/rbutilqt/base/archiveutil.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2013 Amaury Pouly + * + * 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 ARCHIVEUTIL_H +#define ARCHIVEUTIL_H + +#include + +class ArchiveUtil : public QObject +{ + Q_OBJECT + + public: + ArchiveUtil(QObject* parent); + ~ArchiveUtil(); + virtual bool close(void) = 0; + virtual bool extractArchive(const QString& dest, QString file = "") = 0; + virtual QStringList files(void) = 0; + + signals: + void logProgress(int, int); + void logItem(QString, int); +}; +#endif + + diff --git a/rbutil/rbutilqt/base/bootloaderinstallbase.cpp b/rbutil/rbutilqt/base/bootloaderinstallbase.cpp index 6cfb2cd1c6..1a47f967b0 100644 --- a/rbutil/rbutilqt/base/bootloaderinstallbase.cpp +++ b/rbutil/rbutilqt/base/bootloaderinstallbase.cpp @@ -22,6 +22,7 @@ #include "bootloaderinstallbase.h" #include "utils.h" #include "ziputil.h" +#include "mspackutil.h" #if defined(Q_OS_MACX) #include @@ -215,11 +216,34 @@ void BootloaderInstallBase::setBlFile(QStringList sl) bool BootloaderInstallBase::setOfFile(QString of, QStringList blfile) { bool found = false; - ZipUtil z(this); - // check if the file set is in zip format - if(z.open(of)) { + ArchiveUtil *util = 0; + + // try ZIP first + ZipUtil *zu = new ZipUtil(this); + if(zu->open(of)) + { emit logItem(tr("Zip file format detected"), LOGINFO); - QStringList contents = z.files(); + util = zu; + } + else + delete zu; + + // if ZIP failed, try CAB + if(util == 0) + { + MsPackUtil *msu = new MsPackUtil(this); + if(msu->open(of)) + { + emit logItem(tr("CAB file format detected"), LOGINFO); + util = msu; + } + else + delete msu; + } + + // check if the file set is in zip format + if(util) { + QStringList contents = util->files(); qDebug() << "[BootloaderInstallBase] archive contains:" << contents; for(int i = 0; i < blfile.size(); ++i) { // strip any path, we don't know the structure in the zip @@ -237,7 +261,7 @@ bool BootloaderInstallBase::setOfFile(QString of, QStringList blfile) m_tempof.open(); m_offile = m_tempof.fileName(); m_tempof.close(); - if(!z.extractArchive(m_offile, contents.at(j))) { + if(!util->extractArchive(m_offile, contents.at(j))) { emit logItem(tr("Error extracting firmware from archive"), LOGERROR); found = false; break; @@ -249,12 +273,13 @@ bool BootloaderInstallBase::setOfFile(QString of, QStringList blfile) if(!found) { emit logItem(tr("Could not find firmware in archive"), LOGERROR); } - + delete util; } else { m_offile = of; found = true; } + return found; } diff --git a/rbutil/rbutilqt/base/mspackutil.cpp b/rbutil/rbutilqt/base/mspackutil.cpp new file mode 100644 index 0000000000..4bc7307cd9 --- /dev/null +++ b/rbutil/rbutilqt/base/mspackutil.cpp @@ -0,0 +1,163 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2013 Amaury Pouly + * + * 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 +#include +#include "mspackutil.h" +#include "progressloggerinterface.h" + +MsPackUtil::MsPackUtil(QObject* parent) + :ArchiveUtil(parent) +{ + m_cabd = mspack_create_cab_decompressor(NULL); + m_cabinet = NULL; + if(!m_cabd) + qDebug() << "[MsPackUtil] CAB decompressor creation failed!"; +} + +MsPackUtil::~MsPackUtil() +{ + close(); + if(m_cabd) + mspack_destroy_cab_decompressor(m_cabd); +} + +bool MsPackUtil::open(QString& mspackfile) +{ + close(); + + if(m_cabd == NULL) + { + qDebug() << "[MsPackUtil] No CAB decompressor available: cannot open file!"; + return false; + } + m_cabinet = m_cabd->search(m_cabd, QFile::encodeName(mspackfile).constData()); + return m_cabinet != NULL; +} + +bool MsPackUtil::close(void) +{ + if(m_cabd && m_cabinet) + m_cabd->close(m_cabd, m_cabinet); + m_cabinet = NULL; + return true; +} + +bool MsPackUtil::extractArchive(const QString& dest, QString file) +{ + qDebug() << "[MsPackUtil] extractArchive" << dest << file; + if(!m_cabinet) + { + qDebug() << "[MsPackUtil] CAB file not open!"; + return false; + } + + // construct the filename when extracting a single file from an archive. + // if the given destination is a full path use it as output name, + // otherwise use it as path to place the file as named in the archive. + QString singleoutfile; + if(!file.isEmpty() && QFileInfo(dest).isDir()) + singleoutfile = dest + "/" + file; + else if(!file.isEmpty()) + singleoutfile = dest; + struct mscabd_file *f = m_cabinet->files; + if(f == NULL) + { + qDebug() << "[MsPackUtil] CAB doesn't contain file" << file; + return true; + } + bool found = false; + while(f) + { + QString name = QFile::decodeName(f->filename); + name.replace("\\", "/"); + if(name.at(0) == '/') + name.remove(0, 1); + if(name == file || file.isEmpty()) + { + QString path; + if(!singleoutfile.isEmpty()) + path = singleoutfile; + else + path = dest + "/" + name; + // make sure the output path exists + if(!QDir().mkpath(QFileInfo(path).absolutePath())) + { + emit logItem(tr("Creating output path failed"), LOGERROR); + qDebug() << "[MsPackUtil] creating output path failed for:" << path; + emit logProgress(1, 1); + return false; + } + int ret = m_cabd->extract(m_cabd, f, QFile::encodeName(path).constData()); + if(ret != MSPACK_ERR_OK) + { + emit logItem(tr("Error during CAB operation"), LOGERROR); + qDebug() << "[MsPackUtil] mspack error: " << ret << "(" << errorStringMsPack(ret) << ")"; + emit logProgress(1, 1); + return false; + } + found = true; + } + f = f->next; + } + emit logProgress(1, 1); + + return found; +} + +QStringList MsPackUtil::files(void) +{ + QStringList list; + if(!m_cabinet) + { + qDebug() << "[MsPackUtil] CAB file not open!"; + return list; + } + struct mscabd_file *file = m_cabinet->files; + while(file) + { + QString name = QFile::decodeName(file->filename); + name.replace("\\", "/"); + if(name.at(0) == '/') + name.remove(0, 1); + list.append(name); + file = file->next; + } + + return list; +} + +QString MsPackUtil::errorStringMsPack(int error) const +{ + switch(error) + { + case MSPACK_ERR_OK: return "Ok"; + case MSPACK_ERR_ARGS: return "Bad arguments"; + case MSPACK_ERR_OPEN: return "Open error"; + case MSPACK_ERR_READ: return "Read error"; + case MSPACK_ERR_WRITE: return "Write error"; + case MSPACK_ERR_SEEK: return "Seek error"; + case MSPACK_ERR_NOMEMORY: return "Out of memory"; + case MSPACK_ERR_SIGNATURE: return "Bad signature"; + case MSPACK_ERR_DATAFORMAT: return "Bad data format"; + case MSPACK_ERR_CHECKSUM: return "Checksum error"; + case MSPACK_ERR_CRUNCH: return "Compression error"; + case MSPACK_ERR_DECRUNCH: return "Decompression error"; + default: return "Unknown"; + } +} diff --git a/rbutil/rbutilqt/base/mspackutil.h b/rbutil/rbutilqt/base/mspackutil.h new file mode 100644 index 0000000000..1cb4350b13 --- /dev/null +++ b/rbutil/rbutilqt/base/mspackutil.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2013 Amaury Pouly + * + * 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 MSPACKUTIL_H +#define MSPACKUTIL_H + +#include +#include "archiveutil.h" +#include "mspack/mspack.h" + +class MsPackUtil : public ArchiveUtil +{ + Q_OBJECT + + public: + // archive types can be ORed + MsPackUtil(QObject* parent); + ~MsPackUtil(); + bool open(QString& mspackfile); + virtual bool close(void); + virtual bool extractArchive(const QString& dest, QString file = ""); + virtual QStringList files(void); + + signals: + void logProgress(int, int); + void logItem(QString, int); + + private: + QString errorStringMsPack(int error) const; + struct mscab_decompressor* m_cabd; + struct mscabd_cabinet *m_cabinet; + +}; +#endif + + diff --git a/rbutil/rbutilqt/base/ziputil.cpp b/rbutil/rbutilqt/base/ziputil.cpp index ca921eb708..b93d5fd86a 100644 --- a/rbutil/rbutilqt/base/ziputil.cpp +++ b/rbutil/rbutilqt/base/ziputil.cpp @@ -26,7 +26,7 @@ #include "quazip/quazipfileinfo.h" -ZipUtil::ZipUtil(QObject* parent) : QObject(parent) +ZipUtil::ZipUtil(QObject* parent) : ArchiveUtil(parent) { m_zip = NULL; } @@ -74,7 +74,7 @@ bool ZipUtil::close(void) //! single file. //! @brief file file to extract from archive, full archive if empty. //! @return true on success, false otherwise -bool ZipUtil::extractArchive(QString& dest, QString file) +bool ZipUtil::extractArchive(const QString& dest, QString file) { qDebug() << "[ZipUtil] extractArchive" << dest << file; bool result = true; diff --git a/rbutil/rbutilqt/base/ziputil.h b/rbutil/rbutilqt/base/ziputil.h index 49a1bd3f06..25c3dce391 100644 --- a/rbutil/rbutilqt/base/ziputil.h +++ b/rbutil/rbutilqt/base/ziputil.h @@ -20,11 +20,12 @@ #define ZIPUTIL_H #include +#include "archiveutil.h" #include "quazip/quazip.h" #include "quazip/quazipfile.h" #include "quazip/quazipfileinfo.h" -class ZipUtil : public QObject +class ZipUtil : public ArchiveUtil { Q_OBJECT @@ -32,12 +33,12 @@ class ZipUtil : public QObject ZipUtil(QObject* parent); ~ZipUtil(); bool open(QString& zipfile, QuaZip::Mode mode = QuaZip::mdUnzip); - bool close(void); - bool extractArchive(QString& dest, QString file = ""); + virtual bool close(void); + virtual bool extractArchive(const QString& dest, QString file = ""); bool appendDirToArchive(QString& source, QString& basedir); bool appendFileToArchive(QString& file, QString& basedir); qint64 totalUncompressedSize(unsigned int clustersize = 0); - QStringList files(void); + virtual QStringList files(void); signals: void logProgress(int, int); diff --git a/rbutil/rbutilqt/rbutilqt.pri b/rbutil/rbutilqt/rbutilqt.pri index 8ec961a50f..b8193d56ab 100644 --- a/rbutil/rbutilqt/rbutilqt.pri +++ b/rbutil/rbutilqt/rbutilqt.pri @@ -79,7 +79,14 @@ SOURCES += \ gui/comboboxviewdelegate.cpp \ gui/selectiveinstallwidget.cpp \ gui/backupdialog.cpp \ - gui/changelog.cpp + gui/changelog.cpp \ + mspack/cabd.c \ + mspack/lzxd.c \ + mspack/mszipd.c \ + mspack/qtmd.c \ + mspack/system-mspack.c \ + base/mspackutil.cpp \ + base/archiveutil.cpp \ HEADERS += \ @@ -157,7 +164,25 @@ HEADERS += \ gui/comboboxviewdelegate.h \ gui/selectiveinstallwidget.h \ gui/backupdialog.h \ - gui/changelog.h + gui/changelog.h \ + mspack/cab.h \ + mspack/chm.h \ + mspack/des.h \ + mspack/hlp.h \ + mspack/kwaj.h \ + mspack/lit.h \ + mspack/lzss.h \ + mspack/lzx.h \ + mspack/mspack.h \ + mspack/mszip.h \ + mspack/qtm.h \ + mspack/readbits.h \ + mspack/readhuff.h \ + mspack/sha.h \ + mspack/system-mspack.h \ + mspack/szdd.h \ + base/mspackutil.h \ + base/archiveutil.h \ FORMS += \ -- cgit v1.2.3