1 /* This file is part of the KDE project 2 Copyright (C) 2009,2010 KO GmbH <jos.van.den.oever@kogmbh.com> 3 4 This library is free software; you can redistribute it and/or 5 modify it under the terms of the GNU Library General Public 6 License as published by the Free Software Foundation; either 7 version 2 of the License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Library General Public License for more details. 13 14 You should have received a copy of the GNU Library General Public License 15 along with this library; see the file COPYING.LIB. If not, write to 16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 */ 19 #ifndef LEINPUTSTREAM_H 20 #define LEINPUTSTREAM_H 21 22 #include <QIODevice> 23 #include <QDataStream> 24 #include <QDebug> 25 #include <exception> 26 27 class IOException : public std::exception { 28 public: 29 const QString msg; IOException()30 IOException() {} IOException(const QString & m)31 explicit IOException(const QString &m) :msg(m) {} throw()32 ~IOException() throw() override {} 33 }; 34 35 class IncorrectValueException : public IOException { 36 public: IncorrectValueException(const QString & msg)37 explicit IncorrectValueException(const QString &msg) :IOException(msg) {} IncorrectValueException(qint64,const char * errMsg)38 IncorrectValueException(qint64 /*pos*/, const char* errMsg) :IOException(errMsg) {} throw()39 ~IncorrectValueException() throw() override {} 40 }; 41 42 class EOFException : public IOException { 43 public: IOException(msg)44 explicit EOFException(const QString &msg = QString()) :IOException(msg) {} throw()45 ~EOFException() throw() override {} 46 }; 47 48 class LEInputStream { 49 private: 50 QIODevice* input; 51 QDataStream data; 52 53 qint64 maxPosition; 54 55 qint8 bitfieldpos; 56 quint8 bitfield; 57 getBits(quint8 n)58 quint8 getBits(quint8 n) { 59 if (bitfieldpos < 0) { 60 bitfield = readuint8(); 61 bitfieldpos = 0; 62 } 63 quint8 v = bitfield >> bitfieldpos; 64 bitfieldpos += n; 65 if (bitfieldpos == 8) { 66 bitfieldpos = -1; 67 } else if (bitfieldpos > 8) { 68 throw IOException("Bitfield does not have enough bits left."); 69 } 70 return v; 71 } checkForLeftOverBits()72 void checkForLeftOverBits() const { 73 if (bitfieldpos >= 0) { 74 throw IOException("Cannot read this type halfway through a bit operation."); 75 } 76 } checkStatus()77 void checkStatus() const { 78 if (data.status() != QDataStream::Ok) { 79 if (data.status() == QDataStream::ReadPastEnd) { 80 throw EOFException("Stream claims to be at the end at position: " + QString::number(input->pos()) + "." ); 81 } 82 throw IOException("Error reading data at position " + QString::number(input->pos()) + "."); 83 } 84 } 85 86 public: 87 class Mark { 88 friend class LEInputStream; 89 private: 90 QIODevice* input; 91 qint64 pos; Mark(QIODevice * in)92 explicit Mark(QIODevice *in) :input(in), pos((in) ?in->pos() :0) {} 93 public: Mark()94 Mark() :input(0), pos(0) {} 95 }; 96 LEInputStream(QIODevice * in)97 LEInputStream(QIODevice* in) :input(in), data(in) { 98 maxPosition = 0; 99 bitfield = 0; 100 bitfieldpos = -1; 101 data.setByteOrder(QDataStream::LittleEndian); 102 } 103 setMark()104 Mark setMark() { return Mark(input); } rewind(const Mark & m)105 void rewind(const Mark& m) { 106 maxPosition = qMax(input->pos(), maxPosition); 107 if (!m.input || !m.input->seek(m.pos)) { 108 throw IOException("Cannot rewind."); 109 } 110 data.resetStatus(); 111 } 112 readbit()113 bool readbit() { 114 quint8 v = getBits(1) & 1; 115 return v == 1; 116 } 117 readuint2()118 quint8 readuint2() { 119 return getBits(2) & 3; 120 } 121 readuint3()122 quint8 readuint3() { 123 return getBits(3) & 0x7; 124 } 125 readuint4()126 quint8 readuint4() { 127 return getBits(4) & 0xF; 128 } 129 readuint5()130 quint8 readuint5() { 131 return getBits(5) & 0x1F; 132 } 133 readuint6()134 quint8 readuint6() { 135 return getBits(6) & 0x3F; 136 } 137 readuint7()138 quint8 readuint7() { 139 return getBits(7) & 0x7F; 140 } 141 readuint9()142 quint16 readuint9() { 143 quint8 a = readuint8(); 144 quint8 b = getBits(1) & 0x1; 145 return (b << 8) | a; 146 } 147 readuint12()148 quint16 readuint12() { 149 // we assume there are 4 bits left 150 quint8 a = getBits(4) & 0xF; 151 quint8 b = readuint8(); 152 return (b << 4) | a; 153 } 154 readuint13()155 quint16 readuint13() { 156 quint8 a = getBits(5) & 0x1F; 157 quint8 b = readuint8(); 158 return (b << 5) | a; 159 } 160 readuint14()161 quint16 readuint14() { 162 quint16 v; 163 if (bitfieldpos < 0) { 164 quint8 a = readuint8(); 165 quint8 b = getBits(6) & 0x3F; 166 v = (b << 8) | a; 167 } else if (bitfieldpos == 2) { 168 quint8 a = getBits(6) & 0x3F; 169 quint8 b = readuint8(); 170 v = (b << 6) | a; 171 } else { 172 throw IOException("Cannot read this type halfway through a bit operation."); 173 } 174 return v; 175 } 176 readuint15()177 quint16 readuint15() { 178 // we assume there are 7 bits left 179 quint8 a = getBits(7) & 0x7F; 180 quint8 b = readuint8(); 181 return (b << 7) | a; 182 } 183 readuint20()184 quint32 readuint20() { 185 quint32 v; 186 if (bitfieldpos < 0) { 187 quint8 a = readuint8(); 188 quint8 b = readuint8(); 189 quint8 c = getBits(4) & 0xF; 190 v = (c << 16) | (b << 8) | a; 191 } else if (bitfieldpos == 4) { 192 quint8 a = getBits(4) & 0xF; 193 quint8 b = readuint8(); 194 quint8 c = readuint8(); 195 v = (c << 12) | (b << 4) | a; 196 } else { 197 throw IOException("Cannot read this type halfway through a bit operation."); 198 } 199 return v; 200 } 201 readuint30()202 quint32 readuint30() { 203 checkForLeftOverBits(); 204 quint8 a = readuint8(); 205 quint8 b = readuint8(); 206 quint8 c = readuint8(); 207 quint8 d = getBits(6) & 0x3F; 208 return (d << 24) | (c << 16) | (b << 8) | a; 209 } 210 readuint8()211 quint8 readuint8() { 212 checkForLeftOverBits(); 213 quint8 a; 214 data >> a; 215 checkStatus(); 216 return a; 217 } 218 readint16()219 qint16 readint16() { 220 checkForLeftOverBits(); 221 qint16 v; 222 data >> v; 223 checkStatus(); 224 return v; 225 } 226 readuint16()227 quint16 readuint16() { 228 checkForLeftOverBits(); 229 quint16 v; 230 data >> v; 231 checkStatus(); 232 return v; 233 } 234 readuint32()235 quint32 readuint32() { 236 checkForLeftOverBits(); 237 quint32 v; 238 data >> v; 239 checkStatus(); 240 return v; 241 } 242 readint32()243 qint32 readint32() { 244 checkForLeftOverBits(); 245 qint32 v; 246 data >> v; 247 checkStatus(); 248 return v; 249 } 250 readBytes(QByteArray & b)251 void readBytes(QByteArray& b) { 252 int offset = 0; 253 int todo = b.size(); 254 while (todo > 0) { // do not enter loop if array size is 0 255 int nread = data.readRawData(b.data() + offset, todo); 256 if (nread == -1 || nread == 0) { 257 throw EOFException();// TODO: differentiate 258 } 259 todo -= nread; 260 offset += nread; 261 } 262 } 263 skip(int len)264 void skip(int len) { 265 data.skipRawData(len); 266 } 267 getPosition()268 qint64 getPosition() const { return input->pos(); } 269 getMaxPosition()270 qint64 getMaxPosition() const { return qMax(input->pos(), maxPosition); } getSize()271 qint64 getSize() const { return input->size(); } 272 }; 273 274 #endif 275