Chris@148: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
Chris@148: 
Chris@148: /*
Chris@148:     Sonic Visualiser
Chris@148:     An audio file viewer and annotation editor.
Chris@148:     Centre for Digital Music, Queen Mary, University of London.
Chris@148:     This file copyright 2006 Chris Cannam.
Chris@148:     
Chris@148:     This program is free software; you can redistribute it and/or
Chris@148:     modify it under the terms of the GNU General Public License as
Chris@148:     published by the Free Software Foundation; either version 2 of the
Chris@148:     License, or (at your option) any later version.  See the file
Chris@148:     COPYING included with this distribution for more information.
Chris@148: */
Chris@148: 
Chris@148: #include "BZipFileDevice.h"
Chris@148: 
Chris@148: #include <bzlib.h>
Chris@148: 
Chris@148: #include <iostream>
Chris@148: 
Chris@148: BZipFileDevice::BZipFileDevice(QString fileName) :
Chris@148:     m_fileName(fileName),
Chris@148:     m_file(0),
Chris@148:     m_bzFile(0),
Chris@207:     m_atEnd(true),
Chris@207:     m_ok(true)
Chris@148: {
Chris@148: }
Chris@148: 
Chris@148: BZipFileDevice::~BZipFileDevice()
Chris@148: {
Chris@148: //    std::cerr << "BZipFileDevice::~BZipFileDevice(" << m_fileName.toStdString() << ")" << std::endl;
Chris@148:     if (m_bzFile) close();
Chris@148: }
Chris@148: 
Chris@148: bool
Chris@207: BZipFileDevice::isOK() const
Chris@207: {
Chris@207:     return m_ok;
Chris@207: }
Chris@207: 
Chris@207: bool
Chris@148: BZipFileDevice::open(OpenMode mode)
Chris@148: {
Chris@203:     setErrorString("");
Chris@203: 
Chris@148:     if (m_bzFile) {
Chris@148:         setErrorString(tr("File is already open"));
Chris@148:         return false;
Chris@148:     }
Chris@148: 
Chris@148:     if (mode & Append) {
Chris@148:         setErrorString(tr("Append mode not supported"));
Chris@207:         m_ok = false;
Chris@148:         return false;
Chris@148:     }
Chris@148: 
Chris@148:     if ((mode & (ReadOnly | WriteOnly)) == 0) {
Chris@148:         setErrorString(tr("File access mode not specified"));
Chris@207:         m_ok = false;
Chris@148:         return false;
Chris@148:     }
Chris@148: 
Chris@148:     if ((mode & ReadOnly) && (mode & WriteOnly)) {
Chris@148:         setErrorString(tr("Read and write modes both specified"));
Chris@207:         m_ok = false;
Chris@148:         return false;
Chris@148:     }
Chris@148: 
Chris@148:     if (mode & WriteOnly) {
Chris@148: 
Chris@148:         m_file = fopen(m_fileName.toLocal8Bit().data(), "wb");
Chris@148:         if (!m_file) {
Chris@148:             setErrorString(tr("Failed to open file for writing"));
Chris@207:             m_ok = false;
Chris@148:             return false;
Chris@148:         }
Chris@148: 
Chris@148:         int bzError = BZ_OK;
Chris@148:         m_bzFile = BZ2_bzWriteOpen(&bzError, m_file, 9, 0, 0);
Chris@148: 
Chris@148:         if (!m_bzFile) {
Chris@148:             fclose(m_file);
Chris@148:             m_file = 0;
Chris@148:             setErrorString(tr("Failed to open bzip2 stream for writing"));
Chris@207:             m_ok = false;
Chris@148:             return false;
Chris@148:         }
Chris@148: 
Chris@148: //        std::cerr << "BZipFileDevice: opened \"" << m_fileName.toStdString() << "\" for writing" << std::endl;
Chris@148: 
Chris@148:         setErrorString(QString());
Chris@148:         setOpenMode(mode);
Chris@148:         return true;
Chris@148:     }
Chris@148: 
Chris@148:     if (mode & ReadOnly) {
Chris@148: 
Chris@148:         m_file = fopen(m_fileName.toLocal8Bit().data(), "rb");
Chris@148:         if (!m_file) {
Chris@148:             setErrorString(tr("Failed to open file for reading"));
Chris@207:             m_ok = false;
Chris@148:             return false;
Chris@148:         }
Chris@148: 
Chris@148:         int bzError = BZ_OK;
Chris@148:         m_bzFile = BZ2_bzReadOpen(&bzError, m_file, 0, 0, NULL, 0);
Chris@148: 
Chris@148:         if (!m_bzFile) {
Chris@148:             fclose(m_file);
Chris@148:             m_file = 0;
Chris@148:             setErrorString(tr("Failed to open bzip2 stream for reading"));
Chris@207:             m_ok = false;
Chris@148:             return false;
Chris@148:         }
Chris@148: 
Chris@148: //        std::cerr << "BZipFileDevice: opened \"" << m_fileName.toStdString() << "\" for reading" << std::endl;
Chris@148: 
Chris@148:         m_atEnd = false;
Chris@148: 
Chris@148:         setErrorString(QString());
Chris@148:         setOpenMode(mode);
Chris@148:         return true;
Chris@148:     }
Chris@148: 
Chris@148:     setErrorString(tr("Internal error (open for neither read nor write)"));
Chris@207:     m_ok = false;
Chris@148:     return false;
Chris@148: }
Chris@148: 
Chris@148: void
Chris@148: BZipFileDevice::close()
Chris@148: {
Chris@148:     if (!m_bzFile) {
Chris@148:         setErrorString(tr("File not open"));
Chris@207:         m_ok = false;
Chris@148:         return;
Chris@148:     }
Chris@148: 
Chris@148:     int bzError = BZ_OK;
Chris@148: 
Chris@148:     if (openMode() & WriteOnly) {
Chris@148:         unsigned int in = 0, out = 0;
Chris@148:         BZ2_bzWriteClose(&bzError, m_bzFile, 0, &in, &out);
Chris@148: //	std::cerr << "Wrote bzip2 stream (in=" << in << ", out=" << out << ")" << std::endl;
Chris@148: 	if (bzError != BZ_OK) {
Chris@148: 	    setErrorString(tr("bzip2 stream write close error"));
Chris@148: 	}
Chris@148:         fclose(m_file);
Chris@148:         m_bzFile = 0;
Chris@148:         m_file = 0;
Chris@207:         m_ok = false;
Chris@148:         return;
Chris@148:     }
Chris@148: 
Chris@148:     if (openMode() & ReadOnly) {
Chris@148:         BZ2_bzReadClose(&bzError, m_bzFile);
Chris@148:         if (bzError != BZ_OK) {
Chris@148:             setErrorString(tr("bzip2 stream read close error"));
Chris@148:         }
Chris@148:         fclose(m_file);
Chris@148:         m_bzFile = 0;
Chris@148:         m_file = 0;
Chris@207:         m_ok = false;
Chris@148:         return;
Chris@148:     }
Chris@148: 
Chris@148:     setErrorString(tr("Internal error (close for neither read nor write)"));
Chris@148:     return;
Chris@148: }
Chris@148: 
Chris@148: qint64
Chris@148: BZipFileDevice::readData(char *data, qint64 maxSize)
Chris@148: {
Chris@148:     if (m_atEnd) return 0;
Chris@148: 
Chris@148:     int bzError = BZ_OK;
Chris@148:     int read = BZ2_bzRead(&bzError, m_bzFile, data, maxSize);
Chris@148: 
Chris@148: //    std::cerr << "BZipFileDevice::readData: requested " << maxSize << ", read " << read << std::endl;
Chris@148: 
Chris@148:     if (bzError != BZ_OK) {
Chris@148:         if (bzError != BZ_STREAM_END) {
Chris@148:             std::cerr << "BZipFileDevice::readData: error condition" << std::endl;
Chris@148:             setErrorString(tr("bzip2 stream read error"));
Chris@207:             m_ok = false;
Chris@148:             return -1;
Chris@148:         } else {
Chris@148: //            std::cerr << "BZipFileDevice::readData: reached end of file" << std::endl;
Chris@148:             m_atEnd = true;
Chris@148:         }            
Chris@148:     }
Chris@148: 
Chris@148:     return read;
Chris@148: }
Chris@148: 
Chris@148: qint64
Chris@148: BZipFileDevice::writeData(const char *data, qint64 maxSize)
Chris@148: {
Chris@148:     int bzError = BZ_OK;
Chris@148:     BZ2_bzWrite(&bzError, m_bzFile, (void *)data, maxSize);
Chris@148: 
Chris@148: //    std::cerr << "BZipFileDevice::writeData: " << maxSize << " to write" << std::endl;
Chris@148: 
Chris@148:     if (bzError != BZ_OK) {
Chris@148:         std::cerr << "BZipFileDevice::writeData: error condition" << std::endl;
Chris@148:         setErrorString("bzip2 stream write error");
Chris@207:         m_ok = false;
Chris@148:         return -1;
Chris@148:     }
Chris@148: 
Chris@148: //    std::cerr << "BZipFileDevice::writeData: wrote " << maxSize << std::endl;
Chris@148: 
Chris@148:     return maxSize;
Chris@148: }
Chris@148: