File indexing completed on 2024-12-08 11:06:02

0001 /**
0002  * KDiff3 - Text Diff And Merge Tool
0003  *
0004  * SPDX-FileCopyrightText: 2023 Michael Reeves <reeves.87@gmail.com>
0005  * SPDX-License-Identifier: GPL-2.0-or-later
0006  *
0007  */
0008 
0009 #ifndef ENCODEDDATASTREAM_H
0010 #define ENCODEDDATASTREAM_H
0011 
0012 #include "TypeUtils.h"
0013 
0014 #include <QByteArray>
0015 #include <QDataStream>
0016 #include <QString>
0017 #include <QTextDecoder>
0018 
0019 class EncodedDataStream: public QDataStream
0020 {
0021   private:
0022     QByteArray mEncoding = "UTF-8";
0023     bool mGenerateBOM = false;
0024     bool mError = false;
0025 
0026   public:
0027     using QDataStream::QDataStream;
0028 
0029     void setGenerateByteOrderMark(bool generate) { mGenerateBOM = generate; }
0030 
0031     //Let the compiler choose the optimal solution based on c++ rules.
0032     inline void setEncoding(const QByteArray &inEncoding) noexcept
0033     {
0034         assert(!inEncoding.isEmpty());
0035         if(inEncoding == "UTF-8-BOM")
0036         {
0037             mGenerateBOM = true;
0038             mEncoding = "UTF-8";
0039         }
0040         else
0041             mEncoding = inEncoding;
0042     };
0043 
0044     inline void setEncoding(const QByteArray &&inEncoding) noexcept
0045     {
0046         assert(!inEncoding.isEmpty());
0047         if(inEncoding == "UTF-8-BOM")
0048         {
0049             mGenerateBOM = true;
0050             mEncoding = "UTF-8";
0051         }
0052         else
0053             mEncoding = inEncoding;
0054     };
0055 
0056     inline qint32 readChar(QChar& c)
0057     {
0058         char curByte;
0059         qint32 len = 0;
0060         QString s;
0061 #if(QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
0062         QTextDecoder decoder = QTextDecoder(QTextCodec::codecForName(mEncoding), mGenerateBOM ? QTextCodec::ConversionFlag::DefaultConversion : QTextCodec::ConversionFlag::IgnoreHeader);
0063 #else
0064         QTextDecoder decoder = QTextDecoder(QTextCodec::codecForName(mEncoding), mGenerateBOM ? QStringConverter::Flag::WriteBom : QStringConverter::Flag::ConvertInitialBom);
0065 #endif
0066         do
0067         {
0068             len += readRawData(&curByte, 1);
0069             s = decoder.toUnicode(&curByte, 1);
0070         } while(!decoder.hasFailure() && decoder.needsMoreData() && !atEnd());
0071 
0072         mError = decoder.hasFailure();
0073         if(!mError)
0074             c = s[0];
0075         else
0076             c = QChar::ReplacementCharacter;
0077 
0078         return len;
0079     }
0080 
0081     EncodedDataStream &operator<<(const QString &s)
0082     {
0083 #if(QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
0084         QTextEncoder encoder(QTextCodec::codecForName(mEncoding), mGenerateBOM ? QTextCodec::ConversionFlag::DefaultConversion : QTextCodec::ConversionFlag::IgnoreHeader);
0085 #else
0086         QTextEncoder encoder(QTextCodec::codecForName(mEncoding), mGenerateBOM ? QStringConverter::Flag::WriteBom : QStringConverter::Flag::ConvertInitialBom);
0087 #endif
0088         QByteArray data = encoder.fromUnicode(s);
0089         mError = encoder.hasFailure();
0090 
0091         return *this << data;
0092     };
0093 
0094     inline bool hasError() noexcept { return mError; }
0095 
0096     //Not implemented but may be inherieted from QDataStream
0097     EncodedDataStream &operator<<(const QChar &) = delete;
0098     EncodedDataStream &operator<<(const char *&) = delete;
0099     EncodedDataStream &operator<<(const char &) = delete;
0100 
0101     EncodedDataStream &operator<<(const QByteArray &bytes)
0102     {
0103         writeRawData(bytes.constData(), bytes.length());
0104         return *this;
0105     };
0106 
0107     EncodedDataStream &operator>>(QByteArray &) = delete;
0108     EncodedDataStream &operator>>(QString &) = delete;
0109     EncodedDataStream &operator>>(QChar &) = delete;
0110     EncodedDataStream &operator>>(char *&) = delete;
0111     EncodedDataStream &operator>>(char &) = delete;
0112 };
0113 
0114 #endif /* ENCODEDDATASTREAM_H */