From f410b0f9695aa1f6d6318810130f6d64b23050e1 Mon Sep 17 00:00:00 2001 From: Cr4sh Date: Fri, 23 Dec 2016 01:34:24 +0300 Subject: [PATCH] NE Alpha 37 --- UEFITool/uefitool.cpp | 12 +++++------ UEFITool/uefitool.pro | 5 +++-- UEFITool/uefitool.ui | 11 +++++----- common/ffsparser.cpp | 47 +++++++++++++++++++++++------------------- common/ffsparser.h | 8 +++++-- common/meparser.h | 43 ++++++++++++++++++++++++++++++++++++++ common/nvramparser.cpp | 10 +++++---- common/types.cpp | 6 +++++- common/types.h | 14 ++++++++----- common/ubytearray.h | 2 +- common/ustring.cpp | 2 +- qhexedit2/qhexedit.cpp | 13 ++++++++---- 12 files changed, 121 insertions(+), 52 deletions(-) create mode 100644 common/meparser.h diff --git a/UEFITool/uefitool.cpp b/UEFITool/uefitool.cpp index d1b9895..87ad8a6 100644 --- a/UEFITool/uefitool.cpp +++ b/UEFITool/uefitool.cpp @@ -18,7 +18,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("NE Alpha36")) +version(tr("NE Alpha 37")) { clipboard = QApplication::clipboard(); @@ -128,7 +128,7 @@ void UEFITool::init() ui->menuFileActions->setEnabled(false); ui->menuSectionActions->setEnabled(false); ui->menuStoreActions->setEnabled(false); - ui->menuVariableActions->setEnabled(false); + ui->menuEntryActions->setEnabled(false); ui->menuMessageActions->setEnabled(false); // Create new model ... @@ -182,7 +182,7 @@ void UEFITool::populateUi(const QModelIndex ¤t) ui->menuVolumeActions->setEnabled(type == Types::Volume); ui->menuFileActions->setEnabled(type == Types::File); ui->menuSectionActions->setEnabled(type == Types::Section); - ui->menuVariableActions->setEnabled(type == Types::NvarEntry + ui->menuEntryActions->setEnabled(type == Types::NvarEntry || type == Types::VssEntry || type == Types::FsysEntry || type == Types::EvsaEntry @@ -997,7 +997,7 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event) case Types::VssEntry: case Types::FsysEntry: case Types::EvsaEntry: - case Types::FlashMapEntry: ui->menuVariableActions->exec(event->globalPos()); break; + case Types::FlashMapEntry: ui->menuEntryActions->exec(event->globalPos()); break; case Types::VssStore: case Types::FdcStore: case Types::FsysStore: @@ -1057,7 +1057,7 @@ void UEFITool::showFitTable() // Set up the FIT table ui->fitTableWidget->clear(); - ui->fitTableWidget->setRowCount(fitTable.size()); + ui->fitTableWidget->setRowCount((int)fitTable.size()); ui->fitTableWidget->setColumnCount(6); ui->fitTableWidget->setHorizontalHeaderLabels(QStringList() << tr("Address") << tr("Size") << tr("Version") << tr("Checksum") << tr("Type") << tr("Information")); ui->fitTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); @@ -1070,7 +1070,7 @@ void UEFITool::showFitTable() for (UINT8 j = 0; j < 6; j++) { QTableWidgetItem* item = new QTableWidgetItem(fitTable[i].first[j]); item->setData(Qt::UserRole, fitTable[i].second); - ui->fitTableWidget->setItem(i, j, item); + ui->fitTableWidget->setItem((int)i, j, item); } } diff --git a/UEFITool/uefitool.pro b/UEFITool/uefitool.pro index 34e23e3..fdc63e2 100644 --- a/UEFITool/uefitool.pro +++ b/UEFITool/uefitool.pro @@ -8,10 +8,12 @@ DEFINES += "U_ENABLE_NVRAM_PARSING_SUPPORT" HEADERS += uefitool.h \ searchdialog.h \ hexviewdialog.h \ + gotooffsetdialog.h \ guidlineedit.h \ ffsfinder.h \ ../common/nvram.h \ ../common/nvramparser.h \ + ../common/meparser.h \ ../common/ffsops.h \ ../common/basetypes.h \ ../common/descriptor.h \ @@ -35,8 +37,7 @@ HEADERS += uefitool.h \ ../common/ubytearray.h \ ../qhexedit2/qhexedit.h \ ../qhexedit2/chunks.h \ - ../qhexedit2/commands.h \ - gotooffsetdialog.h + ../qhexedit2/commands.h SOURCES += uefitool_main.cpp \ uefitool.cpp \ diff --git a/UEFITool/uefitool.ui b/UEFITool/uefitool.ui index c8daf82..732f1dc 100644 --- a/UEFITool/uefitool.ui +++ b/UEFITool/uefitool.ui @@ -272,8 +272,8 @@ 0 0 - 851 - 21 + 850 + 22 @@ -428,12 +428,12 @@ - + false - Variable + Entry @@ -485,8 +485,9 @@ + - + diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp index 469bb82..1ba9264 100644 --- a/common/ffsparser.cpp +++ b/common/ffsparser.cpp @@ -14,7 +14,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include -#include +#include #include #include "descriptor.h" @@ -49,7 +49,7 @@ USTATUS FfsParser::parse(const UByteArray & buffer) if (lastVtf.isValid()) result = performSecondPass(root); else - msg(("parse: not a single Volume Top File is found, the image may be corrupted")); + msg(UString("parse: not a single Volume Top File is found, the image may be corrupted")); return result; } @@ -298,7 +298,7 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l // Check for Gigabyte specific descriptor map if (bios.length == (UINT32)intelImage.size()) { if (!me.offset) { - msg(("parseIntelImage: can't determine BIOS region start from Gigabyte-specific descriptor")); + msg(UString("parseIntelImage: can't determine BIOS region start from Gigabyte-specific descriptor")); return U_INVALID_FLASH_DESCRIPTOR; } // Use ME region end as BIOS region offset @@ -314,7 +314,7 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l regions.push_back(bios); } else { - msg(("parseIntelImage: descriptor parsing failed, BIOS region not found in descriptor")); + msg(UString("parseIntelImage: descriptor parsing failed, BIOS region not found in descriptor")); return U_INVALID_FLASH_DESCRIPTOR; } @@ -432,9 +432,9 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l for (size_t i = 1; i < regions.size(); i++) { UINT32 previousRegionEnd = regions[i-1].offset + regions[i-1].length; // Check that current region is fully present in the image - if (regions[i].offset + regions[i].length > (UINT32)intelImage.size()) { + if ((UINT64)regions[i].offset + (UINT64)regions[i].length > (UINT64)intelImage.size()) { msg(UString("parseIntelImage: ") + itemSubtypeToUString(Types::Region, regions[i].type) - + UString(" region is located outside of opened image, if your system uses dual-chip storage, please append another part to the opened image"), + + UString(" region is located outside of the opened image. If your system uses dual-chip storage, please append another part to the opened image"), index); return U_TRUNCATED_IMAGE; } @@ -453,12 +453,12 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l region.data = intelImage.mid(region.offset, region.length); region.type = getPaddingType(region.data); std::vector::iterator iter = regions.begin(); - std::advance(iter, i - 1); + std::advance(iter, i); regions.insert(iter, region); } } // Check for padding after the last region - if (regions.back().offset + regions.back().length < (UINT32)intelImage.size()) { + if ((UINT64)regions.back().offset + (UINT64)regions.back().length < (UINT64)intelImage.size()) { region.offset = regions.back().offset + regions.back().length; region.length = intelImage.size() - region.offset; region.data = intelImage.mid(region.offset, region.length); @@ -609,7 +609,7 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l result = U_SUCCESS; } break; default: - msg(("parseIntelImage: region of unknown type found"), index); + msg(UString("parseIntelImage: region of unknown type found"), index); result = U_INVALID_FLASH_DESCRIPTOR; } // Store the first failed result as a final result @@ -702,6 +702,9 @@ USTATUS FfsParser::parseMeRegion(const UByteArray & me, const UINT32 localOffset else if (!versionFound) { msg(UString("parseMeRegion: ME version is unknown, it can be damaged"), index); } + else { + meParser.parseMeRegionBody(index); + } return U_SUCCESS; } @@ -1020,8 +1023,8 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc UByteArray header = volume.left(headerSize); UByteArray body = volume.mid(headerSize); UString name = guidToUString(volumeHeader->FileSystemGuid); - UString info = usprintf("Signature: _FVH\nZeroVector:\n%02X %02X %02X %02X %02X %02X %02X %02X\n" - "%02X %02X %02X %02X %02X %02X %02X %02X\nFileSystem GUID: ", + UString info = usprintf("ZeroVector:\n%02X %02X %02X %02X %02X %02X %02X %02X\n" + "%02X %02X %02X %02X %02X %02X %02X %02X\nSignature: _FVH\nFileSystem GUID: ", volumeHeader->ZeroVector[0], volumeHeader->ZeroVector[1], volumeHeader->ZeroVector[2], volumeHeader->ZeroVector[3], volumeHeader->ZeroVector[4], volumeHeader->ZeroVector[5], volumeHeader->ZeroVector[6], volumeHeader->ZeroVector[7], volumeHeader->ZeroVector[8], volumeHeader->ZeroVector[9], volumeHeader->ZeroVector[10], volumeHeader->ZeroVector[11], @@ -1618,7 +1621,7 @@ USTATUS FfsParser::parsePadFileBody(const UModelIndex & index) UString info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size()); // Add tree item - UModelIndex dataIndex = model->addItem(model->offset(index) + nonEmptyByteOffset, Types::Padding, Subtypes::DataPadding, UString("Non-UEFI data"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); + UModelIndex dataIndex = model->addItem(model->offset(index) + model->header(index).size() + nonEmptyByteOffset, Types::Padding, Subtypes::DataPadding, UString("Non-UEFI data"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); // Show message msg(UString("parsePadFileBody: non-UEFI data found in pad-file"), dataIndex); @@ -2387,7 +2390,6 @@ USTATUS FfsParser::parseGuidedSectionBody(const UModelIndex & index) if (baGuid == EFI_GUIDED_SECTION_TIANO) { USTATUS result = decompress(model->body(index), EFI_STANDARD_COMPRESSION, algorithm, processed, efiDecompressed); if (result) { - parseCurrentSection = false; msg(UString("parseGuidedSectionBody: decompression failed with error ") + errorCodeToUString(result), index); return U_SUCCESS; } @@ -2416,7 +2418,6 @@ USTATUS FfsParser::parseGuidedSectionBody(const UModelIndex & index) else if (baGuid == EFI_GUIDED_SECTION_LZMA || baGuid == EFI_GUIDED_SECTION_LZMAF86) { USTATUS result = decompress(model->body(index), EFI_CUSTOMIZED_COMPRESSION, algorithm, processed, efiDecompressed); if (result) { - parseCurrentSection = false; msg(UString("parseGuidedSectionBody: decompression failed with error ") + errorCodeToUString(result), index); return U_SUCCESS; } @@ -2764,7 +2765,7 @@ USTATUS FfsParser::parseTeImageSectionBody(const UModelIndex & index) // Get section body UByteArray body = model->body(index); if ((UINT32)body.size() < sizeof(EFI_IMAGE_TE_HEADER)) { - msg(("parsePeImageSectionBody: section body size is smaller than TE header size"), index); + msg(UString("parsePeImageSectionBody: section body size is smaller than TE header size"), index); return U_SUCCESS; } @@ -2878,6 +2879,7 @@ USTATUS FfsParser::parseFit(const UModelIndex & index, const UINT32 diff) // Calculate FIT entry checksum UByteArray tempFIT = model->body(fitIndex).mid(fitOffset, fitSize); FIT_ENTRY* tempFitHeader = (FIT_ENTRY*)tempFIT.data(); + tempFitHeader->Type &= 0x7F; // Remove ChecksumValid bit before calculating the checksum tempFitHeader->Checksum = 0; UINT8 calculated = calculateChecksum8((const UINT8*)tempFitHeader, fitSize); if (calculated != fitHeader->Checksum) { @@ -2887,9 +2889,8 @@ USTATUS FfsParser::parseFit(const UModelIndex & index, const UINT32 diff) // Check fit header type if ((fitHeader->Type & 0x7F) != FIT_TYPE_HEADER) - msg(("Invalid FIT header type"), fitIndex); + msg(UString("Invalid FIT header type"), fitIndex); - // Add FIT header std::vector currentStrings; currentStrings.push_back(UString("_FIT_ ")); @@ -2902,11 +2903,10 @@ USTATUS FfsParser::parseFit(const UModelIndex & index, const UINT32 diff) // Process all other entries bool msgModifiedImageMayNotWork = false; - UModelIndex itemIndex; - UString info; for (UINT32 i = 1; i < fitHeader->Size; i++) { currentStrings.clear(); - info.clear(); + UString info; + UModelIndex itemIndex; const FIT_ENTRY* currentEntry = fitHeader + i; UINT32 currentEntrySize = currentEntry->Size; @@ -2922,7 +2922,7 @@ USTATUS FfsParser::parseFit(const UModelIndex & index, const UINT32 diff) case FIT_TYPE_MICROCODE: { //TODO: refactor into function with error reporting if (currentEntry->Address > diff && currentEntry->Address < 0xFFFFFFFFUL) { - UINT32 offset = currentEntry->Address - diff; + UINT32 offset = (UINT32)currentEntry->Address - diff; UModelIndex mcIndex = model->findByOffset(offset); UByteArray mcFile = model->header(mcIndex) + model->body(mcIndex) + model->tail(mcIndex); @@ -2961,6 +2961,11 @@ USTATUS FfsParser::parseFit(const UModelIndex & index, const UINT32 diff) case FIT_TYPE_AC_KEY_MANIFEST: case FIT_TYPE_AC_BOOT_POLICY: default: + if (currentEntry->Address > diff && currentEntry->Address < 0xFFFFFFFFUL) { + UINT32 offset = (UINT32)currentEntry->Address - diff; + itemIndex = model->findByOffset(offset); + } + msgModifiedImageMayNotWork = true; break; } diff --git a/common/ffsparser.h b/common/ffsparser.h index eeb8de4..2d87350 100644 --- a/common/ffsparser.h +++ b/common/ffsparser.h @@ -20,18 +20,21 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "ubytearray.h" #include "treemodel.h" #include "nvramparser.h" +#include "meparser.h" class FfsParser { public: // Default constructor and destructor - FfsParser(TreeModel* treeModel) : model(treeModel), nvramParser(treeModel), capsuleOffsetFixup(0) {} + FfsParser(TreeModel* treeModel) : model(treeModel), nvramParser(treeModel), meParser(treeModel), capsuleOffsetFixup(0) {} ~FfsParser() {} // Returns messages std::vector > getMessages() const { + std::vector > meVector = meParser.getMessages(); std::vector > nvramVector = nvramParser.getMessages(); std::vector > resultVector = messagesVector; + resultVector.insert(resultVector.end(), meVector.begin(), meVector.end()); resultVector.insert(resultVector.end(), nvramVector.begin(), nvramVector.end()); return resultVector; } @@ -52,7 +55,8 @@ private: messagesVector.push_back(std::pair(message, index)); }; - NvramParser nvramParser; + NvramParser nvramParser; + MeParser meParser; UModelIndex lastVtf; UINT32 capsuleOffsetFixup; diff --git a/common/meparser.h b/common/meparser.h new file mode 100644 index 0000000..45b66dd --- /dev/null +++ b/common/meparser.h @@ -0,0 +1,43 @@ +/* meparser.h + +Copyright (c) 2016, Nikolaj Schlej. All rights reserved. + +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +*/ + +#ifndef MEPARSER_H +#define MEPARSER_H + +#include + +#include "basetypes.h" +#include "ustring.h" +#include "ubytearray.h" +#include "treemodel.h" +#include "me.h" + +// TODO: implement ME region parser + +class MeParser +{ +public: + // Default constructor and destructor + MeParser(TreeModel* treeModel) { U_UNUSED_PARAMETER(treeModel); } + ~MeParser() {} + + // Returns messages + std::vector > getMessages() const { return std::vector >(); } + // Clears messages + void clearMessages() {} + + // ME parsing + USTATUS parseMeRegionBody(const UModelIndex & index) { U_UNUSED_PARAMETER(index); return U_SUCCESS; } +}; +#endif // MEPARSER_H diff --git a/common/nvramparser.cpp b/common/nvramparser.cpp index 1a9a6cc..0ac09b6 100644 --- a/common/nvramparser.cpp +++ b/common/nvramparser.cpp @@ -1468,7 +1468,10 @@ USTATUS NvramParser::parseFsysStoreBody(const UModelIndex & index) UINT32 variableSize = 0; // Get nameSize and name of the variable - const UINT8 nameSize = *(UINT8*)(data.constData() + offset); + UINT8 nameSize = *(UINT8*)(data.constData() + offset); + bool valid = !(nameSize & 0x80); // Last bit is a validity bit, 0 means valid + nameSize &= 0x7F; + // Check sanity if (unparsedSize >= nameSize + sizeof(UINT8)) { variableSize = nameSize + sizeof(UINT8); @@ -1484,11 +1487,10 @@ USTATUS NvramParser::parseFsysStoreBody(const UModelIndex & index) UString info = usprintf("Full size: %Xh (%u)", header.size(), header.size()); // Add EOF tree item - model->addItem(localOffset + offset, Types::FsysEntry, 0, UString("EOF"), UString(), info, header, UByteArray(), UByteArray(), Fixed, index); + model->addItem(localOffset + offset, Types::FsysEntry, Subtypes::NormalFsysEntry, UString("EOF"), UString(), info, header, UByteArray(), UByteArray(), Fixed, index); // Add free space offset += header.size(); - unparsedSize = dataSize - offset; UByteArray body = data.mid(offset); info = usprintf("Full size: %Xh (%u)", body.size(), body.size()); @@ -1529,7 +1531,7 @@ USTATUS NvramParser::parseFsysStoreBody(const UModelIndex & index) body.size(), body.size()); // Add tree item - model->addItem(localOffset + offset, Types::FsysEntry, 0, UString(name.constData()), UString(), info, header, body, UByteArray(), Movable, index); + model->addItem(localOffset + offset, Types::FsysEntry, valid ? Subtypes::NormalFsysEntry : Subtypes::InvalidFsysEntry, UString(name.constData()), UString(), info, header, body, UByteArray(), Movable, index); // Move to next variable offset += variableSize; diff --git a/common/types.cpp b/common/types.cpp index d56efe0..d856509 100644 --- a/common/types.cpp +++ b/common/types.cpp @@ -10,6 +10,7 @@ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. */ +#include "ustring.h" #include "types.h" #include "ffs.h" #include "fit.h" @@ -75,7 +76,6 @@ UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype) case Types::FtwStore: case Types::FlashMapStore: case Types::CmdbStore: - case Types::FsysEntry: case Types::SlicData: return UString(); case Types::Image: if (subtype == Subtypes::IntelImage) return UString("Intel"); @@ -114,6 +114,10 @@ UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype) if (subtype == Subtypes::AppleVssEntry) return UString("Apple"); if (subtype == Subtypes::AuthVssEntry) return UString("Auth"); break; + case Types::FsysEntry: + if (subtype == Subtypes::InvalidFsysEntry) return UString("Invalid"); + if (subtype == Subtypes::NormalFsysEntry) return UString("Normal"); + break; case Types::EvsaEntry: if (subtype == Subtypes::InvalidEvsaEntry) return UString("Invalid"); if (subtype == Subtypes::UnknownEvsaEntry) return UString("Unknown"); diff --git a/common/types.h b/common/types.h index a998014..0884890 100644 --- a/common/types.h +++ b/common/types.h @@ -15,7 +15,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define TYPES_H #include "basetypes.h" -#include "ustring.h" // Actions namespace Actions @@ -115,8 +114,13 @@ namespace Subtypes { AuthVssEntry }; + enum FsysEntrySubtypes { + InvalidFsysEntry = 150, + NormalFsysEntry + }; + enum EvsaEntrySubtypes { - InvalidEvsaEntry = 150, + InvalidEvsaEntry = 160, UnknownEvsaEntry, GuidEvsaEntry, NameEvsaEntry, @@ -124,17 +128,17 @@ namespace Subtypes { }; enum FlashMapEntrySubtypes { - VolumeFlashMapEntry = 160, + VolumeFlashMapEntry = 170, DataFlashMapEntry }; enum MicrocodeSubtypes { - IntelMicrocode = 170, + IntelMicrocode = 180, AmdMicrocode }; enum SlicDataSubtypes { - PubkeySlicData = 180, + PubkeySlicData = 190, MarkerSlicData }; } diff --git a/common/ubytearray.h b/common/ubytearray.h index 1fa1e75..531f4a5 100644 --- a/common/ubytearray.h +++ b/common/ubytearray.h @@ -19,7 +19,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define UByteArray QByteArray #else // Use own implementation -#include +#include #include #include #include diff --git a/common/ustring.cpp b/common/ustring.cpp index 4f15701..6591d26 100644 --- a/common/ustring.cpp +++ b/common/ustring.cpp @@ -11,7 +11,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. */ #include "ustring.h" -#include +#include #if defined(QT_CORE_LIB) UString usprintf(const char* fmt, ...) diff --git a/qhexedit2/qhexedit.cpp b/qhexedit2/qhexedit.cpp index 43e7f54..2b95356 100644 --- a/qhexedit2/qhexedit.cpp +++ b/qhexedit2/qhexedit.cpp @@ -519,7 +519,7 @@ void QHexEdit::keyPressEvent(QKeyEvent *event) { /* Hex input */ int key = int(event->text()[0].toLatin1()); - if ((key>='0' && key<='9') || (key>='a' && key <= 'f')) + if ((key >= '0' && key <= '9') || (key >= 'a' && key <= 'f') || (key >= 'A' && key <= 'F')) { if (getSelectionBegin() != getSelectionEnd()) { @@ -828,10 +828,15 @@ void QHexEdit::paintEvent(QPaintEvent *event) } // paint cursor - if (_blink && !_readOnly && hasFocus()) + if (_blink && !_readOnly && hasFocus()) { painter.fillRect(_cursorRect, this->palette().color(QPalette::WindowText)); - else - painter.drawText(_pxCursorX, _pxCursorY, _hexDataShown.mid(_cursorPosition - _bPosFirst * 2, 1)); + } + else { + QByteArray dataShown = _hexDataShown.mid(_cursorPosition - _bPosFirst * 2, 1); + if (_upperCase) + dataShown = dataShown.toUpper(); + painter.drawText(_pxCursorX, _pxCursorY, dataShown); + } // emit event, if size has changed if (_lastEventSize != _chunks->size())