cb2cb4b by Jos van den Oever at 2010-01-25 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
*/
3a5cbea by Jos van den Oever at 2009-08-27 19
#ifndef LEINPUTSTREAM_H
20
#define LEINPUTSTREAM_H
21
313b78e by Jos van den Oever at 2009-09-12 22
#include <QtCore/QIODevice>
23
#include <QtCore/QDataStream>
e013083 by Jos van den Oever at 2009-09-16 24
#include <QtCore/QDebug>
75317b3 by Jos van den Oever at 2009-09-12 25
#include <exception>
26
313b78e by Jos van den Oever at 2009-09-12 27
class IOException : public std::exception {
3a5cbea by Jos van den Oever at 2009-08-27 28
public:
313b78e by Jos van den Oever at 2009-09-12 29
    const QString msg;
af3349f by Jos van den Oever at 2009-09-12 30
    IOException() {}
313b78e by Jos van den Oever at 2009-09-12 31
    IOException(const QString& m) :msg(m) {}
32
    ~IOException() throw() {}
3a5cbea by Jos van den Oever at 2009-08-27 33
};
34
313b78e by Jos van den Oever at 2009-09-12 35
class IncorrectValueException : public IOException {
75317b3 by Jos van den Oever at 2009-09-12 36
public:
313b78e by Jos van den Oever at 2009-09-12 37
    IncorrectValueException(const QString& msg) :IOException(msg) {}
55d39fd by Jos van den Oever at 2010-01-22 38
    IncorrectValueException(qint64 /*pos*/, const char* errMsg) :IOException(errMsg) {}
313b78e by Jos van den Oever at 2009-09-12 39
    ~IncorrectValueException() throw() {}
40
};
41
42
class EOFException : public IOException {
43
public:
2f03da6 by Jos van den Oever at 2010-01-28 44
    EOFException(const QString& msg = QString()) :IOException(msg) {}
313b78e by Jos van den Oever at 2009-09-12 45
    ~EOFException() throw() {}
75317b3 by Jos van den Oever at 2009-09-12 46
};
47
3a5cbea by Jos van den Oever at 2009-08-27 48
class LEInputStream {
313b78e by Jos van den Oever at 2009-09-12 49
private:
50
    QIODevice* input;
51
    QDataStream data;
52
55d39fd by Jos van den Oever at 2010-01-22 53
    qint64 maxPosition;
54
af3349f by Jos van den Oever at 2009-09-12 55
    qint8 bitfieldpos;
313b78e by Jos van den Oever at 2009-09-12 56
    quint8 bitfield;
57
58
    quint8 getBits(quint8 n) {
59
        if (bitfieldpos < 0) {
af3349f by Jos van den Oever at 2009-09-12 60
            bitfield = readuint8();
313b78e by Jos van den Oever at 2009-09-12 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
    }
af3349f by Jos van den Oever at 2009-09-12 72
    void checkForLeftOverBits() const {
313b78e by Jos van den Oever at 2009-09-12 73
        if (bitfieldpos >= 0) {
74
            throw IOException("Cannot read this type halfway through a bit operation.");
75
        }
76
    }
af3349f by Jos van den Oever at 2009-09-12 77
    void checkStatus() const {
78
        if (data.status() != QDataStream::Ok) {
79
            if (data.status() == QDataStream::ReadPastEnd) {
2f03da6 by Jos van den Oever at 2010-01-28 80
                throw EOFException("Stream claims to be at the end at position: " + QString::number(input->pos()) + "." );
af3349f by Jos van den Oever at 2009-09-12 81
            }
82
            throw IOException("Error reading data at position " + QString::number(input->pos()) + ".");
83
        }
84
    }
313b78e by Jos van den Oever at 2009-09-12 85
3a5cbea by Jos van den Oever at 2009-08-27 86
public:
75317b3 by Jos van den Oever at 2009-09-12 87
    class Mark {
313b78e by Jos van den Oever at 2009-09-12 88
    friend class LEInputStream;
89
    private:
90
        QIODevice* input;
91
        qint64 pos;
92
        Mark(QIODevice* in) :input(in), pos((in) ?in->pos() :0) {} 
75317b3 by Jos van den Oever at 2009-09-12 93
    public:
313b78e by Jos van den Oever at 2009-09-12 94
        Mark() :input(0), pos(0) {} 
75317b3 by Jos van den Oever at 2009-09-12 95
    };
96
313b78e by Jos van den Oever at 2009-09-12 97
    LEInputStream(QIODevice* in) :input(in), data(in) {
55d39fd by Jos van den Oever at 2010-01-22 98
        maxPosition = 0;
af3349f by Jos van den Oever at 2009-09-12 99
        bitfield = 0;
100
        bitfieldpos = -1;
313b78e by Jos van den Oever at 2009-09-12 101
        data.setByteOrder(QDataStream::LittleEndian);
102
    }
103
104
    Mark setMark() { return Mark(input); }
105
    void rewind(const Mark& m) {
55d39fd by Jos van den Oever at 2010-01-22 106
        maxPosition = qMax(input->pos(), maxPosition);
313b78e by Jos van den Oever at 2009-09-12 107
        if (!m.input || !m.input->seek(m.pos)) {
108
            throw IOException("Cannot rewind.");
109
        }
3900d6a by Jos van den Oever at 2010-07-29 110
        data.resetStatus();
313b78e by Jos van den Oever at 2009-09-12 111
    }
112
113
    bool readbit() {
114
        quint8 v = getBits(1) & 1;
115
        return v == 1;
116
    }
117
118
    quint8 readuint2() {
119
        return getBits(2) & 3;
120
    }
121
122
    quint8 readuint3() {
123
        return getBits(3) & 0x7;
124
    }
125
126
    quint8 readuint4() {
127
        return getBits(4) & 0xF;
128
    }
129
130
    quint8 readuint5() {
131
        return getBits(5) & 0x1F;
132
    }
133
134
    quint8 readuint6() {
135
        return getBits(6) & 0x3F;
136
    }
137
138
    quint8 readuint7() {
139
        return getBits(7) & 0x7F;
140
    }
141
142
    quint16 readuint9() {
143
        quint8 a = readuint8();
144
        quint8 b = getBits(1) & 0x1;
4104173 by Jos van den Oever at 2009-12-19 145
        return (b << 8) | a;
313b78e by Jos van den Oever at 2009-09-12 146
    }
147
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
dc5b75d by Jos van den Oever at 2010-09-27 155
    quint16 readuint13() {
156
        quint8 a = getBits(5) & 0x1F;
157
        quint8 b = readuint8();
158
        return (b << 5) | a;
159
    }
160
313b78e by Jos van den Oever at 2009-09-12 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
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
184
    quint32 readuint20() {
2e58eab by Jos van den Oever at 2009-09-16 185
        quint32 v;
313b78e by Jos van den Oever at 2009-09-12 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
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
211
    quint8 readuint8() {
212
        checkForLeftOverBits();
213
        quint8 a;
214
        data >> a;
af3349f by Jos van den Oever at 2009-09-12 215
        checkStatus();
313b78e by Jos van den Oever at 2009-09-12 216
        return a;
217
    }
218
219
    qint16 readint16() {
220
        checkForLeftOverBits();
221
        qint16 v;
222
        data >> v;
af3349f by Jos van den Oever at 2009-09-12 223
        checkStatus();
313b78e by Jos van den Oever at 2009-09-12 224
        return v;
225
    }
226
227
    quint16 readuint16() {
228
        checkForLeftOverBits();
229
        quint16 v;
230
        data >> v;
af3349f by Jos van den Oever at 2009-09-12 231
        checkStatus();
313b78e by Jos van den Oever at 2009-09-12 232
        return v;
233
    }
234
235
    quint32 readuint32() {
236
        checkForLeftOverBits();
237
        quint32 v;
238
        data >> v;
af3349f by Jos van den Oever at 2009-09-12 239
        checkStatus();
313b78e by Jos van den Oever at 2009-09-12 240
        return v;
241
    }
242
243
    qint32 readint32() {
244
        checkForLeftOverBits();
245
        qint32 v;
246
        data >> v;
af3349f by Jos van den Oever at 2009-09-12 247
        checkStatus();
313b78e by Jos van den Oever at 2009-09-12 248
        return v;
249
    }
250
e013083 by Jos van den Oever at 2009-09-16 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);
27d538a by Jos van den Oever at 2009-09-16 256
            if (nread == -1 || nread == 0) {
257
                throw EOFException();// TODO: differentiate
258
            }
e013083 by Jos van den Oever at 2009-09-16 259
            todo -= nread;
260
            offset += nread;
261
        }
262
    }
263
27d538a by Jos van den Oever at 2009-09-16 264
    void skip(int len) {
265
        data.skipRawData(len);
266
    }
267
268
    qint64 getPosition() const { return input->pos(); }
55d39fd by Jos van den Oever at 2010-01-22 269
270
    qint64 getMaxPosition() const { return qMax(input->pos(), maxPosition); }
c1d8729 by Jos van den Oever at 2010-09-27 271
    qint64 getSize() const { return input->size(); }
3a5cbea by Jos van den Oever at 2009-08-27 272
};
273
274
#endif