mirror of
https://github.com/Serial-Studio/Serial-Studio.git
synced 2025-01-23 11:32:53 +08:00
Add better HexDump & make safe binary-to-UTF8 conversions
This commit is contained in:
parent
9c0f2b6c13
commit
430abb247b
@ -149,6 +149,7 @@ set(HEADERS
|
||||
src/IO/CircularBuffer.h
|
||||
src/IO/FileTransmission.h
|
||||
src/IO/FrameReader.h
|
||||
src/IO/HexDump.h
|
||||
src/JSON/FrameParser.h
|
||||
src/JSON/ProjectModel.h
|
||||
src/JSON/Frame.h
|
||||
|
@ -100,9 +100,37 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
## hexdump
|
||||
|
||||
Copyright (c) 2014, Zac Bergquist
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
## QSimpleUpdater
|
||||
|
||||
Copyright (c) 2014-2021 Alex Spataru <https://aspatru.com>.
|
||||
Copyright (c) 2014-2025 Alex Spataru <https://aspatru.com>.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -24,52 +24,9 @@
|
||||
|
||||
#include "IO/Manager.h"
|
||||
#include "IO/Console.h"
|
||||
#include "IO/HexDump.h"
|
||||
#include "Misc/Translator.h"
|
||||
|
||||
/**
|
||||
* Generates a hexdump of the given data
|
||||
*/
|
||||
static QString HexDump(const char *data, const size_t size)
|
||||
{
|
||||
QString result;
|
||||
char ascii[17];
|
||||
ascii[16] = '\0';
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
char hexBuffer[4];
|
||||
snprintf(hexBuffer, sizeof(hexBuffer), "%02X ",
|
||||
static_cast<quint8>(data[i]));
|
||||
result += hexBuffer;
|
||||
|
||||
if (data[i] >= ' ' && data[i] <= '~')
|
||||
ascii[i % 16] = data[i];
|
||||
else
|
||||
ascii[i % 16] = '.';
|
||||
|
||||
if ((i + 1) % 8 == 0 || i + 1 == size)
|
||||
{
|
||||
result += ' ';
|
||||
if ((i + 1) % 16 == 0)
|
||||
result += QString("| %1 \n").arg(ascii);
|
||||
|
||||
else if (i + 1 == size)
|
||||
{
|
||||
ascii[(i + 1) % 16] = '\0';
|
||||
|
||||
if ((i + 1) % 16 <= 8)
|
||||
result += ' ';
|
||||
for (size_t j = (i + 1) % 16; j < 16; ++j)
|
||||
result += " ";
|
||||
|
||||
result += QString("| %1 \n").arg(ascii);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor function
|
||||
*/
|
||||
@ -516,10 +473,10 @@ void IO::Console::append(const QString &string, const bool addTimestamp)
|
||||
// Process lines
|
||||
while (!tokens.isEmpty())
|
||||
{
|
||||
if (m_isStartingLine)
|
||||
auto token = tokens.first();
|
||||
if (m_isStartingLine && !token.simplified().isEmpty())
|
||||
processedString.append(timestamp);
|
||||
|
||||
auto token = tokens.first();
|
||||
processedString.append(token);
|
||||
m_isStartingLine = (token == QStringLiteral("\n"));
|
||||
tokens.removeFirst();
|
||||
@ -589,16 +546,30 @@ QString IO::Console::dataToString(const QByteArray &data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given @a data into an UTF-8 string
|
||||
* @brief Converts a QByteArray to a QString, preserving printable characters
|
||||
* and line breaks.
|
||||
*
|
||||
* Non-printable characters are replaced with a dot ('.') for readability.
|
||||
*
|
||||
* @param data The QByteArray to convert.
|
||||
* @return QString A human-readable string representation of the input data.
|
||||
*/
|
||||
QString IO::Console::plainTextStr(const QByteArray &data)
|
||||
{
|
||||
QString str = QString::fromUtf8(data);
|
||||
// Filter out non-printable characters, but keep line breaks
|
||||
QByteArray filteredData;
|
||||
filteredData.reserve(data.size());
|
||||
for (int i = 0; i < data.size(); ++i)
|
||||
{
|
||||
unsigned char c = static_cast<unsigned char>(data[i]);
|
||||
if (std::isprint(c) || std::isspace(c) || c == '\r' || c == '\n')
|
||||
filteredData.append(c);
|
||||
else
|
||||
filteredData.append('.');
|
||||
}
|
||||
|
||||
if (str.toUtf8() != data)
|
||||
str = QString::fromLatin1(data);
|
||||
|
||||
return str;
|
||||
// Convert the filtered data to QString using UTF-8 as default
|
||||
return QString::fromUtf8(filteredData);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -606,21 +577,7 @@ QString IO::Console::plainTextStr(const QByteArray &data)
|
||||
*/
|
||||
QString IO::Console::hexadecimalStr(const QByteArray &data)
|
||||
{
|
||||
// Remove line breaks from data
|
||||
QByteArray copy = data;
|
||||
|
||||
// Convert data to string with dump every ~80 chars
|
||||
QString str;
|
||||
const int characters = 80;
|
||||
for (int i = 0; i < copy.length(); i += characters)
|
||||
{
|
||||
QByteArray line;
|
||||
for (int j = 0; j < qMin(characters, copy.length() - i); ++j)
|
||||
line.append(copy.at(i + j));
|
||||
|
||||
str.append(HexDump(line.data(), line.size()));
|
||||
}
|
||||
|
||||
// Return string
|
||||
return str;
|
||||
std::ostringstream oss;
|
||||
oss << Hexdump(data.data(), data.size()) << "\n";
|
||||
return QString::fromStdString(oss.str());
|
||||
}
|
||||
|
89
app/src/IO/HexDump.h
Normal file
89
app/src/IO/HexDump.h
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Zac Bergquist
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cctype>
|
||||
#include <iomanip>
|
||||
#include <ostream>
|
||||
|
||||
template<unsigned RowSize, bool ShowAscii>
|
||||
struct CustomHexdump
|
||||
{
|
||||
CustomHexdump(const void *data, unsigned length)
|
||||
: mData(static_cast<const unsigned char *>(data))
|
||||
, mLength(length)
|
||||
{
|
||||
}
|
||||
const unsigned char *mData;
|
||||
const unsigned mLength;
|
||||
};
|
||||
|
||||
template<unsigned RowSize, bool ShowAscii>
|
||||
std::ostream &operator<<(std::ostream &out,
|
||||
const CustomHexdump<RowSize, ShowAscii> &dump)
|
||||
{
|
||||
out.fill('0');
|
||||
for (int i = 0; i < dump.mLength; i += RowSize)
|
||||
{
|
||||
out << "0x" << std::setw(6) << std::hex << i << ": ";
|
||||
for (int j = 0; j < RowSize; ++j)
|
||||
{
|
||||
if (i + j < dump.mLength)
|
||||
{
|
||||
out << std::hex << std::setw(2) << static_cast<int>(dump.mData[i + j])
|
||||
<< " ";
|
||||
}
|
||||
|
||||
else
|
||||
out << " ";
|
||||
}
|
||||
|
||||
out << " ";
|
||||
if (ShowAscii)
|
||||
{
|
||||
for (int j = 0; j < RowSize; ++j)
|
||||
{
|
||||
if (i + j < dump.mLength)
|
||||
{
|
||||
if (std::isprint(dump.mData[i + j]))
|
||||
out << static_cast<char>(dump.mData[i + j]);
|
||||
else
|
||||
out << ".";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out << std::endl;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
typedef CustomHexdump<16, true> Hexdump;
|
Loading…
x
Reference in New Issue
Block a user