diff --git a/NEWS.md b/NEWS.md index d2352231..b5d23b57 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,8 @@ Red Panda C++ Version 2.9 - enhancement: set caret to the corresponding line in the editor after "run"/"generate assembly" - fix: syntax highlighting for cpp style line comment is not correct. + - fix: Save may crash app if the encoding codec is failed to load. + - enhancement: support open and save utf-16/utf-32 BOM files. (but gcc can't compile) Red Panda C++ Version 2.8 diff --git a/RedPandaIDE/compiler/compiler.cpp b/RedPandaIDE/compiler/compiler.cpp index 8b98f1e4..5a754ae2 100644 --- a/RedPandaIDE/compiler/compiler.cpp +++ b/RedPandaIDE/compiler/compiler.cpp @@ -350,6 +350,10 @@ QString Compiler::getCharsetArgument(const QByteArray& encoding,FileType fileTyp encodingName = systemEncodingName; } else if (encoding == ENCODING_UTF8_BOM) { encodingName = "UTF-8"; + } else if (encoding == ENCODING_UTF16_BOM) { + encodingName = "UTF-16"; + } else if (encoding == ENCODING_UTF32_BOM) { + encodingName = "UTF-32"; } else { encodingName = encoding; } diff --git a/RedPandaIDE/compiler/projectcompiler.cpp b/RedPandaIDE/compiler/projectcompiler.cpp index 6da7b87f..89efba86 100644 --- a/RedPandaIDE/compiler/projectcompiler.cpp +++ b/RedPandaIDE/compiler/projectcompiler.cpp @@ -410,6 +410,10 @@ void ProjectCompiler::writeMakeObjFilesRules(QFile &file) targetEncoding = defaultSystemEncoding; } else if (encoding == ENCODING_UTF8_BOM) { targetEncoding = "UTF-8"; + } else if (encoding == ENCODING_UTF16_BOM) { + targetEncoding = "UTF-16"; + } else if (encoding == ENCODING_UTF32_BOM) { + targetEncoding = "UTF-32"; } else { targetEncoding = encoding; } diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index e44d7167..4cffe659 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -263,11 +263,12 @@ void Editor::convertToEncoding(const QByteArray &encoding) bool Editor::save(bool force, bool doReparse) { if (this->mIsNew && !force) { return saveAs(); - } + } while (pMainWindow->parsing()) { QThread::msleep(200); } //is this file writable; + pMainWindow->fileSystemWatcher()->removePath(mFilename); try { if (pSettings->editor().autoFormatWhenSaved()) { diff --git a/libs/qsynedit/qsynedit/document.cpp b/libs/qsynedit/qsynedit/document.cpp index 9a89a6fc..a072efb9 100644 --- a/libs/qsynedit/qsynedit/document.cpp +++ b/libs/qsynedit/qsynedit/document.cpp @@ -519,6 +519,52 @@ bool Document::tryLoadFileByEncoding(QByteArray encodingName, QFile& file) { return true; } +void Document::loadUTF16BOMFile(QFile &file) +{ + QTextCodec* codec=QTextCodec::codecForName(ENCODING_UTF16); + if (!codec) + return; + file.reset(); + internalClear(); + QByteArray buf = file.readAll(); + if (buf.length()<2) + return; + QString text = codec->toUnicode(buf.mid(2)); + this->setText(text); +} + +void Document::loadUTF32BOMFile(QFile &file) +{ + QTextCodec* codec=QTextCodec::codecForName(ENCODING_UTF32); + if (!codec) + return; + file.reset(); + internalClear(); + QByteArray buf = file.readAll(); + if (buf.length()<4) + return; + QString text = codec->toUnicode(buf.mid(4)); + this->setText(text); +} + +void Document::saveUTF16File(QFile &file) +{ + QString text=getTextStr(); + QTextCodec* codec=QTextCodec::codecForName(ENCODING_UTF16); + if (!codec) + return; + file.write(codec->fromUnicode(text)); +} + +void Document::saveUTF32File(QFile &file) +{ + QString text=getTextStr(); + QTextCodec* codec=QTextCodec::codecForName(ENCODING_UTF32); + if (!codec) + return; + file.write(codec->fromUnicode(text)); +} + const QFontMetrics &Document::fontMetrics() const { return mFontMetrics; @@ -568,10 +614,22 @@ void Document::loadFromFile(const QString& filename, const QByteArray& encoding, realEncoding = ENCODING_UTF8_BOM; line = line.mid(3); codec = QTextCodec::codecForName(ENCODING_UTF8); + } else if ((line.length()>=4) && ((unsigned char)line[0]==0xFF) && ((unsigned char)line[1]==0xFE) + && ((unsigned char)line[2]==0x00) + && ((unsigned char)line[3]==0x00)) { + realEncoding = ENCODING_UTF32_BOM; + loadUTF32BOMFile(file); + return; + } else if ((line.length()>=2) && ((unsigned char)line[0]==0xFF) && ((unsigned char)line[1]==0xFE)) { + realEncoding = ENCODING_UTF16_BOM; + loadUTF16BOMFile(file); + return; } else { realEncoding = ENCODING_UTF8; codec = QTextCodec::codecForName(ENCODING_UTF8); } + if (!codec) + throw FileError(tr("Can't load codec '%1'!").arg(QString(realEncoding))); if (line.endsWith("\r\n")) { mNewlineType = NewlineType::Windows; } else if (line.endsWith("\n")) { @@ -579,6 +637,7 @@ void Document::loadFromFile(const QString& filename, const QByteArray& encoding, } else if (line.endsWith("\r")) { mNewlineType = NewlineType::MacOld; } + internalClear(); while (true) { if (line.endsWith("\r\n")) { @@ -669,37 +728,55 @@ void Document::saveToFile(QFile &file, const QByteArray& encoding, const QByteArray& defaultEncoding, QByteArray& realEncoding) { QMutexLocker locker(&mMutex); + QTextCodec* codec; + realEncoding = encoding; + QString codecName = realEncoding; + if (realEncoding == ENCODING_UTF16_BOM || realEncoding == ENCODING_UTF16) { + codec = QTextCodec::codecForName(ENCODING_UTF16); + codecName = ENCODING_UTF16; + } else if (realEncoding == ENCODING_UTF32_BOM || realEncoding == ENCODING_UTF32) { + codec = QTextCodec::codecForName(ENCODING_UTF32); + codecName = ENCODING_UTF32; + } else if (realEncoding == ENCODING_UTF8_BOM) { + codec = QTextCodec::codecForName(ENCODING_UTF8); + codecName = ENCODING_UTF8; + } else if (realEncoding == ENCODING_SYSTEM_DEFAULT) { + codec = QTextCodec::codecForLocale(); + codecName = realEncoding; + } else if (realEncoding == ENCODING_AUTO_DETECT) { + codec = QTextCodec::codecForName(defaultEncoding); + codecName = defaultEncoding; + } else { + codec = QTextCodec::codecForName(realEncoding); + } + if (!codec) + throw FileError(tr("Can't load codec '%1'!").arg(codecName)); + if (!file.open(QFile::WriteOnly | QFile::Truncate)) throw FileError(tr("Can't open file '%1' for save!").arg(file.fileName())); if (mLines.isEmpty()) return; - QTextCodec* codec; - realEncoding = encoding; - if (realEncoding == ENCODING_UTF8_BOM) { - codec = QTextCodec::codecForName(ENCODING_UTF8); + if (realEncoding == ENCODING_UTF16) { + saveUTF16File(file); + return; + } else if (realEncoding == ENCODING_UTF32) { + saveUTF32File(file); + return; + } if (realEncoding == ENCODING_UTF8_BOM) { file.putChar(0xEF); file.putChar(0xBB); file.putChar(0xBF); - } else if (realEncoding == ENCODING_SYSTEM_DEFAULT) { - codec = QTextCodec::codecForLocale(); - } else if (realEncoding == ENCODING_AUTO_DETECT) { - codec = QTextCodec::codecForName(defaultEncoding); - if (!codec) - codec = QTextCodec::codecForLocale(); - } else { - codec = QTextCodec::codecForName(realEncoding); } bool allAscii = true; + QByteArray data; for (PDocumentLine& line:mLines) { + QString text = line->lineText+lineBreak(); + data = codec->fromUnicode(text); if (allAscii) { - allAscii = isTextAllAscii(line->lineText); + allAscii = (data==text.toLatin1()); } - if (!allAscii) { - file.write(codec->fromUnicode(line->lineText)); - } else { - file.write(line->lineText.toLatin1()); - } - file.write(lineBreak().toLatin1()); + if (file.write(data)!=data.size()) + throw FileError(tr("Data not correctly writed to file '%1'.").arg(file.fileName())); } if (allAscii) { realEncoding = ENCODING_ASCII; diff --git a/libs/qsynedit/qsynedit/document.h b/libs/qsynedit/qsynedit/document.h index f5482892..b1879c42 100644 --- a/libs/qsynedit/qsynedit/document.h +++ b/libs/qsynedit/qsynedit/document.h @@ -134,6 +134,10 @@ protected: void internalClear(); private: bool tryLoadFileByEncoding(QByteArray encodingName, QFile& file); + void loadUTF16BOMFile(QFile& file); + void loadUTF32BOMFile(QFile& file); + void saveUTF16File(QFile& file); + void saveUTF32File(QFile& file); private: DocumentLines mLines; diff --git a/libs/redpanda_qt_utils/qt_utils/charsetinfo.cpp b/libs/redpanda_qt_utils/qt_utils/charsetinfo.cpp index 4c9d1d17..ce37f57d 100644 --- a/libs/redpanda_qt_utils/qt_utils/charsetinfo.cpp +++ b/libs/redpanda_qt_utils/qt_utils/charsetinfo.cpp @@ -148,7 +148,7 @@ CharsetInfoManager::CharsetInfoManager(const QString& localeName): mCodePages.append(std::make_shared(1147,"IBM01147","","",false)); mCodePages.append(std::make_shared(1148,"IBM01148","","",false)); mCodePages.append(std::make_shared(1149,"IBM01149","","",false)); - mCodePages.append(std::make_shared(1200,"utf-16","","",false)); + mCodePages.append(std::make_shared(1200,"utf-16",tr("Unicode"),"",true)); mCodePages.append(std::make_shared(1201,"unicodeFFFE","","",false)); mCodePages.append(std::make_shared(1250,"windows-1250",tr("Central Europe"),"",true)); mCodePages.append(std::make_shared(1251,"windows-1251",tr("Cyrillic"),"",true)); @@ -176,7 +176,7 @@ CharsetInfoManager::CharsetInfoManager(const QString& localeName): mCodePages.append(std::make_shared(10079,"x-mac-icelandic","","",false)); mCodePages.append(std::make_shared(10081,"x-mac-turkish","","",false)); mCodePages.append(std::make_shared(10082,"x-mac-croatian","","",false)); - mCodePages.append(std::make_shared(12000,"utf-32","","",false)); + mCodePages.append(std::make_shared(12000,"utf-32",tr("Unicode"),"",true)); mCodePages.append(std::make_shared(12001,"utf-32BE","","",false)); mCodePages.append(std::make_shared(20000,"x-Chinese_CNS","","",false)); mCodePages.append(std::make_shared(20001,"x-cp20001","","",false)); @@ -259,7 +259,7 @@ CharsetInfoManager::CharsetInfoManager(const QString& localeName): mCodePages.append(std::make_shared(57010,"x-iscii-gu","","",false)); mCodePages.append(std::make_shared(57011,"x-iscii-pa","","",false)); mCodePages.append(std::make_shared(65000,"utf-7","","",false)); - mCodePages.append(std::make_shared(65001,"utf-8","","",false)); + mCodePages.append(std::make_shared(65001,"utf-8",tr("Unicode"),"",true)); } diff --git a/libs/redpanda_qt_utils/qt_utils/utils.cpp b/libs/redpanda_qt_utils/qt_utils/utils.cpp index 1204b7a1..cee0212c 100644 --- a/libs/redpanda_qt_utils/qt_utils/utils.cpp +++ b/libs/redpanda_qt_utils/qt_utils/utils.cpp @@ -114,7 +114,7 @@ const QByteArray guessTextEncoding(const QByteArray& text){ bool isTextAllAscii(const QByteArray& text) { for (char c:text) { - if (c<0) { + if (c<=0) { return false; } } diff --git a/libs/redpanda_qt_utils/qt_utils/utils.h b/libs/redpanda_qt_utils/qt_utils/utils.h index 68d8d370..da8f09a2 100644 --- a/libs/redpanda_qt_utils/qt_utils/utils.h +++ b/libs/redpanda_qt_utils/qt_utils/utils.h @@ -32,7 +32,11 @@ class QTextCodec; #define ENCODING_AUTO_DETECT "AUTO" #define ENCODING_UTF8 "UTF-8" +#define ENCODING_UTF16 "UTF-16" +#define ENCODING_UTF32 "UTF-32" #define ENCODING_UTF8_BOM "UTF-8 BOM" +#define ENCODING_UTF16_BOM "UTF-16 BOM" +#define ENCODING_UTF32_BOM "UTF-32 BOM" #define ENCODING_SYSTEM_DEFAULT "SYSTEM" #define ENCODING_ASCII "ASCII"