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 */