Commit e5edf7f667daef8d5e6cee6394601719feac5328

Authored by Charles Otto
1 parent f2f88b8c

Introduce a QIODevice subclass for compressing output in fixed sized blocks

openbr/core/qtutils.cpp
... ... @@ -500,6 +500,140 @@ QString getAbsolutePath(const QString &filename)
500 500 return QFileInfo(filename).absoluteFilePath();
501 501 }
502 502  
  503 +BlockCompression::BlockCompression(QIODevice *_basis)
  504 +{
  505 + blockSize = 1000000;
  506 + setBasis(_basis);
  507 +}
  508 +
  509 +BlockCompression::BlockCompression() { blockSize = 1000000; };
  510 +
  511 +
  512 +bool BlockCompression::open(QIODevice::OpenMode mode)
  513 +{
  514 + this->setOpenMode(mode);
  515 + bool res = basis->open(mode);
  516 +// qDebug() << "basis: " << basis->isReadable() << " write:" << basis->isWritable();
  517 + if (!res)
  518 + return false;
  519 +
  520 + blockReader.setDevice(basis);
  521 + blockWriter.setDevice(basis);
  522 +
  523 + if (mode & QIODevice::WriteOnly) {
  524 + precompressedBlockWriter = new QBuffer;
  525 + precompressedBlockWriter->open(QIODevice::ReadWrite);
  526 + }
  527 + else if (mode & QIODevice::ReadOnly) {
  528 +// qDebug() << "BLock reader status:" << blockReader.status();
  529 + QByteArray compressedBlock;
  530 + blockReader >> compressedBlock;
  531 +// qDebug() <<" Post read attempt, " << blockReader.status();
  532 +
  533 + decompressedBlock = qUncompress(compressedBlock);
  534 +// qDebug() << "Read compressed block: " << compressedBlock.size() << "Expanded to:" << decompressedBlock.size();
  535 + decompressedBlockReader.setBuffer(&decompressedBlock);
  536 + decompressedBlockReader.open(QIODevice::ReadOnly);
  537 + }
  538 +
  539 + return true;
  540 +}
  541 +
  542 +void BlockCompression::close()
  543 +{
  544 + // flush output buffer
  545 + if ((openMode() & QIODevice::WriteOnly) && precompressedBlockWriter) {
  546 + qDebug() << "Serializing final block";
  547 + QByteArray compressedBlock = qCompress(precompressedBlockWriter->buffer(), -1);
  548 + blockWriter << compressedBlock;
  549 + qDebug() << "Done";
  550 + }
  551 + basis->close();
  552 +}
  553 +
  554 +void BlockCompression::setBasis(QIODevice *_basis)
  555 +{
  556 + basis = _basis;
  557 + blockReader.setDevice(basis);
  558 + blockWriter.setDevice(basis);
  559 +}
  560 +
  561 +// read from current decompressed block, if out of space, read and decompress another
  562 +// block from basis
  563 +qint64 BlockCompression::readData(char *data, qint64 remaining)
  564 +{
  565 +// qDebug() <<" Reading: " << remaining;
  566 + qint64 read = 0;
  567 + while (remaining > 0) {
  568 + qint64 single_read = decompressedBlockReader.read(data, remaining);
  569 + if (single_read == -1)
  570 + qFatal("miss read");
  571 +// single_read = 0;
  572 +
  573 +
  574 + remaining -= single_read;
  575 + read += single_read;
  576 + data += single_read;
  577 +// qDebug() << "Read " << single_read << " reamining: "<< remaining;
  578 +
  579 + // need a new block
  580 + if (remaining > 0) {
  581 + QByteArray compressedBlock;
  582 + blockReader >> compressedBlock;
  583 + if (compressedBlock.size() == 0) {
  584 + return read;
  585 + }
  586 + decompressedBlock = qUncompress(compressedBlock);
  587 +
  588 + decompressedBlockReader.close();
  589 + decompressedBlockReader.setBuffer(&decompressedBlock);
  590 + decompressedBlockReader.open(QIODevice::ReadOnly);
  591 + }
  592 + }
  593 + return blockReader.atEnd() && !basis->isReadable() ? -1 : read;
  594 +}
  595 +
  596 +bool BlockCompression::isSequential() const
  597 +{
  598 + return true;
  599 +}
  600 +
  601 +qint64 BlockCompression::writeData(const char *data, qint64 remaining)
  602 +{
  603 + qint64 written = 0;
  604 +
  605 + while (remaining > 0) {
  606 + // how much more can be put in this buffer?
  607 + qint64 capacity = blockSize - precompressedBlockWriter->pos();
  608 +
  609 + // don't try to write beyond capacity
  610 + qint64 write_size = qMin(capacity, remaining);
  611 +
  612 + qint64 singleWrite = precompressedBlockWriter->write(data, write_size);
  613 + // ignore the error case here, we consdier basis's failure mode the real
  614 + // end case
  615 + if (singleWrite == -1)
  616 + singleWrite = 0;
  617 +
  618 + remaining -= singleWrite;
  619 + data += singleWrite;
  620 + written += singleWrite;
  621 +
  622 + if (remaining > 0) {
  623 + QByteArray compressedBlock = qCompress(precompressedBlockWriter->buffer(), -1);
  624 +
  625 + if (compressedBlock.size() != 0)
  626 + blockWriter << compressedBlock;
  627 +
  628 + delete precompressedBlockWriter;
  629 + precompressedBlockWriter = new QBuffer;
  630 + precompressedBlockWriter->open(QIODevice::ReadWrite);
  631 + }
  632 + }
  633 + return basis->isWritable() ? written : -1;
  634 +}
  635 +
  636 +
503 637  
504 638 } // namespace QtUtils
505 639  
... ...
openbr/core/qtutils.h
... ... @@ -17,6 +17,7 @@
17 17 #ifndef QTUTILS_QTUTILS_H
18 18 #define QTUTILS_QTUTILS_H
19 19  
  20 +#include <QBuffer>
20 21 #include <QByteArray>
21 22 #include <QDir>
22 23 #include <QFile>
... ... @@ -93,6 +94,38 @@ namespace QtUtils
93 94  
94 95 /**** Rect Utilities ****/
95 96 float overlap(const QRectF &r, const QRectF &s);
  97 +
  98 +
  99 + class BlockCompression : public QIODevice
  100 + {
  101 + public:
  102 + BlockCompression(QIODevice *_basis);
  103 + BlockCompression();
  104 + int blockSize;
  105 + QIODevice *basis;
  106 +
  107 + bool open(QIODevice::OpenMode mode);
  108 +
  109 + void close();
  110 +
  111 + void setBasis(QIODevice *_basis);
  112 +
  113 + QDataStream blockReader;
  114 + QByteArray decompressedBlock;
  115 + QBuffer decompressedBlockReader;
  116 +
  117 + // read from current decompressed block, if out of space, read and decompress another
  118 + // block from basis
  119 + qint64 readData(char *data, qint64 remaining);
  120 +
  121 + bool isSequential() const;
  122 +
  123 + // write to a QByteArray, when max block sized is reached, compress and write
  124 + // it to basis
  125 + QBuffer * precompressedBlockWriter;
  126 + QDataStream blockWriter;
  127 + qint64 writeData(const char *data, qint64 remaining);
  128 + };
96 129 }
97 130  
98 131 #endif // QTUTILS_QTUTILS_H
... ...