diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 567405f5..91c616e3 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -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 diff --git a/app/rcc/messages/Acknowledgements.txt b/app/rcc/messages/Acknowledgements.txt index 91c8b26e..233699d1 100644 --- a/app/rcc/messages/Acknowledgements.txt +++ b/app/rcc/messages/Acknowledgements.txt @@ -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 . +Copyright (c) 2014-2025 Alex Spataru . Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/app/src/IO/Console.cpp b/app/src/IO/Console.cpp index 86261b1d..a417cd64 100644 --- a/app/src/IO/Console.cpp +++ b/app/src/IO/Console.cpp @@ -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(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(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()); } diff --git a/app/src/IO/HexDump.h b/app/src/IO/HexDump.h new file mode 100644 index 00000000..54162406 --- /dev/null +++ b/app/src/IO/HexDump.h @@ -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 +#include +#include + +template +struct CustomHexdump +{ + CustomHexdump(const void *data, unsigned length) + : mData(static_cast(data)) + , mLength(length) + { + } + const unsigned char *mData; + const unsigned mLength; +}; + +template +std::ostream &operator<<(std::ostream &out, + const CustomHexdump &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(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(dump.mData[i + j]); + else + out << "."; + } + } + } + + out << std::endl; + } + + return out; +} + +typedef CustomHexdump<16, true> Hexdump;