File indexing completed on 2024-12-08 13:30:51
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 <QTextCodec> 0018 #include <QTextDecoder> 0019 0020 class EncodedDataStream: public QDataStream 0021 { 0022 private: 0023 QByteArray mEncoding = "UTF-8"; 0024 bool mGenerateBOM = false; 0025 bool mError = false; 0026 0027 public: 0028 using QDataStream::QDataStream; 0029 0030 void setGenerateByteOrderMark(bool generate) { mGenerateBOM = generate; } 0031 0032 //Let the compiler choose the optimal solution based on c++ rules. 0033 inline void setEncoding(const QByteArray &inEncoding) noexcept 0034 { 0035 assert(!inEncoding.isEmpty()); 0036 if(inEncoding == "UTF-8-BOM") 0037 { 0038 mGenerateBOM = true; 0039 mEncoding = "UTF-8"; 0040 } 0041 else 0042 mEncoding = inEncoding; 0043 }; 0044 0045 inline void setEncoding(const QByteArray &&inEncoding) noexcept 0046 { 0047 assert(!inEncoding.isEmpty()); 0048 if(inEncoding == "UTF-8-BOM") 0049 { 0050 mGenerateBOM = true; 0051 mEncoding = "UTF-8"; 0052 } 0053 else 0054 mEncoding = inEncoding; 0055 }; 0056 0057 inline qint32 readChar(QChar& c) 0058 { 0059 char curByte; 0060 qint32 len = 0; 0061 QString s; 0062 0063 #if(QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) 0064 QTextDecoder decoder = QTextDecoder(QTextCodec::codecForName(mEncoding), mGenerateBOM ? QTextCodec::ConversionFlag::DefaultConversion : QTextCodec::ConversionFlag::IgnoreHeader); 0065 #else 0066 QTextDecoder decoder = QTextDecoder(QTextCodec::codecForName(mEncoding), mGenerateBOM ? QStringConverter::Flag::WriteBom : QStringConverter::Flag::ConvertInitialBom); 0067 #endif 0068 0069 do 0070 { 0071 len += readRawData(&curByte, 1); 0072 s = decoder.toUnicode(&curByte, 1); 0073 } while(!decoder.hasFailure() && decoder.needsMoreData() && !atEnd()); 0074 0075 mError = decoder.hasFailure(); 0076 if(!mError) 0077 c = s[0]; 0078 else 0079 c = QChar::ReplacementCharacter; 0080 0081 return len; 0082 } 0083 0084 EncodedDataStream &operator<<(const QString &s) 0085 { 0086 #if(QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) 0087 QTextEncoder encoder(QTextCodec::codecForName(mEncoding), mGenerateBOM ? QTextCodec::ConversionFlag::DefaultConversion : QTextCodec::ConversionFlag::IgnoreHeader); 0088 #else 0089 QTextEncoder encoder(QTextCodec::codecForName(mEncoding), mGenerateBOM ? QStringConverter::Flag::WriteBom : QStringConverter::Flag::ConvertInitialBom); 0090 #endif 0091 QByteArray data = encoder.fromUnicode(s); 0092 mError = encoder.hasFailure(); 0093 0094 return *this << data; 0095 }; 0096 0097 inline bool hasError() noexcept { return mError; } 0098 0099 //Not implemented but may be inherieted from QDataStream 0100 EncodedDataStream &operator<<(const QChar &) = delete; 0101 EncodedDataStream &operator<<(const char *&) = delete; 0102 EncodedDataStream &operator<<(const char &) = delete; 0103 0104 EncodedDataStream &operator<<(const QByteArray &bytes) 0105 { 0106 writeRawData(bytes.constData(), bytes.length()); 0107 return *this; 0108 }; 0109 0110 EncodedDataStream &operator>>(QByteArray &) = delete; 0111 EncodedDataStream &operator>>(QString &) = delete; 0112 EncodedDataStream &operator>>(QChar &) = delete; 0113 EncodedDataStream &operator>>(char *&) = delete; 0114 EncodedDataStream &operator>>(char &) = delete; 0115 }; 0116 0117 #endif /* ENCODEDDATASTREAM_H */