File indexing completed on 2024-04-28 04:40:01

0001 /* This file is part of the KDE project
0002    Copyright (C) 2009,2010 KO GmbH <jos.van.den.oever@kogmbh.com>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LIB.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018 */
0019 #ifndef LEINPUTSTREAM_H
0020 #define LEINPUTSTREAM_H
0021 
0022 #include <QIODevice>
0023 #include <QDataStream>
0024 #include <QDebug>
0025 #include <exception>
0026 
0027 class IOException : public std::exception {
0028 public:
0029     const QString msg;
0030     IOException() {}
0031     explicit IOException(const QString &m) :msg(m) {}
0032     ~IOException() throw() {}
0033 };
0034 
0035 class IncorrectValueException : public IOException {
0036 public:
0037     explicit IncorrectValueException(const QString &msg) :IOException(msg) {}
0038     IncorrectValueException(qint64 /*pos*/, const char* errMsg) :IOException(errMsg) {}
0039     ~IncorrectValueException() throw() {}
0040 };
0041 
0042 class EOFException : public IOException {
0043 public:
0044     explicit EOFException(const QString &msg = QString()) :IOException(msg) {}
0045     ~EOFException() throw() {}
0046 };
0047 
0048 class LEInputStream {
0049 private:
0050     QIODevice* input;
0051     QDataStream data;
0052 
0053     qint64 maxPosition;
0054 
0055     qint8 bitfieldpos;
0056     quint8 bitfield;
0057 
0058     quint8 getBits(quint8 n) {
0059         if (bitfieldpos < 0) {
0060             bitfield = readuint8();
0061             bitfieldpos = 0;
0062         }
0063         quint8 v = bitfield >> bitfieldpos;
0064         bitfieldpos += n;
0065         if (bitfieldpos == 8) {
0066             bitfieldpos = -1;
0067         } else if (bitfieldpos > 8) {
0068             throw IOException("Bitfield does not have enough bits left.");
0069         }
0070         return v;
0071     }
0072     void checkForLeftOverBits() const {
0073         if (bitfieldpos >= 0) {
0074             throw IOException("Cannot read this type halfway through a bit operation.");
0075         }
0076     }
0077     void checkStatus() const {
0078         if (data.status() != QDataStream::Ok) {
0079             if (data.status() == QDataStream::ReadPastEnd) {
0080                 throw EOFException("Stream claims to be at the end at position: " + QString::number(input->pos()) + "." );
0081             }
0082             throw IOException("Error reading data at position " + QString::number(input->pos()) + ".");
0083         }
0084     }
0085 
0086 public:
0087     class Mark {
0088     friend class LEInputStream;
0089     private:
0090         QIODevice* input;
0091         qint64 pos;
0092         explicit Mark(QIODevice *in) :input(in), pos((in) ?in->pos() :0) {}
0093     public:
0094         Mark() :input(0), pos(0) {} 
0095     };
0096 
0097     LEInputStream(QIODevice* in) :input(in), data(in) {
0098         maxPosition = 0;
0099         bitfield = 0;
0100         bitfieldpos = -1;
0101         data.setByteOrder(QDataStream::LittleEndian);
0102     }
0103 
0104     Mark setMark() { return Mark(input); }
0105     void rewind(const Mark& m) {
0106         maxPosition = qMax(input->pos(), maxPosition);
0107         if (!m.input || !m.input->seek(m.pos)) {
0108             throw IOException("Cannot rewind.");
0109         }
0110         data.resetStatus();
0111     }
0112 
0113     bool readbit() {
0114         quint8 v = getBits(1) & 1;
0115         return v == 1;
0116     }
0117 
0118     quint8 readuint2() {
0119         return getBits(2) & 3;
0120     }
0121 
0122     quint8 readuint3() {
0123         return getBits(3) & 0x7;
0124     }
0125 
0126     quint8 readuint4() {
0127         return getBits(4) & 0xF;
0128     }
0129 
0130     quint8 readuint5() {
0131         return getBits(5) & 0x1F;
0132     }
0133 
0134     quint8 readuint6() {
0135         return getBits(6) & 0x3F;
0136     }
0137 
0138     quint8 readuint7() {
0139         return getBits(7) & 0x7F;
0140     }
0141 
0142     quint16 readuint9() {
0143         quint8 a = readuint8();
0144         quint8 b = getBits(1) & 0x1;
0145         return (b << 8) | a;
0146     }
0147 
0148     quint16 readuint12() {
0149         // we assume there are 4 bits left
0150         quint8 a = getBits(4) & 0xF;
0151         quint8 b = readuint8();
0152         return (b << 4) | a;
0153     }
0154 
0155     quint16 readuint13() {
0156         quint8 a = getBits(5) & 0x1F;
0157         quint8 b = readuint8();
0158         return (b << 5) | a;
0159     }
0160 
0161     quint16 readuint14() {
0162         quint16 v;
0163         if (bitfieldpos < 0) {
0164             quint8 a = readuint8();
0165             quint8 b = getBits(6) & 0x3F;
0166             v = (b << 8) | a;
0167         } else if (bitfieldpos == 2) {
0168             quint8 a = getBits(6) & 0x3F;
0169             quint8 b = readuint8();
0170             v = (b << 6) | a;
0171         } else {
0172             throw IOException("Cannot read this type halfway through a bit operation.");
0173         }
0174         return v;
0175     }
0176 
0177     quint16 readuint15() {
0178         // we assume there are 7 bits left
0179         quint8 a = getBits(7) & 0x7F;
0180         quint8 b = readuint8();
0181         return (b << 7) | a;
0182     }
0183 
0184     quint32 readuint20() {
0185         quint32 v;
0186         if (bitfieldpos < 0) {
0187             quint8 a = readuint8();
0188             quint8 b = readuint8();
0189             quint8 c = getBits(4) & 0xF;
0190             v = (c << 16) | (b << 8) | a;
0191         } else if (bitfieldpos == 4) {
0192             quint8 a = getBits(4) & 0xF;
0193             quint8 b = readuint8();
0194             quint8 c = readuint8();
0195             v = (c << 12) | (b << 4) | a;
0196         } else {
0197             throw IOException("Cannot read this type halfway through a bit operation.");
0198         }
0199         return v;
0200     }
0201 
0202     quint32 readuint30() {
0203         checkForLeftOverBits();
0204         quint8 a = readuint8();
0205         quint8 b = readuint8();
0206         quint8 c = readuint8();
0207         quint8 d = getBits(6) & 0x3F;
0208         return (d << 24) | (c << 16) | (b << 8) | a;
0209     }
0210 
0211     quint8 readuint8() {
0212         checkForLeftOverBits();
0213         quint8 a;
0214         data >> a;
0215         checkStatus();
0216         return a;
0217     }
0218 
0219     qint16 readint16() {
0220         checkForLeftOverBits();
0221         qint16 v;
0222         data >> v;
0223         checkStatus();
0224         return v;
0225     }
0226 
0227     quint16 readuint16() {
0228         checkForLeftOverBits();
0229         quint16 v;
0230         data >> v;
0231         checkStatus();
0232         return v;
0233     }
0234 
0235     quint32 readuint32() {
0236         checkForLeftOverBits();
0237         quint32 v;
0238         data >> v;
0239         checkStatus();
0240         return v;
0241     }
0242 
0243     qint32 readint32() {
0244         checkForLeftOverBits();
0245         qint32 v;
0246         data >> v;
0247         checkStatus();
0248         return v;
0249     }
0250 
0251     void readBytes(QByteArray& b) {
0252         int offset = 0;
0253         int todo = b.size();
0254         while (todo > 0) { // do not enter loop if array size is 0
0255             int nread = data.readRawData(b.data() + offset, todo);
0256             if (nread == -1 || nread == 0) {
0257                 throw EOFException();// TODO: differentiate
0258             }
0259             todo -= nread;
0260             offset += nread;
0261         }
0262     }
0263 
0264     void skip(int len) {
0265         data.skipRawData(len);
0266     }
0267 
0268     qint64 getPosition() const { return input->pos(); }
0269 
0270     qint64 getMaxPosition() const { return qMax(input->pos(), maxPosition); }
0271     qint64 getSize() const { return input->size(); }
0272 };
0273 
0274 #endif