- 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)
This commit is contained in:
Roy Qu 2023-01-14 21:51:55 +08:00
parent d8fae209c6
commit 6072944c23
9 changed files with 120 additions and 24 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -268,6 +268,7 @@ bool Editor::save(bool force, bool doReparse) {
QThread::msleep(200);
}
//is this file writable;
pMainWindow->fileSystemWatcher()->removePath(mFilename);
try {
if (pSettings->editor().autoFormatWhenSaved()) {

View File

@ -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;

View File

@ -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;

View File

@ -148,7 +148,7 @@ CharsetInfoManager::CharsetInfoManager(const QString& localeName):
mCodePages.append(std::make_shared<CharsetInfo>(1147,"IBM01147","","",false));
mCodePages.append(std::make_shared<CharsetInfo>(1148,"IBM01148","","",false));
mCodePages.append(std::make_shared<CharsetInfo>(1149,"IBM01149","","",false));
mCodePages.append(std::make_shared<CharsetInfo>(1200,"utf-16","","",false));
mCodePages.append(std::make_shared<CharsetInfo>(1200,"utf-16",tr("Unicode"),"",true));
mCodePages.append(std::make_shared<CharsetInfo>(1201,"unicodeFFFE","","",false));
mCodePages.append(std::make_shared<CharsetInfo>(1250,"windows-1250",tr("Central Europe"),"",true));
mCodePages.append(std::make_shared<CharsetInfo>(1251,"windows-1251",tr("Cyrillic"),"",true));
@ -176,7 +176,7 @@ CharsetInfoManager::CharsetInfoManager(const QString& localeName):
mCodePages.append(std::make_shared<CharsetInfo>(10079,"x-mac-icelandic","","",false));
mCodePages.append(std::make_shared<CharsetInfo>(10081,"x-mac-turkish","","",false));
mCodePages.append(std::make_shared<CharsetInfo>(10082,"x-mac-croatian","","",false));
mCodePages.append(std::make_shared<CharsetInfo>(12000,"utf-32","","",false));
mCodePages.append(std::make_shared<CharsetInfo>(12000,"utf-32",tr("Unicode"),"",true));
mCodePages.append(std::make_shared<CharsetInfo>(12001,"utf-32BE","","",false));
mCodePages.append(std::make_shared<CharsetInfo>(20000,"x-Chinese_CNS","","",false));
mCodePages.append(std::make_shared<CharsetInfo>(20001,"x-cp20001","","",false));
@ -259,7 +259,7 @@ CharsetInfoManager::CharsetInfoManager(const QString& localeName):
mCodePages.append(std::make_shared<CharsetInfo>(57010,"x-iscii-gu","","",false));
mCodePages.append(std::make_shared<CharsetInfo>(57011,"x-iscii-pa","","",false));
mCodePages.append(std::make_shared<CharsetInfo>(65000,"utf-7","","",false));
mCodePages.append(std::make_shared<CharsetInfo>(65001,"utf-8","","",false));
mCodePages.append(std::make_shared<CharsetInfo>(65001,"utf-8",tr("Unicode"),"",true));
}

View File

@ -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;
}
}

View File

@ -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"