BinaryReader.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2006-2007 by Peter Dimov.
00004 
00005 This file is part of Calitko (http://www.calitko.org).
00006 
00007 Calitko is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2 of the License, or
00010 (at your option) any later version.
00011 
00012 Calitko is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Calitko; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021 */
00022 
00023 #include "Qt.h"
00024 #include "BinaryReader.h"
00025 #include <algorithm>
00026 
00027 using Utils::Encodings::BinaryReader;
00028 
00030 
00034 BinaryReader::BinaryReader (const QByteArray &rawData, ByteOrder byteOrder)
00035  :  d()
00036 {
00037     d.rawData       = rawData;
00038     d.readOrigin    = ReadFromStart;
00039     d.dataStart     = d.rawData.data();
00040     d.dataEnd       = d.dataStart + d.rawData.size();
00041     // Make sure d.swapBytes and d.byteOrder are initialized:
00042     setByteOrder (byteOrder);
00043 }
00044 
00046 
00054 void BinaryReader::doRead (char *destination, size_t count)
00055 {
00056     // Only read if enough unread data left:
00057     if (canRead (count)) {
00058         if (const char* start = getRangePtrs (count))
00059             copyBytes (start, start+count, destination);
00060     }
00061     bumpPtrs (count);
00062 }
00063 
00065 
00073 const char* BinaryReader::getRangePtrs (size_t count)
00074 {
00075     Q_ASSERT (canRead (count));
00076     if (d.readOrigin == ReadFromEnd)
00077         return d.dataEnd - count;
00078     else
00079         return d.dataStart;
00080 }
00081 
00083 
00087 void BinaryReader::copyBytes (const char *beg, const char *end, char *dest)
00088 {
00089     if (d.swapBytes)
00090         while (beg != end) *dest++ = *--end;
00091     else
00092         std::copy (beg, end, dest);
00093 }
00094 
00096 
00100 void BinaryReader::bumpPtrs (size_t count)
00101 {
00102     if (d.readOrigin == ReadFromStart)
00103         d.dataStart += count;
00104     else
00105         d.dataEnd -= count;
00106 }
00108 
00118 uchar BinaryReader::lookAhead (const int count)
00119 {
00120     Q_ASSERT (count > 0);
00121     uchar res = 0;
00122     // Only return if the requested data is within the buffer:
00123     if (canRead (count)) {
00124         if (d.readOrigin == ReadFromEnd) {
00125             res = *(d.dataEnd - count);
00126         } else {
00127             res = *(d.dataStart + count - 1);
00128         }
00129     }
00130     return res;
00131 }
00132 
00134 
00136 bool BinaryReader::canRead (const int count)
00137 {
00138     return d.dataStart + count <= d.dataEnd;
00139 }
00140 
00142 
00150 uchar BinaryReader::readByte()
00151 {
00152     uchar res = 0;
00153     doRead (reinterpret_cast <char *> (&res), sizeof (res));
00154     return res;
00155 }
00156 
00158 
00166 quint16 BinaryReader::readUInt16()
00167 {
00168     quint16 res = 0;
00169     doRead (reinterpret_cast <char *> (&res), sizeof (res));
00170     return res;
00171 }
00172 
00174 
00182 quint32 BinaryReader::readUInt32()
00183 {
00184     quint32 res = 0;
00185     doRead (reinterpret_cast <char *> (&res), sizeof (res));
00186     return res;
00187 }
00188 
00190 
00198 quint64 BinaryReader::readUInt64()
00199 {
00200     quint64 res = 0;
00201     doRead (reinterpret_cast <char *> (&res), sizeof (res));
00202     return res;
00203 }
00204 
00206 QByteArray BinaryReader::readAll()
00207 {
00208     if (d.dataEnd <= d.dataStart)
00209         return QByteArray();
00210     else
00211         return readBytes (d.dataEnd - d.dataStart);
00212 }
00213 
00215 
00224 QByteArray BinaryReader::readBytes (size_t count)
00225 {
00226     QByteArray res (count, '\0');
00227     if (canRead(count)) {
00228         const char* start = getRangePtrs (count);
00229         std::copy (start, start+count, res.data());
00230     }
00231     bumpPtrs (count);
00232     return res;
00233 }
00234 
00236 
00260 QByteArray BinaryReader::getSharedBytes (size_t count)
00261 {
00262     QByteArray res;
00263     if (canRead (count)) {
00264         if (d.readOrigin == ReadFromStart)
00265             res = QByteArray::fromRawData (d.dataStart, count);
00266         else
00267             res = QByteArray::fromRawData (d.dataEnd - count, count);
00268     } else {
00269         res = QByteArray (count, '\0');
00270     }
00271     bumpPtrs (count);
00272     return res;
00273 }
00274 
00276 
00290 QByteArray BinaryReader::readString (char terminator)
00291 {
00292     QByteArray res;
00293     if (d.readOrigin == ReadFromStart) {
00294         char *pos = d.dataStart;
00295         while (pos < d.dataEnd && *pos != terminator)
00296             res.append (*pos++); // could potentially throw bad_alloc.
00297         // Eigher a zero, or the end was reached, step past it:
00298         d.dataStart = ++pos;
00299     } else {
00300         char *pos = d.dataEnd;
00301         --pos; // Move on the last byte, don't stay past it.
00302         while (pos >= d.dataStart && *pos != terminator)
00303             res.prepend (*pos--); // could potentially throw bad_alloc.
00304         d.dataEnd = pos;
00305     }
00306     return res;
00307 }
00308 
00310 
00314 void BinaryReader::setByteOrder (ByteOrder byteOrder)
00315 {
00316     d.byteOrder = byteOrder;
00317     if (byteOrder == LittleEndian)
00318         d.swapBytes = QSysInfo::ByteOrder != QSysInfo::LittleEndian;
00319     else if (byteOrder == BigEndian)
00320         d.swapBytes = QSysInfo::ByteOrder != QSysInfo::BigEndian;
00321     else
00322         Q_ASSERT (false);
00323 }
00324 
00326 
00335 void BinaryReader::setReadOrigin (ReadOrigin readOrigin)
00336 {
00337     Q_ASSERT (d.readOrigin == ReadFromStart || d.readOrigin == ReadFromEnd);
00338     d.readOrigin = readOrigin;
00339 }
00340 
00342 
00349 bool BinaryReader::hasReadPastEnd() const
00350 {
00351     return d.dataStart > d.dataEnd;
00352 }
00353 
00355 
00363 bool BinaryReader::hasReadAll() const
00364 {
00365     return d.dataStart >= d.dataEnd;
00366 }