File indexing completed on 2025-01-19 13:26:39
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() override {} 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() override {} 0040 }; 0041 0042 class EOFException : public IOException { 0043 public: 0044 explicit EOFException(const QString &msg = QString()) :IOException(msg) {} 0045 ~EOFException() throw() override {} 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