diff --git a/UEFIFind/uefifind.cpp b/UEFIFind/uefifind.cpp
index 5b2d848..25e40f6 100644
--- a/UEFIFind/uefifind.cpp
+++ b/UEFIFind/uefifind.cpp
@@ -92,7 +92,7 @@ USTATUS UEFIFind::findFileRecursive(const UModelIndex index, const UString & hex
 
     // For patterns that cross header|body boundary, skip patterns entirely located in body, since
     // children search above has already found them.
-    if (hasChildren && mode == SEARCH_MODE_ALL && offset >= model->header(index).size()) {
+    if (hasChildren && mode == SEARCH_MODE_ALL && offset >= model->headerSize(index)) {
         offset = -1;
     }
 
diff --git a/UEFITool/QHexView/src/qhexview.cpp b/UEFITool/QHexView/src/qhexview.cpp
index e9a35da..af74167 100644
--- a/UEFITool/QHexView/src/qhexview.cpp
+++ b/UEFITool/QHexView/src/qhexview.cpp
@@ -788,6 +788,7 @@ void QHexView::drawDocument(QTextCursor& c) const {
         else if(m_options.linebackground.isValid() && !(line % 2))
             bf.setBackground(m_options.linebackground);
 
+        bf.setLineHeight(this->lineHeight(), QTextBlockFormat::FixedHeight);
         c.setBlockFormat(bf);
         c.insertBlock({});
         if(m_hexdocument->isEmpty())
diff --git a/UEFITool/ffsfinder.cpp b/UEFITool/ffsfinder.cpp
index 51a2f0e..963ba67 100644
--- a/UEFITool/ffsfinder.cpp
+++ b/UEFITool/ffsfinder.cpp
@@ -12,6 +12,7 @@
  */
 
 #include "ffsfinder.h"
+#include "../common/utility.h"
 
 #if QT_VERSION_MAJOR >= 6
 #include <QRegularExpression>
@@ -36,7 +37,8 @@ USTATUS FfsFinder::findHexPattern(const UModelIndex & index, const UByteArray &
         return U_INVALID_PARAMETER;
     
     // Check for "all substrings" pattern
-    if (hexPattern.count('.') == hexPattern.length())
+    auto c = checkSingle(hexPattern);
+    if (c == '.')
         return U_SUCCESS;
     
     USTATUS ret = U_ITEM_NOT_FOUND;
@@ -78,7 +80,7 @@ USTATUS FfsFinder::findHexPattern(const UModelIndex & index, const UByteArray &
         if (offset % 2 == 0) {
             // For patterns that cross header|body boundary, skip patterns entirely located in body, since
             // children search above has already found them.
-            if (!(hasChildren && mode == SEARCH_MODE_ALL && offset/2 >= model->header(index).size())) {
+            if (!(hasChildren && mode == SEARCH_MODE_ALL && offset/2 >= model->headerSize(index))) {
                 UModelIndex parentFileIndex = model->findParentOfType(index, Types::File);
                 UString name = model->name(index);
                 if (model->parent(index) == parentFileIndex) {
@@ -165,7 +167,8 @@ USTATUS FfsFinder::findGuidPattern(const UModelIndex & index, const UByteArray &
     hexPattern.append(list.at(3)).append(list.at(4));
 
     // Check for "all substrings" pattern
-    if (hexPattern.count('.') == hexPattern.length())
+    auto c = checkSingle(hexPattern);
+    if (c == '.')
         return U_SUCCESS;
 
 #if QT_VERSION_MAJOR >= 6
diff --git a/UEFITool/uefitool.cpp b/UEFITool/uefitool.cpp
index f1b19b3..9f18a8e 100644
--- a/UEFITool/uefitool.cpp
+++ b/UEFITool/uefitool.cpp
@@ -23,12 +23,22 @@ UEFITool::UEFITool(QWidget *parent) :
 QMainWindow(parent),
 ui(new Ui::UEFITool),
 version(tr(PROGRAM_VERSION)),
-markingEnabled(true)
+changedFileFlag(false),
+markingEnabled(true),
+cStyleHexEnabled(true)
 {
     clipboard = QApplication::clipboard();
     
     // Create UI
     ui->setupUi(this);
+    openedFileLabel.setToolButtonStyle(Qt::ToolButtonTextOnly);
+    openedFileLabel.setStyleSheet("QToolButton { border: none; background-color: transparent; }");
+    openedFileLabel.setFocusPolicy(Qt::NoFocus);
+    ui->statusBar->addPermanentWidget(&openedFileLabel);
+    QFont font = ui->statusBar->font();
+    font.setBold(true);
+    openedFileLabel.setFont(font);
+    connect(&openedFileLabel, SIGNAL(clicked()), this, SLOT(fileChangedResume()));
     searchDialog = new SearchDialog(this);
     hexViewDialog = new HexViewDialog(this);
     goToAddressDialog = new GoToAddressDialog(this);
@@ -73,7 +83,10 @@ markingEnabled(true)
     connect(ui->actionExportDiscoveredGuids, SIGNAL(triggered()), this, SLOT(exportDiscoveredGuids()));
     connect(ui->actionGenerateReport, SIGNAL(triggered()), this, SLOT(generateReport()));
     connect(ui->actionToggleBootGuardMarking, SIGNAL(toggled(bool)), this, SLOT(toggleBootGuardMarking(bool)));
+    connect(ui->actionToggleCStyleHexValues, SIGNAL(toggled(bool)), this, SLOT(toggleCStyleHexValues(bool)));
+    connect(ui->actionExpandAll, SIGNAL(triggered()), this, SLOT(expandTree()));
     connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(writeSettings()));
+    connect(&watcher, SIGNAL(fileChanged(QString)), this, SLOT(fileChanged(QString)));
     
     // Enable Drag-and-Drop actions
     setAcceptDrops(true);
@@ -92,6 +105,24 @@ markingEnabled(true)
     
     // Read stored settings
     readSettings();
+
+    // Update recent files list in menu
+    updateRecentFilesMenu();
+
+    // Create a QActionGroup
+    QActionGroup* actionGroup = new QActionGroup(this);
+    actionGroup->setExclusive(true); // Ensure only one action is checked at a time
+    // Add actions from the menu to the QActionGroup
+    ui->actionTrackAndIgnore->setData(TRACK_IGNORE);
+    ui->actionTrackAndIgnore->setChecked(ui->actionTrackAndIgnore->data() == fileTrackingState);
+    actionGroup->addAction(ui->actionTrackAndIgnore);
+    ui->actionTrackAndAsk->setData(TRACK_ASK);
+    ui->actionTrackAndAsk->setChecked(ui->actionTrackAndAsk->data() == fileTrackingState);
+    actionGroup->addAction(ui->actionTrackAndAsk);
+    ui->actionTrackAndReopen->setData(TRACK_REOPEN);
+    ui->actionTrackAndReopen->setChecked(ui->actionTrackAndReopen->data() == fileTrackingState);
+    actionGroup->addAction(ui->actionTrackAndReopen);
+    connect(actionGroup, SIGNAL(triggered(QAction*)), this, SLOT(onTrackingAction(QAction*)));
 }
 
 UEFITool::~UEFITool()
@@ -125,6 +156,9 @@ void UEFITool::init()
     // Set window title
     setWindowTitle(tr("UEFITool %1").arg(version));
     
+    // Some font hint
+    setFont(ui->infoEdit->font());
+
     // Disable menus
     ui->actionSearch->setEnabled(false);
     ui->actionGoToBase->setEnabled(false);
@@ -139,6 +173,7 @@ void UEFITool::init()
     ui->menuStoreActions->setEnabled(false);
     ui->menuEntryActions->setEnabled(false);
     ui->menuMessageActions->setEnabled(false);
+    ui->actionExpandAll->setEnabled(false);
     
     // Create new model ...
     delete model;
@@ -152,11 +187,17 @@ void UEFITool::init()
     model->setMarkingEnabled(markingEnabled);
     ui->actionToggleBootGuardMarking->setChecked(markingEnabled);
     
+    // Set proper C-Style hex values view state
+    model->setCStyleHexEnabled(cStyleHexEnabled);
+    ui->actionToggleCStyleHexValues->setChecked(cStyleHexEnabled);
+    
     // Connect signals to slots
     connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
             this, SLOT(populateUi(const QModelIndex &)));
     connect(ui->structureTreeView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
             this, SLOT(populateUi(const QItemSelection &)));
+    connect(ui->structureTreeView,         SIGNAL(expanded(const QModelIndex &)),       this, SLOT(setExpandAll()));
+    connect(ui->structureTreeView,         SIGNAL(collapsed(const QModelIndex&)),       this, SLOT(setExpandAll()));
     connect(ui->parserMessagesListWidget,  SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(scrollTreeView(QListWidgetItem*)));
     connect(ui->parserMessagesListWidget,  SIGNAL(itemEntered(QListWidgetItem*)),       this, SLOT(enableMessagesCopyActions(QListWidgetItem*)));
     connect(ui->finderMessagesListWidget,  SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(scrollTreeView(QListWidgetItem*)));
@@ -211,6 +252,38 @@ void UEFITool::updateUiForNewColorScheme(Qt::ColorScheme scheme)
 }
 #endif
 
+void UEFITool::updateRecentFilesMenu(const QString& fileName)
+{
+    // Update list
+    if (!fileName.isEmpty()) {
+        recentFiles.removeAll(fileName);
+        recentFiles.prepend(fileName);
+        while (recentFiles.size() > 21) {
+            recentFiles.removeLast();
+        }
+    }
+
+    // Delete old actions
+    for (QAction* action : recentFileActions) {
+        ui->menuFile->removeAction(action);
+        delete action;
+    }
+    recentFileActions.clear();
+
+    if (!recentFiles.isEmpty()) {
+        // Insert new actions before "Quit"
+        for (const QString& path : recentFiles) {
+            QAction* action = new QAction(QDir::toNativeSeparators(path), this);
+            connect(action, SIGNAL(triggered()), this, SLOT(openRecentImageFile()));
+            action->setData(path);
+            ui->menuFile->insertAction(ui->actionQuit, action);
+            recentFileActions.append(action);
+        }
+        // Finally, insert a separator after the list and before "Quit"
+        recentFileActions.append(ui->menuFile->insertSeparator(ui->actionQuit));
+    }
+}
+
 void UEFITool::populateUi(const QItemSelection &selected)
 {
     if (selected.isEmpty()) {
@@ -235,7 +308,10 @@ void UEFITool::populateUi(const QModelIndex &current)
     
     // Enable menus
     ui->menuCapsuleActions->setEnabled(type == Types::Capsule);
-    ui->menuImageActions->setEnabled(type == Types::Image);
+    ui->menuImageActions->setEnabled(type == Types::Image
+                                     || (type == Types::Volume && model->hasEmptyHeader(current))
+                                     || type == Types::FreeSpace
+                                     );
     ui->menuRegionActions->setEnabled(type == Types::Region);
     ui->menuPaddingActions->setEnabled(type == Types::Padding);
     ui->menuVolumeActions->setEnabled(type == Types::Volume);
@@ -300,6 +376,8 @@ void UEFITool::populateUi(const QModelIndex &current)
     //ui->actionReplaceBody->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section);
     
     ui->menuMessageActions->setEnabled(false);
+
+    setExpandAll();
 }
 
 void UEFITool::search()
@@ -310,7 +388,7 @@ void UEFITool::search()
     int index = searchDialog->ui->tabWidget->currentIndex();
     if (index == 0) { // Hex pattern
         searchDialog->ui->hexEdit->setFocus();
-        QByteArray pattern = searchDialog->ui->hexEdit->text().toLatin1().replace(" ", "");
+        UByteArray pattern = searchDialog->ui->hexEdit->text().toLatin1().replace(" ", "");
         if (pattern.isEmpty())
             return;
         UINT8 mode;
@@ -326,7 +404,7 @@ void UEFITool::search()
     else if (index == 1) { // GUID
         searchDialog->ui->guidEdit->setFocus();
         searchDialog->ui->guidEdit->setCursorPosition(0);
-        QByteArray pattern = searchDialog->ui->guidEdit->text().toLatin1();
+        UByteArray pattern = searchDialog->ui->guidEdit->text().toLatin1();
         if (pattern.isEmpty())
             return;
         UINT8 mode;
@@ -508,7 +586,7 @@ void UEFITool::extract(const UINT8 mode)
     if (!index.isValid())
         return;
     
-    QByteArray extracted;
+    UByteArray extracted;
     QString name;
     USTATUS result = ffsOps->extract(index, name, extracted, mode);
     if (result) {
@@ -516,7 +594,7 @@ void UEFITool::extract(const UINT8 mode)
         return;
     }
     
-    name = QDir::toNativeSeparators(currentDir + QDir::separator() + name);
+    name = QDir::toNativeSeparators(extractDir + QDir::separator() + name);
     
     //ui->statusBar->showMessage(name);
     
@@ -566,6 +644,8 @@ void UEFITool::extract(const UINT8 mode)
     outputFile.resize(0);
     outputFile.write(extracted);
     outputFile.close();
+
+    extractDir = QFileInfo(path).absolutePath();
 }
 
 void UEFITool::rebuild()
@@ -617,20 +697,185 @@ void UEFITool::saveImageFile()
     
 }
 
+void UEFITool::askReopenImageFile()
+{
+    QMessageBox msgBox(QMessageBox::Question, tr("Confirmation"),
+        tr("Image file was changed by external program, do you want to reopen it?"),
+        QMessageBox::Yes | QMessageBox::No);
+    QCheckBox checkBox(tr("Do not ask again"));
+    checkBox.setChecked(TRACK_IGNORE == fileTrackingState);
+    msgBox.setDefaultButton(QMessageBox::Yes);
+    msgBox.setCheckBox(&checkBox);
+
+    int ret = msgBox.exec();
+
+    if (checkBox.isChecked()) {
+        if (ret == QMessageBox::Yes) {
+            ui->actionTrackAndReopen->setChecked(true);
+            fileTrackingState = TRACK_REOPEN;
+        }
+        else if (ret == QMessageBox::No) {
+            ui->actionTrackAndIgnore->setChecked(true);
+            fileTrackingState = TRACK_IGNORE;
+        }
+    }
+    if (ret == QMessageBox::Yes)
+        reopenImageFile();
+}
+
+void UEFITool::onTrackingAction(QAction* action)
+{
+    if (action) {
+        int newTrackingState = action->data().toInt();
+        if (newTrackingState != fileTrackingState) {
+            fileTrackingState = newTrackingState;
+        }
+    }
+}
+
+void UEFITool::saveTreeState(const QModelIndex& index, QHash<QString, bool>& states)
+{
+    if (!index.isValid())
+        return;
+
+    // Save the expanded state using the item's data as the key
+    QString key = model->data(index, Qt::DisplayRole).toString();
+    states[key] = ui->structureTreeView->isExpanded(index);
+
+    // Recursively save child states
+    for (int row = 0; row < model->rowCount(index); row++) {
+        saveTreeState(model->index(row, 0, index), states);
+    }
+}
+
+void UEFITool::restoreTreeState(const QModelIndex& index, const QHash<QString, bool>& states)
+{
+    if (!index.isValid())
+        return;
+
+    // Restore the expanded state using the item's data as the key
+    QString key = model->data(index, Qt::DisplayRole).toString();
+    if (states.contains(key)) {
+        ui->structureTreeView->setExpanded(index, states[key]);
+    }
+
+    // Recursively restore child states
+    for (int row = 0; row < model->rowCount(index); row++) {
+        restoreTreeState(model->index(row, 0, index), states);
+    }
+}
+
+bool UEFITool::isAllExpanded()
+{
+    QAbstractItemModel* model = ui->structureTreeView->model();
+    if (!model)
+        return false;
+
+    QStack<QModelIndex> stack;
+    stack.push(QModelIndex());
+
+    while (!stack.isEmpty()) {
+        QModelIndex current = stack.pop();
+
+        if (current.isValid() && ui->structureTreeView->isExpanded(current) == false) {
+            return false;
+        }
+
+        int rowCount = model->rowCount(current);
+        for (int i = 0; i < rowCount; ++i) {
+            QModelIndex child = model->index(i, 0, current);
+            if (child.isValid()) {
+                stack.push(child);
+            }
+        }
+    }
+
+    return true;
+}
+
+void UEFITool::setExpandAll()
+{
+    ui->actionExpandAll->setEnabled(!isAllExpanded());
+}
+
+void UEFITool::expandTree()
+{
+    ui->structureTreeView->expandAll();
+}
+
+void UEFITool::fileChangedResume()
+{
+    if (changedFileFlag) {
+        askReopenImageFile();
+    }
+}
+
+void UEFITool::fileChanged(const QString& path)
+{
+    setChangedFileFlag(true);
+
+    switch (fileTrackingState) {
+        case TRACK_REOPEN :
+            reopenImageFile();
+        case TRACK_IGNORE :
+            return;
+    }
+
+    askReopenImageFile();
+}
+
+void UEFITool::setChangedFileFlag(const bool flag)
+{
+    QFont font(openedFileLabel.font());
+    font.setItalic(flag);
+    openedFileLabel.setFont(font);
+    changedFileFlag = flag;
+}
+
 void UEFITool::openImageFile()
 {
-    QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file"), currentDir, tr("BIOS image files (*.rom *.bin *.cap *scap *.bio *.fd *.wph *.dec);;All files (*)"));
+    QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file"), openImageDir, tr("BIOS image files (*.rom *.bin *.cap *scap *.bio *.fd *.wph *.dec);;All files (*)"));
     openImageFile(path);
 }
 
 void UEFITool::openImageFileInNewWindow()
 {
-    QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file in new window"), currentDir, tr("BIOS image files (*.rom *.bin *.cap *scap *.bio *.fd *.wph *.dec);;All files (*)"));
+    QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file in new window"), openImageDir, tr("BIOS image files (*.rom *.bin *.cap *scap *.bio *.fd *.wph *.dec);;All files (*)"));
     if (path.trimmed().isEmpty())
         return;
     QProcess::startDetached(currentProgramPath, QStringList(path));
 }
 
+void UEFITool::openRecentImageFile()
+{
+    QAction* action = qobject_cast<QAction*>(sender());
+    if (action) {
+        QString fileName = action->data().toString();
+        if (!fileName.isEmpty()) {
+            openImageFile(fileName);
+        }
+    }
+}
+
+void UEFITool::reopenImageFile()
+{
+    if (!currentPath.isEmpty() && ui->structureTreeView->model()->hasChildren(UModelIndex())) {
+        QHash<QString, bool> states;
+        saveTreeState(model->index(0, 0), states);
+        QList <UModelIndex> selected = ui->structureTreeView->selectionModel()->selectedIndexes();
+        UINT64 base = selected.isEmpty() ? UEFI_UPPER_INVALID_ADDRESS : model->base(selected.first());
+
+        openImageFile(currentPath);
+
+        restoreTreeState(model->index(0, 0), states);
+        if (base < UEFI_UPPER_INVALID_ADDRESS) {
+            UModelIndex index = model->findByBase(base);
+            ui->structureTreeView->selectionModel()->select(index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
+            ui->structureTreeView->scrollTo(index);
+        }
+    }
+}
+
 void UEFITool::openImageFile(QString path)
 {
     if (path.trimmed().isEmpty())
@@ -645,18 +890,23 @@ void UEFITool::openImageFile(QString path)
     
     QFile inputFile;
     inputFile.setFileName(path);
-    
+    QElapsedTimer timer;
+    timer.start();
     if (!inputFile.open(QFile::ReadOnly)) {
         QMessageBox::critical(this, tr("Image parsing failed"), tr("Can't open input file for reading"), QMessageBox::Ok);
         return;
     }
-    
+
+    watcher.removePaths(watcher.files());
+    setChangedFileFlag(false);
+    watcher.addPath(path);
+
     QByteArray buffer = inputFile.readAll();
     inputFile.close();
-    
+
     init();
     setWindowTitle(tr("UEFITool %1 - %2").arg(version).arg(fileInfo.fileName()));
-    
+
     // Parse the image
     USTATUS result = ffsParser->parse(buffer);
     showParserMessages();
@@ -665,7 +915,10 @@ void UEFITool::openImageFile(QString path)
         return;
     }
     else {
-        ui->statusBar->showMessage(tr("Opened: %1").arg(fileInfo.fileName()));
+        ui->statusBar->showMessage(QString("Image file %1 ").arg(fileInfo.fileName())
+            + (path == currentPath ? tr("reopened") : tr("opened"))
+            + QString(" in %1 sec").arg(timer.elapsed() / 1000.0));
+        openedFileLabel.setText(QDir::toNativeSeparators(fileInfo.absoluteFilePath()));
     }
     ffsParser->outputInfo();
     
@@ -688,7 +941,7 @@ void UEFITool::openImageFile(QString path)
     
     // Enable goToBase and goToAddress
     ui->actionGoToBase->setEnabled(true);
-    if (ffsParser->getAddressDiff() <= 0xFFFFFFFFUL)
+    if (ffsParser->getAddressDiff() < UEFI_UPPER_INVALID_ADDRESS)
         ui->actionGoToAddress->setEnabled(true);
     
     // Enable generateReport
@@ -699,9 +952,15 @@ void UEFITool::openImageFile(QString path)
     
     // Set current directory
     currentDir = fileInfo.absolutePath();
-    
+    openImageDir = currentDir;
+
     // Set current path
     currentPath = path;
+
+    // Update menu
+    updateRecentFilesMenu(currentPath);
+
+    ui->structureTreeView->expandToDepth(1);
 }
 
 void UEFITool::enableMessagesCopyActions(QListWidgetItem* item)
@@ -771,6 +1030,12 @@ void UEFITool::toggleBootGuardMarking(bool enabled)
     markingEnabled = enabled;
 }
 
+void UEFITool::toggleCStyleHexValues(bool enabled)
+{
+    model->setCStyleHexEnabled(enabled);
+    cStyleHexEnabled = enabled;
+}
+
 // Emit double click signal of QListWidget on enter/return key pressed
 bool UEFITool::eventFilter(QObject* obj, QEvent* event)
 {
@@ -898,14 +1163,21 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event)
         return;
     }
     
+    QMenu* menu = nullptr;
+
     switch (model->type(index)) {
-        case Types::Capsule:        ui->menuCapsuleActions->exec(event->globalPos());      break;
-        case Types::Image:          ui->menuImageActions->exec(event->globalPos());        break;
-        case Types::Region:         ui->menuRegionActions->exec(event->globalPos());       break;
-        case Types::Padding:        ui->menuPaddingActions->exec(event->globalPos());      break;
-        case Types::Volume:         ui->menuVolumeActions->exec(event->globalPos());       break;
-        case Types::File:           ui->menuFileActions->exec(event->globalPos());         break;
-        case Types::Section:        ui->menuSectionActions->exec(event->globalPos());      break;
+        case Types::Capsule:        menu = ui->menuCapsuleActions;      break;
+        case Types::Image:          menu = ui->menuImageActions;        break;
+        case Types::Region:         menu = ui->menuRegionActions;       break;
+        case Types::Padding:        menu = ui->menuPaddingActions;      break;
+        case Types::Volume:
+            if (model->hasEmptyHeader(index))
+                menu = ui->menuImageActions;
+            else
+                menu = ui->menuVolumeActions;
+            break;
+        case Types::File:           menu = ui->menuFileActions;         break;
+        case Types::Section:        menu = ui->menuSectionActions;      break;
         case Types::VssStore:
         case Types::Vss2Store:
         case Types::FdcStore:
@@ -918,9 +1190,16 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event)
         case Types::CmdbStore:
         case Types::FptStore:
         case Types::CpdStore:
-        case Types::BpdtStore:      ui->menuStoreActions->exec(event->globalPos());        break;
-        case Types::FreeSpace:      break; // No menu needed for FreeSpace item
-        default:                    ui->menuEntryActions->exec(event->globalPos());        break;
+        case Types::BpdtStore:      menu = ui->menuStoreActions;        break;
+        case Types::FreeSpace:      menu = ui->menuImageActions;        break;
+        default:                    menu = ui->menuEntryActions;        break;
+    }
+
+    if (menu != nullptr) {
+        QList<QAction*> actions = menu->actions();
+        QAction s = QAction(nullptr);
+        s.setSeparator(true);
+        QMenu::exec(actions << &s << ui->actionExpandAll, event->globalPos());
     }
 }
 
@@ -942,11 +1221,20 @@ void UEFITool::readSettings()
     ui->structureTreeView->setColumnWidth(3, settings.value("tree/columnWidth3", ui->structureTreeView->columnWidth(3)).toInt());
     markingEnabled = settings.value("tree/markingEnabled", true).toBool();
     ui->actionToggleBootGuardMarking->setChecked(markingEnabled);
-    
+    cStyleHexEnabled = settings.value("tree/cStyleHexEnabled", true).toBool();
+    ui->actionToggleCStyleHexValues->setChecked(cStyleHexEnabled);
+    openImageDir = settings.value("paths/openImageDir", ".").toString();
+    openGuidDatabaseDir = settings.value("paths/openGuidDatabaseDir", ".").toString();
+    extractDir = settings.value("paths/extractDir", ".").toString();
+    recentFiles = settings.value("paths/recentFiles").toStringList();
+    fileTrackingState = settings.value("options/fileTracking", TRACK_IGNORE).toInt();
+    if (fileTrackingState < TRACK_MIN || fileTrackingState > TRACK_MAX)
+        fileTrackingState = TRACK_IGNORE;
+
     // Set monospace font
     QString fontName;
     int fontSize;
-#if defined Q_OS_MACOS
+#if defined Q_OS_OSX
     fontName = settings.value("mainWindow/fontName", QString("Menlo")).toString();
     fontSize = settings.value("mainWindow/fontSize", 10).toInt();
 #elif defined Q_OS_WIN
@@ -975,8 +1263,14 @@ void UEFITool::writeSettings()
     settings.setValue("tree/columnWidth2", ui->structureTreeView->columnWidth(2));
     settings.setValue("tree/columnWidth3", ui->structureTreeView->columnWidth(3));
     settings.setValue("tree/markingEnabled", markingEnabled);
+    settings.setValue("tree/cStyleHexEnabled", cStyleHexEnabled);
     settings.setValue("mainWindow/fontName", currentFont.family());
     settings.setValue("mainWindow/fontSize", currentFont.pointSize());
+    settings.setValue("paths/openImageDir", openImageDir);
+    settings.setValue("paths/openGuidDatabaseDir", openGuidDatabaseDir);
+    settings.setValue("paths/extractDir", extractDir);
+    settings.setValue("paths/recentFiles", recentFiles);
+    settings.setValue("options/fileTracking", fileTrackingState);
 }
 
 void UEFITool::showFitTable()
@@ -1041,11 +1335,12 @@ void UEFITool::currentTabChanged(int index)
 
 void UEFITool::loadGuidDatabase()
 {
-    QString path = QFileDialog::getOpenFileName(this, tr("Select GUID database file to load"), currentDir, tr("Comma-separated values files (*.csv);;All files (*)"));
+    QString path = QFileDialog::getOpenFileName(this, tr("Select GUID database file to load"), openGuidDatabaseDir, tr("Comma-separated values files (*.csv);;All files (*)"));
     if (!path.isEmpty()) {
         initGuidDatabase(path);
         if (!currentPath.isEmpty() && QMessageBox::Yes == QMessageBox::information(this, tr("New GUID database loaded"), tr("Apply new GUID database on the opened file?\nUnsaved changes and tree position will be lost."), QMessageBox::Yes, QMessageBox::No))
             openImageFile(currentPath);
+        openGuidDatabaseDir = QFileInfo(path).absolutePath();
     }
 }
 
diff --git a/UEFITool/uefitool.h b/UEFITool/uefitool.h
index 08ef908..be0980d 100644
--- a/UEFITool/uefitool.h
+++ b/UEFITool/uefitool.h
@@ -15,6 +15,7 @@
 #define UEFITOOL_H
 
 #include <QMainWindow>
+#include <QActionGroup>
 #include <QByteArray>
 #include <QClipboard>
 #include <QDragEnterEvent>
@@ -22,6 +23,7 @@
 #include <QFile>
 #include <QFileDialog>
 #include <QFileInfo>
+#include <QFileSystemWatcher>
 #include <QFont>
 #include <QListWidget>
 #include <QMenu>
@@ -32,10 +34,12 @@
 #include <QProcess>
 #include <QSettings>
 #include <QSplitter>
+#include <QStack>
 #include <QStyleFactory>
 #include <QString>
 #include <QTableWidget>
 #include <QTreeView>
+#include <QToolButton>
 #include <QUrl>
 
 #include "../common/basetypes.h"
@@ -75,13 +79,19 @@ private slots:
     void scrollTreeView(QListWidgetItem* item); // For messages
     void scrollTreeView(QTableWidgetItem* item); // For FIT table entries
 
+    void onTrackingAction(QAction* action);
+    void fileChangedResume();
+    void fileChanged(const QString& path);
+    void setChangedFileFlag(const bool flag);
     void openImageFile();
     void openImageFileInNewWindow();
+    void openRecentImageFile();
     void saveImageFile();
 
     void search();
     void goToBase();
     void goToAddress();
+    void expandTree();
 
     void hexView();
     void bodyHexView();
@@ -112,6 +122,8 @@ private slots:
     void clearMessages();
 
     void toggleBootGuardMarking(bool enabled);
+    void toggleCStyleHexValues(bool enabled);
+    void setExpandAll();
 
     void about();
     void aboutQt();
@@ -144,23 +156,39 @@ private:
     GoToBaseDialog* goToBaseDialog;
     GoToAddressDialog* goToAddressDialog;
     QClipboard* clipboard;
+    QList<QAction*> recentFileActions;
+    QFileSystemWatcher watcher;
+    QToolButton openedFileLabel;
+    QStringList recentFiles;
     QString currentDir;
     QString currentPath;
     QString currentProgramPath;
+    QString openImageDir;
+    QString openGuidDatabaseDir;
+    QString extractDir;
     QFont currentFont;
     const QString version;
+    int fileTrackingState;
+    bool changedFileFlag;
     bool markingEnabled;
+    bool cStyleHexEnabled;
 
     bool eventFilter(QObject* obj, QEvent* event);
     void dragEnterEvent(QDragEnterEvent* event);
     void dropEvent(QDropEvent* event);
     void contextMenuEvent(QContextMenuEvent* event);
+    void updateRecentFilesMenu(const QString& fileName = QString());
     void readSettings();
+    void askReopenImageFile();
+    void reopenImageFile();
     void showParserMessages();
     void showFinderMessages();
     void showFitTable();
     void showSecurityInfo();
     void showBuilderMessages();
+    bool isAllExpanded();
+    void saveTreeState(const QModelIndex& index, QHash<QString, bool>& states);
+    void restoreTreeState(const QModelIndex& index, const QHash<QString, bool>& states);
 
     enum {
         TAB_PARSER,
@@ -169,6 +197,14 @@ private:
         TAB_SEARCH,
         TAB_BUILDER
     };
+
+    enum {
+        TRACK_MIN = 0,
+        TRACK_IGNORE = TRACK_MIN,
+        TRACK_ASK,
+        TRACK_REOPEN,
+        TRACK_MAX = TRACK_REOPEN
+    };
 };
 
 #endif // UEFITOOL_H
diff --git a/UEFITool/uefitool.ui b/UEFITool/uefitool.ui
index 51b6248..290709e 100644
--- a/UEFITool/uefitool.ui
+++ b/UEFITool/uefitool.ui
@@ -48,11 +48,11 @@
     <item>
      <widget class="QSplitter" name="messagesSplitter">
       <property name="orientation">
-       <enum>Qt::Vertical</enum>
+       <enum>Qt::Orientation::Vertical</enum>
       </property>
       <widget class="QSplitter" name="infoSplitter">
        <property name="orientation">
-        <enum>Qt::Horizontal</enum>
+        <enum>Qt::Orientation::Horizontal</enum>
        </property>
        <widget class="QGroupBox" name="structureGroupBox">
         <property name="title">
@@ -196,7 +196,7 @@
          <item>
           <widget class="QSplitter" name="splitter">
            <property name="orientation">
-            <enum>Qt::Horizontal</enum>
+            <enum>Qt::Orientation::Horizontal</enum>
            </property>
            <widget class="QTableWidget" name="fitTableWidget"/>
           </widget>
@@ -311,17 +311,27 @@
      <x>0</x>
      <y>0</y>
      <width>851</width>
-     <height>31</height>
+     <height>33</height>
     </rect>
    </property>
    <widget class="QMenu" name="menuFile">
     <property name="title">
      <string>&amp;File</string>
     </property>
+    <widget class="QMenu" name="menuOpenedImageFileTracking">
+     <property name="title">
+      <string>Opened image file tracking</string>
+     </property>
+     <addaction name="actionTrackAndIgnore"/>
+     <addaction name="actionTrackAndAsk"/>
+     <addaction name="actionTrackAndReopen"/>
+    </widget>
     <addaction name="actionOpenImageFile"/>
     <addaction name="actionOpenImageFileInNewWindow"/>
     <addaction name="actionSaveImageFile"/>
     <addaction name="separator"/>
+    <addaction name="menuOpenedImageFileTracking"/>
+    <addaction name="separator"/>
     <addaction name="actionGenerateReport"/>
     <addaction name="separator"/>
     <addaction name="actionLoadGuidDatabase"/>
@@ -329,6 +339,7 @@
     <addaction name="actionUnloadGuidDatabase"/>
     <addaction name="actionExportDiscoveredGuids"/>
     <addaction name="separator"/>
+    <addaction name="separator"/>
     <addaction name="actionQuit"/>
    </widget>
    <widget class="QMenu" name="menuHelp">
@@ -548,6 +559,9 @@
      <string>&amp;View</string>
     </property>
     <addaction name="actionToggleBootGuardMarking"/>
+    <addaction name="actionToggleCStyleHexValues"/>
+    <addaction name="separator"/>
+    <addaction name="actionExpandAll"/>
    </widget>
    <addaction name="menuFile"/>
    <addaction name="menuAction"/>
@@ -699,7 +713,7 @@
     <string>F1</string>
    </property>
    <property name="menuRole">
-    <enum>QAction::AboutRole</enum>
+    <enum>QAction::MenuRole::AboutRole</enum>
    </property>
   </action>
   <action name="actionAboutQt">
@@ -710,7 +724,7 @@
     <string>Shift+F1</string>
    </property>
    <property name="menuRole">
-    <enum>QAction::AboutQtRole</enum>
+    <enum>QAction::MenuRole::AboutQtRole</enum>
    </property>
   </action>
   <action name="actionQuit">
@@ -721,7 +735,7 @@
     <string>Alt+X</string>
    </property>
    <property name="menuRole">
-    <enum>QAction::QuitRole</enum>
+    <enum>QAction::MenuRole::QuitRole</enum>
    </property>
   </action>
   <action name="actionSearch">
@@ -936,6 +950,52 @@
     <string>Ctrl+Alt+E</string>
    </property>
   </action>
+  <action name="actionToggleCStyleHexValues">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>C-style hex values</string>
+   </property>
+   <property name="toolTip">
+    <string>C-style hex values</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Shift+C</string>
+   </property>
+  </action>
+  <action name="actionTrackAndIgnore">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>Ignore changes</string>
+   </property>
+  </action>
+  <action name="actionTrackAndAsk">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>Ask if changed</string>
+   </property>
+  </action>
+  <action name="actionTrackAndReopen">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>Auto reopen if changed</string>
+   </property>
+  </action>
+  <action name="actionExpandAll">
+   <property name="text">
+    <string>Expand all</string>
+   </property>
+   <property name="toolTip">
+    <string>Expand all tree items</string>
+   </property>
+  </action>
  </widget>
  <layoutdefault spacing="6" margin="11"/>
  <resources/>
diff --git a/common/basetypes.h b/common/basetypes.h
index 89c94f9..ad53567 100644
--- a/common/basetypes.h
+++ b/common/basetypes.h
@@ -78,6 +78,8 @@ typedef size_t USTATUS;
 #define U_INVALID_SYMBOL                  55
 #define U_ZLIB_DECOMPRESSION_FAILED       56
 #define U_INVALID_STORE                   57
+#define U_INVALID_PE_HEADER               58
+#define U_INVALID_TE_HEADER               59
 
 #define U_INVALID_MANIFEST                251
 #define U_UNKNOWN_MANIFEST_HEADER_VERSION 252
@@ -221,6 +223,10 @@ typedef struct EFI_TIME_ {
 #define TCG_HASH_ALGORITHM_ID_NULL   0x0010
 #define TCG_HASH_ALGORITHM_ID_SM3    0x0012
 
+// Some whole image-related notional defines
+#define UEFI_UPPER_INVALID_ADDRESS   0x100000000ULL
+#define UEFI_LOWER_INVALID_ADDRESS   (UEFI_UPPER_INVALID_ADDRESS >> 1)
+
 // A workaround for compilers not supporting c++11 and c11
 // for using PRIX64.
 #define __STDC_FORMAT_MACROS
diff --git a/common/ffsbuilder.cpp b/common/ffsbuilder.cpp
index dac3fa5..3d97358 100644
--- a/common/ffsbuilder.cpp
+++ b/common/ffsbuilder.cpp
@@ -39,7 +39,7 @@ USTATUS FfsBuilder::erase(const UModelIndex & index, UByteArray & erased)
         }
     }
     
-    erased = UByteArray(model->header(index).size() + model->body(index).size() + model->tail(index).size(), emptyByte);
+    erased = UByteArray(model->headerSize(index) + model->bodySize(index) + model->tailSize(index), emptyByte);
     
     return U_SUCCESS;
 }
@@ -124,7 +124,7 @@ USTATUS FfsBuilder::buildCapsule(const UModelIndex & index, UByteArray & capsule
             
             // Check size of reconstructed capsule body, it must remain the same
             UINT32 newSize = (UINT32)capsule.size();
-            UINT32 oldSize = (UINT32)model->body(index).size();
+            UINT32 oldSize = (UINT32)model->bodySize(index);
             if (newSize > oldSize) {
                 msg(usprintf("buildCapsule: new capsule size %Xh (%u) is bigger than the original %Xh (%u)", newSize, newSize, oldSize, oldSize), index);
                 return U_INVALID_CAPSULE;
@@ -223,7 +223,7 @@ USTATUS FfsBuilder::buildIntelImage(const UModelIndex & index, UByteArray & inte
         
         // Check size of new image, it must be same as old one
         UINT32 newSize = (UINT32)intelImage.size();
-        UINT32 oldSize = (UINT32)model->body(index).size();
+        UINT32 oldSize = (UINT32)model->bodySize(index);
         if (newSize > oldSize) {
             msg(usprintf("buildIntelImage: new image size %Xh (%u) is bigger than the original %Xh (%u)", newSize, newSize, oldSize, oldSize), index);
             return U_INVALID_IMAGE;
@@ -294,7 +294,7 @@ USTATUS FfsBuilder::buildRawArea(const UModelIndex & index, UByteArray & rawArea
             
             // Check size of new raw area, it must be same as original one
             UINT32 newSize = (UINT32)rawArea.size();
-            UINT32 oldSize = (UINT32)model->body(index).size();
+            UINT32 oldSize = (UINT32)model->bodySize(index);
             if (newSize > oldSize) {
                 msg(usprintf("buildRawArea: new area size %Xh (%u) is bigger than the original %Xh (%u)", newSize, newSize, oldSize, oldSize), index);
                 return U_INVALID_RAW_AREA;
diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp
index 9236211..64c619c 100644
--- a/common/ffsparser.cpp
+++ b/common/ffsparser.cpp
@@ -41,7 +41,7 @@
 
 // Constructor
 FfsParser::FfsParser(TreeModel* treeModel) : model(treeModel),
-imageBase(0), addressDiff(0x100000000ULL), protectedRegionsBase(0) {
+imageBase(0), addressDiff(UEFI_UPPER_INVALID_ADDRESS), protectedRegionsBase(0) {
     fitParser = new FitParser(treeModel, this);
     nvramParser = new NvramParser(treeModel, this);
     meParser = new MeParser(treeModel, this);
@@ -85,15 +85,18 @@ USTATUS FfsParser::parse(const UByteArray & buffer)
     // Reset global parser state
     openedImage = buffer;
     imageBase = 0;
-    addressDiff = 0x100000000ULL;
+    addressDiff = UEFI_UPPER_INVALID_ADDRESS;
+    baseAddressesMap.clear();
     protectedRegionsBase = 0;
     securityInfo = "";
     protectedRanges.clear();
     lastVtf = UModelIndex();
     dxeCore = UModelIndex();
     
+    model->setImage(buffer);
+
     // Parse input buffer
-    USTATUS result = performFirstPass(buffer, root);
+    USTATUS result = performFirstPass(openedImage, root);
     if (result == U_SUCCESS) {
         if (lastVtf.isValid()) {
             result = performSecondPass(root);
@@ -102,7 +105,7 @@ USTATUS FfsParser::parse(const UByteArray & buffer)
             msg(usprintf("%s: not a single Volume Top File is found, the image may be corrupted", __FUNCTION__));
         }
     }
-    
+
     addInfoRecursive(root);
     return result;
 }
@@ -114,18 +117,78 @@ USTATUS FfsParser::performFirstPass(const UByteArray & buffer, UModelIndex & ind
         return U_INVALID_PARAMETER;
     }
     
+    biosRegionInfo.type = Subtypes::InvalidRegion;
+
     // Try parsing as UEFI Capsule
     if (U_SUCCESS == parseCapsule(buffer, 0, UModelIndex(), index)) {
         return U_SUCCESS;
     }
-    
+    // Try parsing as some image
+    return parseImage(buffer, 0, UModelIndex(), index);
+}
+
+USTATUS FfsParser::parseImage(const UByteArray& buffer, const UINT32 localOffset, const UModelIndex& parent, UModelIndex& index)
+{
     // Try parsing as Intel image
-    if (U_SUCCESS == parseIntelImage(buffer, 0, UModelIndex(), index)) {
-        return U_SUCCESS;
+    USTATUS result = parseIntelImage(buffer, localOffset, parent, index);
+    bool retryFindLastVtf = true;
+    if (U_SUCCESS != result || biosRegionInfo.type != Subtypes::BiosRegion) {
+        // Parse as generic image
+        result = parseGenericImage(buffer, localOffset, parent, index);
+        if (U_STORES_NOT_FOUND == result || model->rowCount(index) <= 0) {
+            result = parseVolumeBody(index, true);
+            bool notEmpty = model->rowCount(index) > 0;
+            if (U_SUCCESS == result && notEmpty) {
+                model->setName(index, "UEFI volume part");
+                model->setType(index, Types::Volume);
+                model->setSubtype(index, Subtypes::Ffs2Volume);
+            }
+            else if (U_STORES_NOT_FOUND == result || !notEmpty) {
+                retryFindLastVtf = false;
+                model->setName(index, "Non-UEFI data");
+                model->setType(index, Types::Padding);
+                model->setSubtype(index, Subtypes::DataPadding);
+                result = U_SUCCESS;
+            }
+        }
     }
-    
-    // Parse as generic image
-    return parseGenericImage(buffer, 0, UModelIndex(), index);
+
+    if (retryFindLastVtf && !lastVtf.isValid()) {
+        // If lastVtf not found, we can present an alternative view of what the lastVtf and addressDiff shoud be
+        UINT64 preAddressDiff = UEFI_UPPER_INVALID_ADDRESS;
+        if (biosRegionInfo.type == Subtypes::BiosRegion) {
+            addressDiff = UEFI_UPPER_INVALID_ADDRESS - biosRegionInfo.length - biosRegionInfo.offset;
+        }
+        else if (!baseAddressesMap.empty()) {
+            if (baseAddressesMap.size() == 1) {
+                addressDiff = baseAddressesMap.begin()->first;
+            }
+            else {
+                std::pair <decltype(baseAddressesMap)::key_type, decltype(baseAddressesMap)::mapped_type> p = { 0, -1 }, p2 = p;
+                for (const auto& pair : baseAddressesMap)
+                    if (pair.second > p.second)
+                        p = pair;
+                baseAddressesMap.erase(p.first);
+                for (const auto& pair : baseAddressesMap)
+                    if (pair.second > p2.second)
+                        p2 = pair;
+                if (p.second > p2.second)
+                    addressDiff = p.first;
+            }
+        }
+
+        if (addressDiff < UEFI_UPPER_INVALID_ADDRESS) {
+            UINT64 endAddress = addressDiff + model->base(index) + model->headerSize(index) + model->bodySize(index);
+            if (endAddress > (UEFI_UPPER_INVALID_ADDRESS - INTEL_FIT_POINTER_OFFSET + sizeof(UINT32))) {
+                UModelIndex lastIndex = model->findByBase((UINT32)(endAddress - INTEL_FIT_POINTER_OFFSET - addressDiff));
+                if (!model->compressed(lastIndex)) {
+                    lastVtf = lastIndex;
+                }
+            }
+        }
+    }
+
+    return result;
 }
 
 USTATUS FfsParser::parseGenericImage(const UByteArray & buffer, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
@@ -135,7 +198,11 @@ USTATUS FfsParser::parseGenericImage(const UByteArray & buffer, const UINT32 loc
     UString info = usprintf("Full size: %Xh (%u)", (UINT32)buffer.size(), (UINT32)buffer.size());
     
     // Add tree item
-    index = model->addItem(localOffset, Types::Image, Subtypes::UefiImage, name, UString(), info, UByteArray(), buffer, UByteArray(), Fixed, parent);
+    index = model->addItem(
+        localOffset, Types::Image, Subtypes::UefiImage,
+        name, UString(), info,
+        0, buffer.size(), 0,
+        Fixed, parent);
     
     // Parse the image as raw area
     imageBase = model->base(parent) + localOffset;
@@ -176,8 +243,6 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, const UINT32 localOf
         }
         
         capsuleHeaderSize = capsuleHeader->HeaderSize;
-        UByteArray header = capsule.left(capsuleHeaderSize);
-        UByteArray body = capsule.mid(capsuleHeaderSize);
         UString name("UEFI capsule");
         UString info = UString("Capsule GUID: ") + guidToUString(capsuleHeader->CapsuleGuid, false) +
         usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nImage size: %Xh (%u)\nFlags: %08Xh",
@@ -187,7 +252,11 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, const UINT32 localOf
                  capsuleHeader->Flags);
         
         // Add tree item
-        index = model->addItem(localOffset, Types::Capsule, Subtypes::UefiCapsule, name, UString(), info, header, body, UByteArray(), Fixed, parent);
+        index = model->addItem(
+            localOffset, Types::Capsule, Subtypes::UefiCapsule,
+            name, UString(), info,
+            capsuleHeaderSize, capsule.size() - capsuleHeaderSize, 0,
+            Fixed, parent);
     }
     // Check buffer for being Toshiba capsule header
     else if (capsule.startsWith(TOSHIBA_CAPSULE_GUID)) {
@@ -208,8 +277,6 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, const UINT32 localOf
         }
         
         capsuleHeaderSize = capsuleHeader->HeaderSize;
-        UByteArray header = capsule.left(capsuleHeaderSize);
-        UByteArray body = capsule.mid(capsuleHeaderSize);
         UString name("Toshiba capsule");
         UString info = UString("Capsule GUID: ") + guidToUString(capsuleHeader->CapsuleGuid, false) +
         usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nImage size: %Xh (%u)\nFlags: %08Xh",
@@ -219,7 +286,11 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, const UINT32 localOf
                  capsuleHeader->Flags);
         
         // Add tree item
-        index = model->addItem(localOffset, Types::Capsule, Subtypes::ToshibaCapsule, name, UString(), info, header, body, UByteArray(), Fixed, parent);
+        index = model->addItem(
+            localOffset, Types::Capsule, Subtypes::ToshibaCapsule,
+            name, UString(), info,
+            capsuleHeaderSize, capsule.size() - capsuleHeaderSize, 0,
+            Fixed, parent);
     }
     // Check buffer for being extended Aptio capsule header
     else if (capsule.startsWith(APTIO_SIGNED_CAPSULE_GUID)
@@ -249,8 +320,8 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, const UINT32 localOf
         }
         
         capsuleHeaderSize = capsuleHeader->RomImageOffset;
-        UByteArray header = capsule.left(capsuleHeaderSize);
-        UByteArray body = capsule.mid(capsuleHeaderSize);
+//        UByteArray header = capsule.left(capsuleHeaderSize);
+//        UByteArray body = capsule.mid(capsuleHeaderSize);
         UString name("AMI Aptio capsule");
         UString info = UString("Capsule GUID: ") + guidToUString(capsuleHeader->CapsuleHeader.CapsuleGuid, false) +
         usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nImage size: %Xh (%u)\nFlags: %08Xh",
@@ -260,7 +331,11 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, const UINT32 localOf
                  capsuleHeader->CapsuleHeader.Flags);
         
         // Add tree item
-        index = model->addItem(localOffset, Types::Capsule, signedCapsule ? Subtypes::AptioSignedCapsule : Subtypes::AptioUnsignedCapsule, name, UString(), info, header, body, UByteArray(), Fixed, parent);
+        index = model->addItem(
+            localOffset, Types::Capsule, signedCapsule ? Subtypes::AptioSignedCapsule : Subtypes::AptioUnsignedCapsule,
+            name, UString(), info,
+            capsuleHeaderSize, capsule.size() - capsuleHeaderSize, 0,
+            Fixed, parent);
         
         // Show message about possible Aptio signature break
         if (signedCapsule) {
@@ -270,16 +345,10 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, const UINT32 localOf
     
     // Capsule present
     if (capsuleHeaderSize > 0) {
-        UByteArray image = capsule.mid(capsuleHeaderSize);
         UModelIndex imageIndex;
-        
-        // Try parsing as Intel image
-        if (U_SUCCESS == parseIntelImage(image, capsuleHeaderSize, index, imageIndex)) {
-            return U_SUCCESS;
-        }
-        
-        // Parse as generic image
-        return parseGenericImage(image, capsuleHeaderSize, index, imageIndex);
+
+        // Try parsing as some image
+        return parseImage(capsule.mid(capsuleHeaderSize), capsuleHeaderSize, index, imageIndex);
     }
     
     return U_ITEM_NOT_FOUND;
@@ -306,10 +375,12 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l
     const FLASH_DESCRIPTOR_UPPER_MAP* upperMap = (const FLASH_DESCRIPTOR_UPPER_MAP*)((UINT8*)descriptor + FLASH_DESCRIPTOR_UPPER_MAP_BASE);
     
     // Check sanity of base values
-    if (descriptorMap->MasterBase > FLASH_DESCRIPTOR_MAX_BASE
-        || descriptorMap->MasterBase == descriptorMap->RegionBase
-        || descriptorMap->MasterBase == descriptorMap->ComponentBase) {
-        msg(usprintf("%s: invalid descriptor master base %02Xh", __FUNCTION__, descriptorMap->MasterBase));
+    UINT32 masterBase = descriptorMap->MasterBase;
+    if (masterBase > FLASH_DESCRIPTOR_MAX_BASE)
+        masterBase = 8;
+    if (masterBase == descriptorMap->RegionBase
+        || masterBase == descriptorMap->ComponentBase) {
+        msg(usprintf("%s: invalid descriptor master base %02Xh", __FUNCTION__, masterBase));
         return U_INVALID_FLASH_DESCRIPTOR;
     }
     if (descriptorMap->RegionBase > FLASH_DESCRIPTOR_MAX_BASE
@@ -346,10 +417,13 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l
                 + itemSubtypeToUString(Types::Region, me.type)
                 + 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;
+            if ((UINT32)intelImage.size() > me.offset)
+                return U_TRUNCATED_IMAGE;
+        }
+        else {
+            me.data = intelImage.mid(me.offset, me.length);
+            regions.push_back(me);
         }
-        me.data = intelImage.mid(me.offset, me.length);
-        regions.push_back(me);
     }
     
     // BIOS region
@@ -377,6 +451,7 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l
                 index);
             return U_TRUNCATED_IMAGE;
         }
+        biosRegionInfo = bios;
         bios.data = intelImage.mid(bios.offset, bios.length);
         regions.push_back(bios);
     }
@@ -486,11 +561,14 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l
     imageBase = model->base(parent) + localOffset;
     
     // Add Intel image tree item
-    index = model->addItem(localOffset, Types::Image, Subtypes::IntelImage, name, UString(), info, UByteArray(), intelImage, UByteArray(), Fixed, parent);
+    index = model->addItem(
+        localOffset, Types::Image, Subtypes::IntelImage,
+        name, UString(), info,
+        0, intelImage.size(), 0,
+        Fixed, parent);
     
     // Descriptor
     // Get descriptor info
-    UByteArray body = intelImage.left(FLASH_DESCRIPTOR_SIZE);
     name = UString("Descriptor region");
     info = usprintf("ReservedVector:\n%02X %02X %02X %02X %02X %02X %02X %02X\n"
                     "%02X %02X %02X %02X %02X %02X %02X %02X\nFull size: %Xh (%u)",
@@ -509,7 +587,7 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l
     
     // Region access settings
     if (descriptorVersion == 1) {
-        const FLASH_DESCRIPTOR_MASTER_SECTION* masterSection = (const FLASH_DESCRIPTOR_MASTER_SECTION*)calculateAddress8((UINT8*)descriptor, descriptorMap->MasterBase);
+        const FLASH_DESCRIPTOR_MASTER_SECTION* masterSection = (const FLASH_DESCRIPTOR_MASTER_SECTION*)calculateAddress8((UINT8*)descriptor, masterBase);
         info += UString("\nRegion access settings:");
         info += usprintf("\nBIOS: %02Xh %02Xh ME: %02Xh %02Xh\nGbE:  %02Xh %02Xh",
                          masterSection->BiosRead,
@@ -533,7 +611,7 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l
                          masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR  ? "Yes " : "No  ");
     }
     else if (descriptorVersion == 2) {
-        const FLASH_DESCRIPTOR_MASTER_SECTION_V2* masterSection = (const FLASH_DESCRIPTOR_MASTER_SECTION_V2*)calculateAddress8((UINT8*)descriptor, descriptorMap->MasterBase);
+        const FLASH_DESCRIPTOR_MASTER_SECTION_V2* masterSection = (const FLASH_DESCRIPTOR_MASTER_SECTION_V2*)calculateAddress8((UINT8*)descriptor, masterBase);
         info += UString("\nRegion access settings:");
         info += usprintf("\nBIOS: %03Xh %03Xh ME: %03Xh %03Xh\nGbE:  %03Xh %03Xh EC: %03Xh %03Xh",
                          masterSection->BiosRead,
@@ -594,7 +672,11 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l
     }
     
     // Add descriptor tree item
-    UModelIndex regionIndex = model->addItem(localOffset, Types::Region, Subtypes::DescriptorRegion, name, UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
+    UModelIndex regionIndex = model->addItem(
+        localOffset, Types::Region, Subtypes::DescriptorRegion,
+        name, UString(), info,
+        0, FLASH_DESCRIPTOR_SIZE, 0,
+        Fixed, index);
     
     // Parse regions
     USTATUS result = U_SUCCESS;
@@ -633,15 +715,20 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l
             case Subtypes::OnePadding:
             case Subtypes::DataPadding: {
                 // Add padding between regions
-                UByteArray padding = intelImage.mid(region.offset, region.length);
+                UINT32 paddingSize = region.offset + region.length > intelImage.size()
+                    ? intelImage.size() - region.offset : region.length;
                 
                 // Get info
                 name = UString("Padding");
-                info = usprintf("Full size: %Xh (%u)",
-                                (UINT32)padding.size(), (UINT32)padding.size());
+                info = usprintf("Full size: %Xh (%u)", paddingSize, paddingSize);
                 
                 // Add tree item
-                regionIndex = model->addItem(region.offset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
+                UByteArray padding = intelImage.mid(region.offset, paddingSize);
+                regionIndex = model->addItem(
+                    region.offset, Types::Padding, getPaddingType(padding),
+                    name, UString(), info,
+                    0, paddingSize, 0,
+                    Fixed, index);
                 result = U_SUCCESS;
             } break;
             default:
@@ -677,7 +764,11 @@ USTATUS FfsParser::parseGbeRegion(const UByteArray & gbe, const UINT32 localOffs
                             version->minor);
     
     // Add tree item
-    index = model->addItem(localOffset, Types::Region, Subtypes::GbeRegion, name, UString(), info, UByteArray(), gbe, UByteArray(), Fixed, parent);
+    index = model->addItem(
+        localOffset, Types::Region, Subtypes::GbeRegion,
+        name, UString(), info,
+        0, gbe.size(), 0,
+        Fixed, parent);
     
     return U_SUCCESS;
 }
@@ -696,10 +787,11 @@ USTATUS FfsParser::parseMeRegion(const UByteArray & me, const UINT32 localOffset
     bool versionFound = true;
     bool emptyRegion = false;
     // Check for empty region
-    if (me.size() == me.count('\xFF') || me.size() == me.count('\x00')) {
+    auto c = checkSingle(me);
+    if (c >= 0) {
         // Further parsing not needed
         emptyRegion = true;
-        info += ("\nState: empty");
+        info += usprintf("\nState: empty (0x%02X)", c);
     }
     else {
         // Search for new signature
@@ -716,11 +808,13 @@ USTATUS FfsParser::parseMeRegion(const UByteArray & me, const UINT32 localOffset
                 versionFound = false;
             }
         }
-        
+
+#if 0 // We need ME region to be shown even if it's version/structure is unknown - so we still can save ME binary part from UI
         // Check sanity
         if ((UINT32)me.size() < (UINT32)versionOffset + sizeof(ME_VERSION))
             return U_INVALID_REGION;
-        
+#endif
+
         // Add version information
         if (versionFound) {
             const ME_VERSION* version = (const ME_VERSION*)(me.constData() + versionOffset);
@@ -731,9 +825,13 @@ USTATUS FfsParser::parseMeRegion(const UByteArray & me, const UINT32 localOffset
                              version->Build);
         }
     }
-    
+
     // Add tree item
-    index = model->addItem(localOffset, Types::Region, Subtypes::MeRegion, name, UString(), info, UByteArray(), me, UByteArray(), Fixed, parent);
+    index = model->addItem(
+        localOffset, Types::Region, Subtypes::MeRegion,
+        name, UString(), info,
+        0, me.size(), 0,
+        Fixed, parent);
     
     // Show messages
     if (emptyRegion) {
@@ -759,8 +857,21 @@ USTATUS FfsParser::parsePdrRegion(const UByteArray & pdr, const UINT32 localOffs
     UString name("PDR region");
     UString info = usprintf("Full size: %Xh (%u)", (UINT32)pdr.size(), (UINT32)pdr.size());
     
+    bool emptyRegion = false;
+    // Check for empty region
+    auto c = checkSingle(pdr);
+    if (c >= 0) {
+        // Further parsing not needed
+        emptyRegion = true;
+        info += usprintf("\nState: empty (0x%02X)", c);
+    }
+
     // Add tree item
-    index = model->addItem(localOffset, Types::Region, Subtypes::PdrRegion, name, UString(), info, UByteArray(), pdr, UByteArray(), Fixed, parent);
+    index = model->addItem(
+        localOffset, Types::Region, Subtypes::PdrRegion,
+        name, UString(), info,
+        0, pdr.size(), 0,
+        Fixed, parent);
     
     // Parse PDR region as BIOS space
     USTATUS result = parseRawArea(index);
@@ -782,14 +893,19 @@ USTATUS FfsParser::parseDevExp1Region(const UByteArray & devExp1, const UINT32 l
     
     bool emptyRegion = false;
     // Check for empty region
-    if (devExp1.size() == devExp1.count('\xFF') || devExp1.size() == devExp1.count('\x00')) {
+    auto c = checkSingle(devExp1);
+    if (c >= 0) {
         // Further parsing not needed
         emptyRegion = true;
-        info += ("\nState: empty");
+        info += usprintf("\nState: empty (0x%02X)", c);
     }
     
     // Add tree item
-    index = model->addItem(localOffset, Types::Region, Subtypes::DevExp1Region, name, UString(), info, UByteArray(), devExp1, UByteArray(), Fixed, parent);
+    index = model->addItem(
+        localOffset, Types::Region, Subtypes::DevExp1Region,
+        name, UString(), info,
+        0, devExp1.size(), 0,
+        Fixed, parent);
     
     if (!emptyRegion) {
         meParser->parseMeRegionBody(index);
@@ -807,8 +923,21 @@ USTATUS FfsParser::parseGenericRegion(const UINT8 subtype, const UByteArray & re
     UString name = itemSubtypeToUString(Types::Region, subtype) + UString(" region");
     UString info = usprintf("Full size: %Xh (%u)", (UINT32)region.size(), (UINT32)region.size());
     
+    bool emptyRegion = false;
+    // Check for empty region
+    auto c = checkSingle(region);
+    if (c >= 0) {
+        // Further parsing not needed
+        emptyRegion = true;
+        info += usprintf("\nState: empty (0x%02X)", c);
+    }
+
     // Add tree item
-    index = model->addItem(localOffset, Types::Region, subtype, name, UString(), info, UByteArray(), region, UByteArray(), Fixed, parent);
+    index = model->addItem(
+        localOffset, Types::Region, subtype,
+        name, UString(), info,
+        0, region.size(), 0,
+        Fixed, parent);
     
     return U_SUCCESS;
 }
@@ -824,7 +953,11 @@ USTATUS FfsParser::parseBiosRegion(const UByteArray & bios, const UINT32 localOf
     UString info = usprintf("Full size: %Xh (%u)", (UINT32)bios.size(), (UINT32)bios.size());
     
     // Add tree item
-    index = model->addItem(localOffset, Types::Region, Subtypes::BiosRegion, name, UString(), info, UByteArray(), bios, UByteArray(), Fixed, parent);
+    index = model->addItem(
+        localOffset, Types::Region, Subtypes::BiosRegion,
+        name, UString(), info,
+        0, bios.size(), 0,
+        Fixed, parent);
     
     return parseRawArea(index);
 }
@@ -837,7 +970,8 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
     
     // Get item data
     UByteArray data = model->body(index);
-    UINT32 headerSize = (UINT32)model->header(index).size();
+    UINT32 headerSize = (UINT32)model->headerSize(index);
+    UINT32 bodySize;
     
     USTATUS result;
     UString name;
@@ -852,7 +986,7 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
     result = findNextRawAreaItem(index, 0, prevItemType, prevItemOffset, prevItemSize, prevItemAltSize);
     if (result) {
         // No need to parse further
-        return U_SUCCESS;
+        return U_STORES_NOT_FOUND; // it was U_SUCCESS in stock, but we need to know if something went wrong
     }
     
     // Set base of protected regions to be the first volume
@@ -864,12 +998,17 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
     // First item is not at the beginning of this raw area
     if (prevItemOffset > 0) {
         // Get info
-        UByteArray padding = data.left(prevItemOffset);
+        UINT32 paddingSize = prevItemOffset > data.size() ? data.size() : prevItemOffset;
         name = UString("Padding");
-        info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size());
+        info = usprintf("Full size: %Xh (%u)", paddingSize, paddingSize);
         
         // Add tree item
-        model->addItem(headerSize, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
+        UByteArray padding = data.left(paddingSize);
+        model->addItem(
+            headerSize, Types::Padding, getPaddingType(padding),
+            name, UString(), info,
+            0, paddingSize, 0,
+            Fixed, index);
     }
     
     // Search for and parse all items
@@ -882,33 +1021,43 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
         // Padding between items
         if (itemOffset > prevItemOffset + prevItemSize) {
             UINT32 paddingOffset = prevItemOffset + prevItemSize;
-            UINT32 paddingSize = itemOffset - paddingOffset;
-            UByteArray padding = data.mid(paddingOffset, paddingSize);
+            UINT32 paddingSize = itemOffset > data.size() ? data.size() - paddingOffset : itemOffset - paddingOffset;
             
             // Get info
             name = UString("Padding");
-            info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size());
+            info = usprintf("Full size: %Xh (%u)", paddingSize, paddingSize);
             
             // Add tree item
-            model->addItem(headerSize + paddingOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
+            UByteArray padding = data.mid(paddingOffset, paddingSize);
+            model->addItem(
+                headerSize + paddingOffset, Types::Padding, getPaddingType(padding),
+                name, UString(), info,
+                0, paddingSize, 0,
+                Fixed, index);
         }
         
         // Check that item is fully present in input
         if (itemSize > (UINT32)data.size() || itemOffset + itemSize > (UINT32)data.size()) {
             // Mark the rest as padding and finish parsing
-            UByteArray padding = data.mid(itemOffset);
+            UINT32 paddingSize = itemOffset > data.size()
+                ? 0 : data.size() - itemOffset;
             
             // Get info
             name = UString("Padding");
-            info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size());
+            info = usprintf("Full size: %Xh (%u)", paddingSize, paddingSize);
             
             // Add tree item
-            UModelIndex paddingIndex = model->addItem(headerSize + itemOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
+            UByteArray padding = data.mid(paddingSize);
+            UModelIndex paddingIndex = model->addItem(
+                headerSize + paddingSize, Types::Padding, getPaddingType(padding),
+                name, UString(), info,
+                0, paddingSize, 0,
+                Fixed, index);
             msg(usprintf("%s: one of objects inside overlaps the end of data", __FUNCTION__), paddingIndex);
             
             // Update variables
             prevItemOffset = itemOffset;
-            prevItemSize = (UINT32)padding.size();
+            prevItemSize = paddingSize;
             break;
         }
         
@@ -943,7 +1092,10 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
             info = usprintf("Full size: %Xh (%u)", (UINT32)bpdtStore.size(), (UINT32)bpdtStore.size());
             
             // Add tree item
-            UModelIndex bpdtIndex = model->addItem(headerSize + itemOffset, Types::BpdtStore, 0, name, UString(), info, UByteArray(), bpdtStore, UByteArray(), Fixed, index);
+            UModelIndex bpdtIndex = model->addItem(headerSize + itemOffset, Types::BpdtStore, 0,
+                name, UString(), info,
+                0, bpdtStore.size(), 0,
+                Fixed, index);
             
             // Parse BPDT region
             UModelIndex bpdtPtIndex;
@@ -960,16 +1112,16 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
                 insyde_fdm_t parsed(&ks);
                 UINT32 storeSize = (UINT32)fdm.size();
                 
-                // Construct header and body
-                UByteArray header = fdm.left(parsed.data_offset());
-                UByteArray body = fdm.mid(header.size(), storeSize - header.size());
+                // Obtain header and body size
+                headerSize = parsed.data_offset();
+                bodySize = storeSize - headerSize;
                 
                 // Add info
                 UString name = UString("Insyde H2O FlashDeviceMap");
                 UString info = usprintf("Signature: HFDM\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nData offset: %Xh\nEntry size: %Xh (%u)\nEntry format: %02Xh\nRevision: %02Xh\nExtension count: %u\nFlash descriptor base address: %08Xh\nChecksum: %02Xh",
                                         storeSize, storeSize,
-                                        (UINT32)header.size(), (UINT32)header.size(),
-                                        (UINT32)body.size(), (UINT32)body.size(),
+                                        headerSize, headerSize,
+                                        bodySize, bodySize,
                                         parsed.data_offset(),
                                         parsed.entry_size(), parsed.entry_size(),
                                         parsed.entry_format(),
@@ -1004,7 +1156,11 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
                 }
                 
                 // Add header tree item
-                UModelIndex headerIndex = model->addItem(headerSize + itemOffset, Types::InsydeFlashDeviceMapStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index);
+                UModelIndex headerIndex = model->addItem(
+                    headerSize + itemOffset, Types::InsydeFlashDeviceMapStore, 0,
+                    name, UString(), info,
+                    headerSize, bodySize, 0,
+                    Fixed, index);
                 
                 // Add entries
                 UINT32 entryOffset = parsed.data_offset();
@@ -1013,11 +1169,11 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
                     const EFI_GUID guid = readUnaligned((const EFI_GUID*)entry->guid().c_str());
                     name = insydeFlashDeviceMapEntryTypeGuidToUString(guid);
                     UString text;
-                    header = data.mid(itemOffset + entryOffset, sizeof(INSYDE_FLASH_DEVICE_MAP_ENTRY));
-                    body = data.mid(itemOffset + entryOffset + header.size(), parsed.entry_size() - header.size());
+                    headerSize = sizeof(INSYDE_FLASH_DEVICE_MAP_ENTRY);
+                    bodySize = parsed.entry_size() - headerSize;
                     
                     // Add info
-                    UINT32 entrySize = (UINT32)header.size() + (UINT32)body.size();
+                    UINT32 entrySize = headerSize + bodySize;
                     info = UString("Region type: ") + guidToUString(guid, false) + "\n";
                     info += UString("Region id: ");
                     for (UINT8 i = 0; i < 16; i++) {
@@ -1025,8 +1181,8 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
                     }
                     info += usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nRegion address: %08Xh\nRegion size: %08Xh\nAttributes: %08Xh",
                                      entrySize, entrySize,
-                                     (UINT32)header.size(), (UINT32)header.size(),
-                                     (UINT32)body.size(), (UINT32)body.size(),
+                                     headerSize, headerSize,
+                                     bodySize, bodySize,
                                      (UINT32)entry->region_base(),
                                      (UINT32)entry->region_size(),
                                      entry->attributes());
@@ -1045,14 +1201,18 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
                         range.Size = (UINT32)entry->region_size();
                         range.AlgorithmId = TCG_HASH_ALGORITHM_ID_SHA256;
                         range.Type = PROTECTED_RANGE_VENDOR_HASH_INSYDE;
-                        range.Hash = body;
+                        range.Hash = data.mid(itemOffset + entryOffset + headerSize, bodySize);
                         protectedRanges.push_back(range);
                         
-                        securityInfo += usprintf("Address: %08Xh Size: %Xh\nHash: ", range.Offset, range.Size) + UString(body.toHex().constData()) + "\n";
+                        securityInfo += usprintf("Address: %08Xh Size: %Xh\nHash: ", range.Offset, range.Size) + UString(range.Hash.toHex().constData()) + "\n";
                     }
                     
                     // Add tree item
-                    model->addItem(entryOffset, Types::InsydeFlashDeviceMapEntry, 0, name, text, info, header, body, UByteArray(), Fixed, headerIndex);
+                    model->addItem(
+                        entryOffset, Types::InsydeFlashDeviceMapEntry, 0,
+                        name, text, info,
+                        headerSize, bodySize, 0,
+                        Fixed, headerIndex);
                     
                     entryOffset += entrySize;
                 }
@@ -1082,14 +1242,19 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
     // Padding at the end of RAW area
     itemOffset = prevItemOffset + prevItemSize;
     if ((UINT32)data.size() > itemOffset) {
-        UByteArray padding = data.mid(itemOffset);
+        UINT32 paddingSize = data.size() - itemOffset;
         
         // Get info
         name = UString("Padding");
-        info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size());
+        info = usprintf("Full size: %Xh (%u)", paddingSize, paddingSize);
         
         // Add tree item
-        model->addItem(headerSize + itemOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
+        UByteArray padding = data.mid(itemOffset);
+        model->addItem(
+            headerSize + itemOffset, Types::Padding, getPaddingType(padding),
+            name, UString(), info,
+            0, paddingSize, 0,
+            Fixed, index);
     }
     
     // Parse bodies
@@ -1109,9 +1274,6 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
             case Types::BpdtPartition:
                 // Parsing already done
                 break;
-            case Types::InsydeFlashDeviceMapStore:
-                // Parsing already done
-                break;
             case Types::Padding:
                 // No parsing required
                 break;
@@ -1195,7 +1357,7 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc
         isMicrocodeVolume = true;
         headerSize = EFI_APPLE_MICROCODE_VOLUME_HEADER_SIZE;
     }
-    
+
     // Check volume revision and alignment
     bool msgAlignmentBitsSet = false;
     bool msgUnaligned = false;
@@ -1231,8 +1393,8 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc
     // Check for AppleCRC32 and UsedSpace in ZeroVector
     bool hasAppleCrc32 = false;
     UINT32 volumeSize = (UINT32)volume.size();
-    UINT32 appleCrc32 = *(UINT32*)(volume.constData() + 8);
-    UINT32 usedSpace = *(UINT32*)(volume.constData() + 12);
+    const UINT32 appleCrc32 = *(const UINT32*)(volume.constData() + 8);
+    const UINT32 usedSpace = *(const UINT32*)(volume.constData() + 12);
     if (appleCrc32 != 0) {
         // Calculate CRC32 of the volume body
         UINT32 crc = (UINT32)crc32(0, (const UINT8*)(volume.constData() + volumeHeader->HeaderLength), volumeSize - volumeHeader->HeaderLength);
@@ -1258,8 +1420,6 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc
     if (headerSize >= (UINT32)volume.size()) {
         return U_INVALID_VOLUME;
     }
-    UByteArray header = volume.left(headerSize);
-    UByteArray body = volume.mid(headerSize);
     UString name = guidToUString(volumeHeader->FileSystemGuid);
     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: ",
@@ -1288,7 +1448,28 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc
                          extendedHeader->ExtHeaderSize, extendedHeader->ExtHeaderSize) + guidToUString(extendedHeader->FvName, false);
         name = guidToUString(extendedHeader->FvName); // Replace FFS GUID with volume GUID
     }
-    
+
+    // Block size and blocks number
+    const EFI_FV_BLOCK_MAP_ENTRY* entry = (const EFI_FV_BLOCK_MAP_ENTRY*)(volume.constData() + sizeof(EFI_FIRMWARE_VOLUME_HEADER));
+    UString infoNum = usprintf("Number of blocks: %Xh (%u)", entry->NumBlocks, entry->NumBlocks);
+    UString infoSize = usprintf("Block size: %Xh (%u)", entry->Length, entry->Length);
+    UINT32 volumeAltSize = entry->NumBlocks * entry->Length;
+    if (volumeSize != volumeAltSize) {
+        if (volumeAltSize % entry->Length == 0 && volumeSize % entry->Length == 0) {
+            infoNum += usprintf(", invalid, should be %Xh", volumeSize / entry->Length);
+            infoSize += ", valid";
+        }
+        else if (volumeAltSize % entry->NumBlocks == 0 && volumeSize % entry->NumBlocks == 0) {
+            infoNum += ", valid";
+            infoSize += usprintf(", invalid, should be %Xh", volumeSize / entry->NumBlocks);
+        }
+    }
+    else {
+        infoNum += ", valid";
+        infoSize += ", valid";
+    }
+    info += "\n" + infoNum + "\n" + infoSize;
+
     // Add text
     UString text;
     if (hasAppleCrc32)
@@ -1306,7 +1487,11 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc
         else if (isMicrocodeVolume)
             subtype = Subtypes::MicrocodeVolume;
     }
-    index = model->addItem(localOffset, Types::Volume, subtype, name, text, info, header, body, UByteArray(), Movable, parent);
+    index = model->addItem(
+        localOffset, Types::Volume, subtype,
+        name, text, info,
+        headerSize, volume.size() - headerSize, 0,
+        Movable, parent);
     
     // Set parsing data for created volume
     VOLUME_PARSING_DATA pdata = {};
@@ -1341,17 +1526,6 @@ bool FfsParser::microcodeHeaderValid(const INTEL_MICROCODE_HEADER* ucodeHeader)
 {
     bool reservedBytesValid = true;
 
-    // Check CpuFlags reserved bytes to be zero
-    for (UINT32 i = 0; i < sizeof(ucodeHeader->ProcessorFlagsReserved); i++) {
-        if (ucodeHeader->ProcessorFlagsReserved[i] != 0x00) {
-            reservedBytesValid = false;
-            break;
-        }
-    }
-    if (!reservedBytesValid) {
-        return false;
-    }
-    
     // Check data size to be multiple of 4 and less than 0x1000000
     if (ucodeHeader->DataSize % 4 != 0 ||
         ucodeHeader->DataSize > 0xFFFFFF) {
@@ -1389,8 +1563,8 @@ bool FfsParser::microcodeHeaderValid(const INTEL_MICROCODE_HEADER* ucodeHeader)
         ucodeHeader->DateYear > 0x2049) {
         return FALSE;
     }
-    // Check HeaderVersion to be 1.
-    if (ucodeHeader->HeaderVersion != 1) {
+    // Check HeaderType to be 1.
+    if (ucodeHeader->HeaderType != 1) {
         return FALSE;
     }
     // Check LoaderRevision to be 1.
@@ -1535,28 +1709,6 @@ continue_searching: {}
             nextItemOffset = offset;
             break;
         }
-        else if (readUnaligned(currentPos) == INSYDE_FLASH_DEVICE_MAP_SIGNATURE) {
-            // Check data size
-            if (restSize < sizeof(INSYDE_FLASH_DEVICE_MAP_HEADER))
-                continue;
-            
-            const INSYDE_FLASH_DEVICE_MAP_HEADER *fdmHeader = (const INSYDE_FLASH_DEVICE_MAP_HEADER *)currentPos;
-            
-            if (restSize < fdmHeader->Size)
-                continue;
-            
-            if (fdmHeader->Revision > 4) {
-                msg(usprintf("%s: Insyde Flash Device Map candidate with unknown revision %u", __FUNCTION__, fdmHeader->Revision), index);
-                continue;
-            }
-            
-            // All checks passed, FDM found
-            nextItemType = Types::InsydeFlashDeviceMapStore;
-            nextItemSize = fdmHeader->Size;
-            nextItemAlternativeSize = fdmHeader->Size;
-            nextItemOffset = offset;
-            break;
-        }
     }
     
     // No more stores found
@@ -1577,14 +1729,18 @@ USTATUS FfsParser::parseVolumeNonUefiData(const UByteArray & data, const UINT32
     UString info = usprintf("Full size: %Xh (%u)", (UINT32)data.size(), (UINT32)data.size());
     
     // Add padding tree item
-    UModelIndex paddingIndex = model->addItem(localOffset, Types::Padding, Subtypes::DataPadding, UString("Non-UEFI data"), UString(), info, UByteArray(), data, UByteArray(), Fixed, index);
+    UModelIndex paddingIndex = model->addItem(
+        localOffset, Types::Padding, Subtypes::DataPadding,
+        UString("Non-UEFI data"), UString(),
+        info, 0, data.size(), 0,
+        Fixed, index);
     msg(usprintf("%s: non-UEFI data found in volume's free space", __FUNCTION__), paddingIndex);
     
     // Parse contents as RAW area
     return parseRawArea(paddingIndex);
 }
 
-USTATUS FfsParser::parseVolumeBody(const UModelIndex & index)
+USTATUS FfsParser::parseVolumeBody(const UModelIndex & index, const bool probe)
 {
     // Sanity check
     if (!index.isValid()) {
@@ -1593,9 +1749,9 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index)
     
     // Get volume header size and body
     UByteArray volumeBody = model->body(index);
-    UINT32 volumeHeaderSize = (UINT32)model->header(index).size();
+    UINT32 volumeHeaderSize = (UINT32)model->headerSize(index);
     
-    // Parse NVRAM volume with a dedicated function
+    // Parse VSS NVRAM volumes with a dedicated function
     if (model->subtype(index) == Subtypes::NvramVolume) {
         return nvramParser->parseNvramVolumeBody(index);
     }
@@ -1639,7 +1795,8 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index)
         
         // Check that we are at the empty space
         UByteArray header = volumeBody.mid(fileOffset, (int)std::min(sizeof(EFI_FFS_FILE_HEADER), (size_t)volumeBodySize - fileOffset));
-        if (header.count(emptyByte) == header.size()) { //Empty space
+        auto c = checkSingle(header, (unsigned char)emptyByte);
+        if (c == emptyByte) {   //Empty space
             // Check volume usedSpace entry to be valid
             if (usedSpace > 0 && usedSpace == fileOffset + volumeHeaderSize) {
                 if (model->hasEmptyParsingData(index) == false) {
@@ -1653,11 +1810,12 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index)
             
             // Check free space to be actually free
             UByteArray freeSpace = volumeBody.mid(fileOffset);
-            if (freeSpace.count(emptyByte) != freeSpace.size()) {
+            auto c = checkSingle(freeSpace, (unsigned char)emptyByte);
+            if (c != emptyByte) {
                 // Search for the first non-empty byte
                 UINT32 i;
                 UINT32 size = (UINT32)freeSpace.size();
-                const UINT8* current = (UINT8*)freeSpace.constData();
+                const UINT8* current = (const UINT8*)freeSpace.constData();
                 for (i = 0; i < size; i++) {
                     if (*current++ != emptyByte) {
                         break; // Exit from parsing loop
@@ -1672,13 +1830,19 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index)
                 
                 // Add all bytes before as free space
                 if (i > 0) {
-                    UByteArray free = freeSpace.left(i);
+                    if (probe)
+                        return U_STORES_NOT_FOUND;
+                    UINT32 freeSize = i > freeSpace.size() ? freeSpace.size() : i;
                     
                     // Get info
-                    UString info = usprintf("Full size: %Xh (%u)", (UINT32)free.size(), (UINT32)free.size());
+                    UString info = usprintf("Full size: %Xh (%u)", freeSize, freeSize);
                     
                     // Add free space item
-                    model->addItem(volumeHeaderSize + fileOffset, Types::FreeSpace, 0, UString("Volume free space"), UString(), info, UByteArray(), free, UByteArray(), Movable, index);
+                    model->addItem(
+                        volumeHeaderSize + fileOffset, Types::FreeSpace, 0,
+                        UString("Volume free space"), UString(), info,
+                        0, freeSize, 0,
+                        Movable, index);
                 }
                 
                 // Parse non-UEFI data
@@ -1689,7 +1853,11 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index)
                 UString info = usprintf("Full size: %Xh (%u)", (UINT32)freeSpace.size(), (UINT32)freeSpace.size());
                 
                 // Add free space item
-                model->addItem(volumeHeaderSize + fileOffset, Types::FreeSpace, 0, UString("Volume free space"), UString(), info, UByteArray(), freeSpace, UByteArray(), Movable, index);
+                model->addItem(
+                    volumeHeaderSize + fileOffset, Types::FreeSpace, 0,
+                    UString("Volume free space"), UString(), info,
+                    0, freeSpace.size(), 0,
+                    Movable, index);
             }
             
             break; // Exit from parsing loop
@@ -1699,6 +1867,8 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index)
         // Check that the remaining space can still have a file in it
         if (volumeBodySize - fileOffset < sizeof(EFI_FFS_FILE_HEADER) // Remaining space is smaller than the smallest possible file
             || volumeBodySize - fileOffset < fileSize) { // Remaining space is smaller than non-empty file size
+            if (probe)
+                return U_STORES_NOT_FOUND;
             // Parse non-UEFI data
             parseVolumeNonUefiData(volumeBody.mid(fileOffset), volumeHeaderSize + fileOffset, index);
             
@@ -1707,7 +1877,7 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index)
         
         // Parse current file's header
         UModelIndex fileIndex;
-        USTATUS result = parseFileHeader(volumeBody.mid(fileOffset, fileSize), volumeHeaderSize + fileOffset, index, fileIndex);
+        USTATUS result = parseFileHeader(volumeBody.mid(fileOffset, fileSize), volumeHeaderSize + fileOffset, index, fileIndex, probe);
         if (result) {
             msg(usprintf("%s: file header parsing failed with error ", __FUNCTION__) + errorCodeToUString(result), index);
         }
@@ -1729,7 +1899,7 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index)
         }
         
         // Get current file GUID
-        UByteArray currentGuid(model->header(current).constData(), sizeof(EFI_GUID));
+        const UByteArray currentGuid(model->header(current).constData(), sizeof(EFI_GUID));
         
         // Check files after current for having an equal GUID
         for (int j = i + 1; j < model->rowCount(index); j++) {
@@ -1741,11 +1911,11 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index)
             }
             
             // Get another file GUID
-            UByteArray anotherGuid(model->header(another).constData(), sizeof(EFI_GUID));
+            const UByteArray anotherGuid(model->header(another).constData(), sizeof(EFI_GUID));
             
             // Check GUIDs for being equal
             if (currentGuid == anotherGuid) {
-                msg(usprintf("%s: file with duplicate GUID ", __FUNCTION__) + guidToUString(readUnaligned((EFI_GUID*)(anotherGuid.data()))), another);
+                msg(usprintf("%s: file with duplicate GUID ", __FUNCTION__) + guidToUString(readUnaligned((const EFI_GUID*)(anotherGuid.constData()))), another);
             }
         }
     }
@@ -1808,7 +1978,7 @@ UINT32 FfsParser::getFileSize(const UByteArray & volume, const UINT32 fileOffset
     return 0;
 }
 
-USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
+USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const bool probe)
 {
     // Sanity check
     if (file.isEmpty()) {
@@ -1834,21 +2004,20 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
     }
     
     // Get file header
-    UByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER));
-    EFI_FFS_FILE_HEADER* tempFileHeader = (EFI_FFS_FILE_HEADER*)header.data();
-    if (tempFileHeader->Attributes & FFS_ATTRIB_LARGE_FILE) {
+    UINT32 headerSize = sizeof(EFI_FFS_FILE_HEADER);
+    const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)file.constData();
+    if (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE) {
         if (ffsVersion == 2 && volumeRevision == 2) {
-            if ((UINT32)file.size() < sizeof(EFI_FFS_FILE_HEADER2_LENOVO))
+            if (headerSize < sizeof(EFI_FFS_FILE_HEADER2_LENOVO))
                 return U_INVALID_FILE;
-            header = file.left(sizeof(EFI_FFS_FILE_HEADER2_LENOVO));
+            headerSize = sizeof(EFI_FFS_FILE_HEADER2_LENOVO);
         }
         if (ffsVersion == 3) {
-            if ((UINT32)file.size() < sizeof(EFI_FFS_FILE_HEADER2))
+            if (headerSize < sizeof(EFI_FFS_FILE_HEADER2))
                 return U_INVALID_FILE;
-            header = file.left(sizeof(EFI_FFS_FILE_HEADER2));
+            headerSize = sizeof(EFI_FFS_FILE_HEADER2);
         }
     }
-    const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)header.constData();
     
     // Check file alignment
     bool msgUnalignedFile = false;
@@ -1858,7 +2027,7 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
     }
     
     UINT32 alignment = (UINT32)(1UL << alignmentPower);
-    if ((localOffset + header.size()) % alignment) {
+    if ((localOffset + headerSize) % alignment) {
         msgUnalignedFile = true;
     }
     
@@ -1869,24 +2038,24 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
     }
     
     // Get file body
-    UByteArray body = file.mid(header.size());
-    
+    UINT32 bodySize = file.size() - headerSize;
+    UINT32 tailSize = 0;
+
     // Check for file tail presence
-    UByteArray tail;
     bool msgInvalidTailValue = false;
+    UINT16 tailValue;
     if (volumeRevision == 1 && (fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT)) {
-        //Check file tail;
-        UINT16 tailValue = *(UINT16*)body.right(sizeof(UINT16)).constData();
+        // Get tail and remove it from file body
+        bodySize -= sizeof(UINT16);
+        tailSize += sizeof(UINT16);
+        // Check file tail;
+        tailValue = *(const UINT16*)(file.constData() + headerSize + bodySize);
         if (fileHeader->IntegrityCheck.TailReference != (UINT16)~tailValue)
             msgInvalidTailValue = true;
-        
-        // Get tail and remove it from file body
-        tail = body.right(sizeof(UINT16));
-        body = body.left(body.size() - sizeof(UINT16));
     }
-    
+
     // Check header checksum
-    UINT8 calculatedHeader = 0x100 - (calculateSum8((const UINT8*)header.constData(), (UINT32)header.size()) - fileHeader->IntegrityCheck.Checksum.Header - fileHeader->IntegrityCheck.Checksum.File - fileHeader->State);
+    UINT8 calculatedHeader = 0x100 - (calculateSum8((const UINT8*)fileHeader, headerSize) - fileHeader->IntegrityCheck.Checksum.Header - fileHeader->IntegrityCheck.Checksum.File - fileHeader->State);
     bool msgInvalidHeaderChecksum = false;
     if (fileHeader->IntegrityCheck.Checksum.Header != calculatedHeader) {
         msgInvalidHeaderChecksum = true;
@@ -1897,7 +2066,7 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
     bool msgInvalidDataChecksum = false;
     UINT8 calculatedData = 0;
     if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM) {
-        calculatedData = calculateChecksum8((const UINT8*)body.constData(), (UINT32)body.size());
+        calculatedData = calculateChecksum8((const UINT8*)(file.constData() + headerSize), bodySize);
     }
     // Data checksum must be one of predefined values
     else if (volumeRevision == 1) {
@@ -1917,6 +2086,25 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
         msgUnknownType = true;
     };
     
+    // If probing, more strict error
+    if (probe) {
+        int errScores = 0;
+        if (msgUnalignedFile)
+            errScores += 1;
+        if (msgFileAlignmentIsGreaterThanVolumeAlignment)
+            errScores += 1;
+        if (msgInvalidHeaderChecksum)
+            errScores += 2;
+        if (msgInvalidDataChecksum)
+            errScores += 2;
+        if (msgInvalidTailValue)
+            errScores += 1;
+        if (msgUnknownType)
+            errScores += 3;
+        if (errScores > 2)
+            return U_INVALID_FILE;
+    }
+
     // Get info
     UString name;
     UString info;
@@ -1930,10 +2118,10 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
     usprintf("\nType: %02Xh\nAttributes: %02Xh\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nTail size: %Xh (%u)\nState: %02Xh",
              fileHeader->Type,
              fileHeader->Attributes,
-             (UINT32)(header.size() + body.size() + tail.size()), (UINT32)(header.size() + body.size() + tail.size()),
-             (UINT32)header.size(), (UINT32)header.size(),
-             (UINT32)body.size(), (UINT32)body.size(),
-             (UINT32)tail.size(), (UINT32)tail.size(),
+             headerSize + bodySize + tailSize, headerSize + bodySize + tailSize,
+             headerSize, headerSize,
+             bodySize, bodySize,
+             tailSize, tailSize,
              fileHeader->State) +
     usprintf("\nHeader checksum: %02Xh", fileHeader->IntegrityCheck.Checksum.Header) + (msgInvalidHeaderChecksum ? usprintf(", invalid, should be %02Xh", calculatedHeader) : UString(", valid")) +
     usprintf("\nData checksum: %02Xh", fileHeader->IntegrityCheck.Checksum.File) + (msgInvalidDataChecksum ? usprintf(", invalid, should be %02Xh", calculatedData) : UString(", valid"));
@@ -1961,7 +2149,11 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
     ItemFixedState fixed = (ItemFixedState)((fileHeader->Attributes & FFS_ATTRIB_FIXED) != 0);
     
     // Add tree item
-    index = model->addItem(localOffset, Types::File, fileHeader->Type, name, text, info, header, body, tail, fixed, parent);
+    index = model->addItem(
+        localOffset, Types::File, fileHeader->Type,
+        name, text, info,
+        headerSize, bodySize, tailSize,
+        fixed, parent);
     
     // Set parsing data for created file
     FILE_PARSING_DATA pdata = {};
@@ -1989,7 +2181,7 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
     if (msgInvalidDataChecksum)
         msg(usprintf("%s: invalid data checksum %02Xh, should be %02Xh", __FUNCTION__, fileHeader->IntegrityCheck.Checksum.File, calculatedData), index);
     if (msgInvalidTailValue)
-        msg(usprintf("%s: invalid tail value %04Xh", __FUNCTION__, *(const UINT16*)tail.constData()), index);
+        msg(usprintf("%s: invalid tail value %04Xh", __FUNCTION__, tailValue), index);
     if (msgUnknownType)
         msg(usprintf("%s: unknown file type %02Xh", __FUNCTION__, fileHeader->Type), index);
     
@@ -2038,7 +2230,7 @@ USTATUS FfsParser::parseFileBody(const UModelIndex & index)
     
     // Parse raw files as raw areas
     if (model->subtype(index) == EFI_FV_FILETYPE_RAW || model->subtype(index) == EFI_FV_FILETYPE_ALL) {
-        UByteArray fileGuid = UByteArray(model->header(index).constData(), sizeof(EFI_GUID));
+        const UByteArray fileGuid(model->header(index).constData(), sizeof(EFI_GUID));
         
         // Parse NVAR store
         if (fileGuid == NVRAM_NVAR_STORE_FILE_GUID) {
@@ -2081,7 +2273,9 @@ USTATUS FfsParser::parseFileBody(const UModelIndex & index)
             return U_SUCCESS;
         }
         
-        return parseRawArea(index);
+        if (parseSections(model->body(index), index, false) != U_SUCCESS) {
+            return parseRawArea(index);
+        }
     }
     
     // Parse sections
@@ -2107,7 +2301,8 @@ USTATUS FfsParser::parsePadFileBody(const UModelIndex & index)
     }
     
     // Check if the while padding file is empty
-    if (body.size() == body.count(emptyByte))
+    auto c = checkSingle(body, (unsigned char)emptyByte);
+    if (c == emptyByte)
         return U_SUCCESS;
     
     // Search for the first non-empty byte
@@ -2120,7 +2315,7 @@ USTATUS FfsParser::parsePadFileBody(const UModelIndex & index)
     }
     
     // Add all bytes before as free space...
-    UINT32 headerSize = (UINT32)model->header(index).size();
+    UINT32 headerSize = (UINT32)model->headerSize(index);
     if (nonEmptyByteOffset >= 8) {
         // Align free space to 8 bytes boundary
         if (nonEmptyByteOffset != ALIGN8(nonEmptyByteOffset))
@@ -2132,7 +2327,11 @@ USTATUS FfsParser::parsePadFileBody(const UModelIndex & index)
         UString info = usprintf("Full size: %Xh (%u)", (UINT32)free.size(), (UINT32)free.size());
         
         // Add tree item
-        model->addItem(headerSize, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), free, UByteArray(), Movable, index);
+        model->addItem(
+            headerSize, Types::FreeSpace, 0,
+            UString("Free space"), UString(), info,
+            0, free.size(), 0,
+            Movable, index);
     }
     else {
         nonEmptyByteOffset = 0;
@@ -2148,7 +2347,11 @@ USTATUS FfsParser::parsePadFileBody(const UModelIndex & index)
         UString info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size());
         
         // Add tree item
-        (void)model->addItem(headerSize + nonEmptyByteOffset, Types::StartupApDataEntry, Subtypes::x86128kStartupApDataEntry, UString("Startup AP data"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
+        model->addItem(
+            headerSize + nonEmptyByteOffset, Types::StartupApDataEntry, Subtypes::x86128kStartupApDataEntry,
+            UString("Startup AP data"), UString(), info,
+            0, padding.size(), 0,
+            Fixed, index);
         
         // Rename the file
         model->setName(index, UString("Startup AP data padding file"));
@@ -2161,7 +2364,11 @@ USTATUS FfsParser::parsePadFileBody(const UModelIndex & index)
         UString info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size());
         
         // Add tree item
-        UModelIndex dataIndex = model->addItem(headerSize + nonEmptyByteOffset, Types::Padding, Subtypes::DataPadding, UString("Non-UEFI data"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
+        UModelIndex dataIndex = model->addItem(
+            headerSize + nonEmptyByteOffset, Types::Padding, Subtypes::DataPadding,
+            UString("Non-UEFI data"), UString(), info,
+            0, padding.size(), 0,
+            Fixed, index);
         
         // Show message
         msg(usprintf("%s: non-UEFI data found in padding file", __FUNCTION__), dataIndex);
@@ -2184,7 +2391,7 @@ USTATUS FfsParser::parseSections(const UByteArray & sections, const UModelIndex
     
     // Search for and parse all sections
     UINT32 bodySize = (UINT32)sections.size();
-    UINT32 headerSize = (UINT32)model->header(index).size();
+    UINT32 headerSize = (UINT32)model->headerSize(index);
     UINT32 sectionOffset = 0;
     USTATUS result = U_SUCCESS;
     
@@ -2209,13 +2416,17 @@ USTATUS FfsParser::parseSections(const UByteArray & sections, const UModelIndex
             // Final parsing
             if (insertIntoTree) {
                 // Add padding to fill the rest of sections
-                UByteArray padding = sections.mid(sectionOffset);
+                UINT32 paddingSize = sections.size() - sectionOffset;
                 
                 // Get info
-                UString info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size());
+                UString info = usprintf("Full size: %Xh (%u)", paddingSize, paddingSize);
                 
                 // Add tree item
-                UModelIndex dataIndex = model->addItem(headerSize + sectionOffset, Types::Padding, Subtypes::DataPadding, UString("Non-UEFI data"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
+                UModelIndex dataIndex = model->addItem(
+                    headerSize + sectionOffset, Types::Padding, Subtypes::DataPadding,
+                    UString("Non-UEFI data"), UString(), info,
+                    0, paddingSize, 0,
+                    Fixed, index);
                 
                 // Show message
                 msg(usprintf("%s: non-UEFI data found in sections area", __FUNCTION__), dataIndex);
@@ -2315,7 +2526,8 @@ USTATUS FfsParser::parseSectionHeader(const UByteArray & section, const UINT32 l
             // Unknown
         default:
             USTATUS result = parseCommonSectionHeader(section, localOffset, parent, index, insertIntoTree);
-            msg(usprintf("%s: section with unknown type %02Xh", __FUNCTION__, sectionHeader->Type), index);
+            if (insertIntoTree)
+                msg(usprintf("%s: section with unknown type %02Xh", __FUNCTION__, sectionHeader->Type), index);
             return result;
     }
 }
@@ -2348,8 +2560,7 @@ USTATUS FfsParser::parseCommonSectionHeader(const UByteArray & section, const UI
         return U_INVALID_SECTION;
     }
     
-    UByteArray header = section.left(headerSize);
-    UByteArray body = section.mid(headerSize);
+    UINT32 bodySize = section.size() - headerSize;
     
     // Get info
     UString name = sectionTypeToUString(type) + UString(" section");
@@ -2357,11 +2568,15 @@ USTATUS FfsParser::parseCommonSectionHeader(const UByteArray & section, const UI
                             type,
                             (UINT32)section.size(), (UINT32)section.size(),
                             headerSize, headerSize,
-                            (UINT32)body.size(), (UINT32)body.size());
+                            bodySize, bodySize);
     
     // Add tree item
     if (insertIntoTree) {
-        index = model->addItem(localOffset, Types::Section, type, name, UString(), info, header, body, UByteArray(), Movable, parent);
+        index = model->addItem(
+            localOffset, Types::Section, type,
+            name, UString(), info,
+            headerSize, bodySize, 0,
+            Movable, parent);
     }
     
     return U_SUCCESS;
@@ -2409,8 +2624,7 @@ USTATUS FfsParser::parseCompressedSectionHeader(const UByteArray & section, cons
         return U_INVALID_SECTION;
     }
     
-    UByteArray header = section.left(headerSize);
-    UByteArray body = section.mid(headerSize);
+    UINT32 bodySize = section.size() - headerSize;
     
     // Get info
     UString name = sectionTypeToUString(sectionHeader->Type) + UString(" section");
@@ -2418,13 +2632,17 @@ USTATUS FfsParser::parseCompressedSectionHeader(const UByteArray & section, cons
                             sectionHeader->Type,
                             (UINT32)section.size(), (UINT32)section.size(),
                             headerSize, headerSize,
-                            (UINT32)body.size(), (UINT32)body.size(),
+                            bodySize, bodySize,
                             compressionType,
                             uncompressedLength, uncompressedLength);
     
     // Add tree item
     if (insertIntoTree) {
-        index = model->addItem(localOffset, Types::Section, sectionHeader->Type, name, UString(), info, header, body, UByteArray(), Movable, parent);
+        index = model->addItem(
+            localOffset, Types::Section, sectionHeader->Type,
+            name, UString(), info,
+            headerSize, bodySize, 0,
+            Movable, parent);
         
         // Set section parsing data
         COMPRESSED_SECTION_PARSING_DATA pdata = {};
@@ -2514,7 +2732,6 @@ USTATUS FfsParser::parseGuidedSectionHeader(const UByteArray & section, const UI
     }
     else if (baGuid == EFI_GUIDED_SECTION_LZMA
         || baGuid == EFI_GUIDED_SECTION_LZMA_HP
-        || baGuid == EFI_GUIDED_SECTION_LZMA_MS
         || baGuid == EFI_GUIDED_SECTION_LZMAF86
         || baGuid == EFI_GUIDED_SECTION_TIANO
         || baGuid == EFI_GUIDED_SECTION_GZIP) {
@@ -2602,8 +2819,7 @@ USTATUS FfsParser::parseGuidedSectionHeader(const UByteArray & section, const UI
         msgProcessingRequiredAttributeOnUnknownGuidedSection = true;
     }
     
-    UByteArray header = section.left(dataOffset);
-    UByteArray body = section.mid(dataOffset);
+    UINT32 bodySize = section.size() - dataOffset;
     
     // Get info
     UString name = guidToUString(guid);
@@ -2611,8 +2827,8 @@ USTATUS FfsParser::parseGuidedSectionHeader(const UByteArray & section, const UI
     usprintf("\nType: %02Xh\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nAttributes: %04Xh",
              sectionHeader->Type,
              (UINT32)section.size(), (UINT32)section.size(),
-             (UINT32)header.size(), (UINT32)header.size(),
-             (UINT32)body.size(), (UINT32)body.size(),
+             dataOffset, dataOffset,
+             bodySize, bodySize,
              attributes);
     
     // Append additional info
@@ -2620,7 +2836,11 @@ USTATUS FfsParser::parseGuidedSectionHeader(const UByteArray & section, const UI
     
     // Add tree item
     if (insertIntoTree) {
-        index = model->addItem(localOffset, Types::Section, sectionHeader->Type, name, UString(), info, header, body, UByteArray(), Movable, parent);
+        index = model->addItem(
+            localOffset, Types::Section, sectionHeader->Type,
+            name, UString(), info,
+            dataOffset, bodySize, 0,
+            Movable, parent);
         
         // Set parsing data
         GUIDED_SECTION_PARSING_DATA pdata = {};
@@ -2692,21 +2912,24 @@ USTATUS FfsParser::parseFreeformGuidedSectionHeader(const UByteArray & section,
     if ((UINT32)section.size() < headerSize)
         return U_INVALID_SECTION;
     
-    UByteArray header = section.left(headerSize);
-    UByteArray body = section.mid(headerSize);
+    UINT32 bodySize = section.size() - headerSize;
     
     // Get info
     UString name = sectionTypeToUString(type) + (" section");
     UString info = usprintf("Type: %02Xh\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nSubtype GUID: ",
                             type,
                             (UINT32)section.size(), (UINT32)section.size(),
-                            (UINT32)header.size(), (UINT32)header.size(),
-                            (UINT32)body.size(), (UINT32)body.size())
+                            headerSize, headerSize,
+                            bodySize, bodySize)
     + guidToUString(guid, false);
     
     // Add tree item
     if (insertIntoTree) {
-        index = model->addItem(localOffset, Types::Section, type, name, UString(), info, header, body, UByteArray(), Movable, parent);
+        index = model->addItem(
+            localOffset, Types::Section, type,
+            name, UString(), info,
+            headerSize, bodySize, 0,
+            Movable, parent);
         
         // Set parsing data
         FREEFORM_GUIDED_SECTION_PARSING_DATA pdata = {};
@@ -2759,21 +2982,24 @@ USTATUS FfsParser::parseVersionSectionHeader(const UByteArray & section, const U
     if ((UINT32)section.size() < headerSize)
         return U_INVALID_SECTION;
     
-    UByteArray header = section.left(headerSize);
-    UByteArray body = section.mid(headerSize);
+    UINT32 bodySize = section.size() - headerSize;
     
     // Get info
     UString name = sectionTypeToUString(type) + (" section");
     UString info = usprintf("Type: %02Xh\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nBuild number: %u",
                             type,
                             (UINT32)section.size(), (UINT32)section.size(),
-                            (UINT32)header.size(), (UINT32)header.size(),
-                            (UINT32)body.size(), (UINT32)body.size(),
+                            headerSize, headerSize,
+                            bodySize, bodySize,
                             buildNumber);
     
     // Add tree item
     if (insertIntoTree) {
-        index = model->addItem(localOffset, Types::Section, type, name, UString(), info, header, body, UByteArray(), Movable, parent);
+        index = model->addItem(
+            localOffset, Types::Section, type,
+            name, UString(), info,
+            headerSize, bodySize, 0,
+            Movable, parent);
     }
     
     return U_SUCCESS;
@@ -2818,21 +3044,24 @@ USTATUS FfsParser::parsePostcodeSectionHeader(const UByteArray & section, const
     if ((UINT32)section.size() < headerSize)
         return U_INVALID_SECTION;
     
-    UByteArray header = section.left(headerSize);
-    UByteArray body = section.mid(headerSize);
+    UINT32 bodySize = section.size() - headerSize;
     
     // Get info
     UString name = sectionTypeToUString(type) + (" section");
     UString info = usprintf("Type: %02Xh\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nPostcode: %Xh",
                             type,
                             (UINT32)section.size(), (UINT32)section.size(),
-                            (UINT32)header.size(), (UINT32)header.size(),
-                            (UINT32)body.size(), (UINT32)body.size(),
+                            headerSize, headerSize,
+                            bodySize, bodySize,
                             postCode);
     
     // Add tree item
     if (insertIntoTree) {
-        index = model->addItem(localOffset, Types::Section, sectionHeader->Type, name, UString(), info, header, body, UByteArray(), Movable, parent);
+        index = model->addItem(
+            localOffset, Types::Section, sectionHeader->Type,
+            name, UString(), info,
+            headerSize, bodySize, 0,
+            Movable, parent);
     }
     
     return U_SUCCESS;
@@ -2883,7 +3112,7 @@ USTATUS FfsParser::parseCompressedSectionBody(const UModelIndex & index)
     
     // Obtain required information from parsing data
     UINT8 compressionType = EFI_NOT_COMPRESSED;
-    UINT32 uncompressedSize = (UINT32)model->body(index).size();
+    UINT32 uncompressedSize = (UINT32)model->bodySize(index);
     if (model->hasEmptyParsingData(index) == false) {
         UByteArray data = model->parsingData(index);
         const COMPRESSED_SECTION_PARSING_DATA* pdata = (const COMPRESSED_SECTION_PARSING_DATA*)data.constData();
@@ -3004,8 +3233,7 @@ USTATUS FfsParser::parseGuidedSectionBody(const UModelIndex & index)
     }
     // LZMA compressed section
     else if (baGuid == EFI_GUIDED_SECTION_LZMA
-             || baGuid == EFI_GUIDED_SECTION_LZMA_HP
-             || baGuid == EFI_GUIDED_SECTION_LZMA_MS) {
+             || baGuid == EFI_GUIDED_SECTION_LZMA_HP) {
         USTATUS result = decompress(model->body(index), EFI_CUSTOMIZED_COMPRESSION, algorithm, dictionarySize, processed, efiDecompressed);
         if (result) {
             msg(usprintf("%s: decompression failed with error ", __FUNCTION__) + errorCodeToUString(result), index);
@@ -3303,13 +3531,28 @@ USTATUS FfsParser::parseRawSectionBody(const UModelIndex & index)
         // Parse AMI vendor hash file
         return parseVendorHashFile(parentFileGuid, index);
     }
-    
+    else if (nvramParser->parseNvarStore(index, true) == U_SUCCESS) {
+        // Rename parent file
+        model->setName(index, UString(sectionTypeToUString(EFI_SECTION_RAW) + " section with NVAR store"));
+        return U_SUCCESS;
+    }
+    else if (parsePeImageSectionBody(index, true) == U_SUCCESS) {
+        // Rename parent file
+        model->setName(index, UString(sectionTypeToUString(EFI_SECTION_RAW) + " section with PE32 image"));
+        return U_SUCCESS;
+    }
+    else if (parseTeImageSectionBody(index, true) == U_SUCCESS) {
+        // Rename parent file
+        model->setName(index, UString(sectionTypeToUString(EFI_SECTION_RAW) + " section with TE image"));
+        return U_SUCCESS;
+    }
+
     // Parse as raw area
     return parseRawArea(index);
 }
 
 
-USTATUS FfsParser::parsePeImageSectionBody(const UModelIndex & index)
+USTATUS FfsParser::parsePeImageSectionBody(const UModelIndex & index, const bool probe)
 {
     // Sanity check
     if (!index.isValid())
@@ -3318,6 +3561,8 @@ USTATUS FfsParser::parsePeImageSectionBody(const UModelIndex & index)
     // Get section body
     UByteArray body = model->body(index);
     if ((UINT32)body.size() < sizeof(EFI_IMAGE_DOS_HEADER)) {
+        if (probe)
+            return U_INVALID_PE_HEADER;
         msg(usprintf("%s: section body size is smaller than DOS header size", __FUNCTION__), index);
         return U_SUCCESS;
     }
@@ -3325,6 +3570,8 @@ USTATUS FfsParser::parsePeImageSectionBody(const UModelIndex & index)
     UString info;
     const EFI_IMAGE_DOS_HEADER* dosHeader = (const EFI_IMAGE_DOS_HEADER*)body.constData();
     if (dosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
+        if (probe)
+            return U_INVALID_PE_HEADER;
         info += usprintf("\nDOS signature: %04Xh, invalid", dosHeader->e_magic);
         msg(usprintf("%s: PE32 image with invalid DOS signature", __FUNCTION__), index);
         model->addInfo(index, info);
@@ -3333,6 +3580,8 @@ USTATUS FfsParser::parsePeImageSectionBody(const UModelIndex & index)
     
     const EFI_IMAGE_PE_HEADER* peHeader = (EFI_IMAGE_PE_HEADER*)(body.constData() + dosHeader->e_lfanew);
     if (body.size() < (UINT8*)peHeader - (UINT8*)dosHeader) {
+        if (probe)
+            return U_INVALID_PE_HEADER;
         info += UString("\nDOS header: invalid");
         msg(usprintf("%s: PE32 image with invalid DOS header", __FUNCTION__), index);
         model->addInfo(index, info);
@@ -3340,6 +3589,8 @@ USTATUS FfsParser::parsePeImageSectionBody(const UModelIndex & index)
     }
     
     if (peHeader->Signature != EFI_IMAGE_PE_SIGNATURE) {
+        if (probe)
+            return U_INVALID_PE_HEADER;
         info += usprintf("\nPE signature: %08Xh, invalid", peHeader->Signature);
         msg(usprintf("%s: PE32 image with invalid PE signature", __FUNCTION__), index);
         model->addInfo(index, info);
@@ -3348,6 +3599,8 @@ USTATUS FfsParser::parsePeImageSectionBody(const UModelIndex & index)
     
     const EFI_IMAGE_FILE_HEADER* imageFileHeader = (const EFI_IMAGE_FILE_HEADER*)(peHeader + 1);
     if (body.size() < (UINT8*)imageFileHeader - (UINT8*)dosHeader) {
+        if (probe)
+            return U_INVALID_PE_HEADER;
         info += UString("\nPE header: invalid");
         msg(usprintf("%s: PE32 image with invalid PE header", __FUNCTION__), index);
         model->addInfo(index, info);
@@ -3365,6 +3618,8 @@ USTATUS FfsParser::parsePeImageSectionBody(const UModelIndex & index)
     EFI_IMAGE_OPTIONAL_HEADER_POINTERS_UNION optionalHeader = {};
     optionalHeader.H32 = (const EFI_IMAGE_OPTIONAL_HEADER32*)(imageFileHeader + 1);
     if (body.size() < (UINT8*)optionalHeader.H32 - (UINT8*)dosHeader) {
+        if (probe)
+            return U_INVALID_PE_HEADER;
         info += UString("\nPE optional header: invalid");
         msg(usprintf("%s: PE32 image with invalid PE optional header", __FUNCTION__), index);
         model->addInfo(index, info);
@@ -3378,6 +3633,11 @@ USTATUS FfsParser::parsePeImageSectionBody(const UModelIndex & index)
                          optionalHeader.H32->AddressOfEntryPoint,
                          optionalHeader.H32->BaseOfCode,
                          optionalHeader.H32->ImageBase);
+        if (!model->compressed(index)) {
+            UINT64 addr = (UINT64)optionalHeader.H32->ImageBase - model->base(index) - model->headerSize(index);
+            if (addr > UEFI_LOWER_INVALID_ADDRESS && addr < UEFI_UPPER_INVALID_ADDRESS)
+                baseAddressesMap[addr]++;
+        }
     }
     else if (optionalHeader.H32->Magic == EFI_IMAGE_PE_OPTIONAL_HDR64_MAGIC) {
         info += usprintf("\nOptional header signature: %04Xh\nSubsystem: %04Xh\nAddress of entry point: %Xh\nBase of code: %Xh\nImage base: %" PRIX64 "h",
@@ -3386,8 +3646,15 @@ USTATUS FfsParser::parsePeImageSectionBody(const UModelIndex & index)
                          optionalHeader.H64->AddressOfEntryPoint,
                          optionalHeader.H64->BaseOfCode,
                          optionalHeader.H64->ImageBase);
+        if (!model->compressed(index)) {
+            UINT64 addr = (UINT64)optionalHeader.H32->ImageBase - model->base(index) - model->headerSize(index);
+            if (addr > UEFI_LOWER_INVALID_ADDRESS && addr < UEFI_UPPER_INVALID_ADDRESS)
+                baseAddressesMap[addr]++;
+        }
     }
     else {
+        if (probe)
+            return U_INVALID_PE_HEADER;
         info += usprintf("\nOptional header signature: %04Xh, unknown", optionalHeader.H32->Magic);
         msg(usprintf("%s: PE32 image with invalid optional PE header signature", __FUNCTION__), index);
     }
@@ -3397,7 +3664,7 @@ USTATUS FfsParser::parsePeImageSectionBody(const UModelIndex & index)
 }
 
 
-USTATUS FfsParser::parseTeImageSectionBody(const UModelIndex & index)
+USTATUS FfsParser::parseTeImageSectionBody(const UModelIndex & index, const bool probe)
 {
     // Check sanity
     if (!index.isValid())
@@ -3406,6 +3673,8 @@ USTATUS FfsParser::parseTeImageSectionBody(const UModelIndex & index)
     // Get section body
     UByteArray body = model->body(index);
     if ((UINT32)body.size() < sizeof(EFI_IMAGE_TE_HEADER)) {
+        if (probe)
+            return U_INVALID_TE_HEADER;
         msg(usprintf("%s: section body size is smaller than TE header size", __FUNCTION__), index);
         return U_SUCCESS;
     }
@@ -3413,6 +3682,8 @@ USTATUS FfsParser::parseTeImageSectionBody(const UModelIndex & index)
     UString info;
     const EFI_IMAGE_TE_HEADER* teHeader = (const EFI_IMAGE_TE_HEADER*)body.constData();
     if (teHeader->Signature != EFI_IMAGE_TE_SIGNATURE) {
+        if (probe)
+            return U_INVALID_TE_HEADER;
         info += usprintf("\nSignature: %04Xh, invalid", teHeader->Signature);
         msg(usprintf("%s: TE image with invalid TE signature", __FUNCTION__), index);
     }
@@ -3428,6 +3699,12 @@ USTATUS FfsParser::parseTeImageSectionBody(const UModelIndex & index)
                  teHeader->AddressOfEntryPoint,
                  teHeader->ImageBase,
                  teHeader->ImageBase + teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER));
+        if (!model->compressed(index)) {
+            UINT64 addr = (UINT64)teHeader->ImageBase + teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER)
+                - model->base(index) - model->headerSize(index);
+            if (addr > UEFI_LOWER_INVALID_ADDRESS && addr < UEFI_UPPER_INVALID_ADDRESS)
+                baseAddressesMap[addr]++;
+        }
     }
     
     // Update parsing data
@@ -3457,8 +3734,9 @@ USTATUS FfsParser::performSecondPass(const UModelIndex & index)
     }
     
     // Calculate address difference
-    const UINT32 vtfSize = (UINT32)(model->header(lastVtf).size() + model->body(lastVtf).size() + model->tail(lastVtf).size());
-    addressDiff = 0xFFFFFFFFULL - model->base(lastVtf) - vtfSize + 1;
+    const UINT32 vtfSize = (UINT32)(model->headerSize(lastVtf) + model->bodySize(lastVtf) + model->tailSize(lastVtf));
+    if (addressDiff >= UEFI_UPPER_INVALID_ADDRESS)
+        addressDiff = UEFI_UPPER_INVALID_ADDRESS - model->base(lastVtf) - vtfSize;
     
     // Parse reset vector data
     parseResetVectorData();
@@ -3531,7 +3809,7 @@ USTATUS FfsParser::checkTeImageBase(const UModelIndex & index)
         if (originalImageBase != 0 || adjustedImageBase != 0) {
             // Check data memory address to be equal to either OriginalImageBase or AdjustedImageBase
             UINT64 address = addressDiff + model->base(index);
-            UINT32 base = (UINT32)(address + model->header(index).size());
+            UINT32 base = (UINT32)(address + model->headerSize(index));
             
             if (originalImageBase == base) {
                 imageBaseType = EFI_IMAGE_TE_BASE_ORIGINAL;
@@ -3586,11 +3864,14 @@ USTATUS FfsParser::addInfoRecursive(const UModelIndex & index)
     
     // Add current base if the element is not compressed
     // or it's compressed, but its parent isn't
-    if ((!model->compressed(index)) || (index.parent().isValid() && !model->compressed(index.parent()))) {
+    if (!model->compressed(index) || (index.parent().isValid() && !model->compressed(index.parent()))) {
         // Add physical address of the whole item or its header and data portions separately
         UINT64 address = addressDiff + model->base(index);
-        if (address <= 0xFFFFFFFFUL) {
-            UINT32 headerSize = (UINT32)model->header(index).size();
+        if (model->type(index) != Types::Capsule && address < UEFI_UPPER_INVALID_ADDRESS
+            && ((biosRegionInfo.type != Subtypes::BiosRegion && address >= UEFI_LOWER_INVALID_ADDRESS)
+                || (biosRegionInfo.type == Subtypes::BiosRegion && address >= (UEFI_UPPER_INVALID_ADDRESS - biosRegionInfo.length))))
+        {
+            UINT32 headerSize = (UINT32)model->headerSize(index);
             if (headerSize) {
                 model->addInfo(index, usprintf("Data address: %08Xh\n", (UINT32)address + headerSize),false);
                 model->addInfo(index, usprintf("Header address: %08Xh\n", (UINT32)address), false);
@@ -3700,7 +3981,7 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index)
                 else {
                     try {
                         protectedRanges[i].Offset = model->base(dxeRootVolumeIndex);
-                        protectedRanges[i].Size = (UINT32)(model->header(dxeRootVolumeIndex).size() + model->body(dxeRootVolumeIndex).size() + model->tail(dxeRootVolumeIndex).size());
+                        protectedRanges[i].Size = (UINT32)(model->headerSize(dxeRootVolumeIndex) + model->bodySize(dxeRootVolumeIndex) + model->tailSize(dxeRootVolumeIndex));
                         protectedParts = openedImage.mid(protectedRanges[i].Offset, protectedRanges[i].Size);
                         
                         // Calculate the hash
@@ -3908,26 +4189,6 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index)
                 // Do nothing, this range is likely not found in the image
             }
         }
-        else if (protectedRanges[i].Type == PROTECTED_RANGE_VENDOR_HASH_INSYDE) {
-            try {
-                protectedRanges[i].Offset -= (UINT32)addressDiff;
-                protectedParts = openedImage.mid(protectedRanges[i].Offset, protectedRanges[i].Size);
-                
-                UByteArray digest(SHA256_HASH_SIZE, '\x00');
-                sha256(protectedParts.constData(), protectedParts.size(), digest.data());
-                
-                if (digest != protectedRanges[i].Hash) {
-                    msg(usprintf("%s: Insyde protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot", __FUNCTION__,
-                                 protectedRanges[i].Offset, protectedRanges[i].Offset + protectedRanges[i].Size),
-                        model->findByBase(protectedRanges[i].Offset));
-                }
-                
-                markProtectedRangeRecursive(index, protectedRanges[i]);
-            }
-            catch(...) {
-                // Do nothing, this range is likely not found in the image
-            }
-        }
     }
     
     return U_SUCCESS;
@@ -3946,7 +4207,7 @@ USTATUS FfsParser::markProtectedRangeRecursive(const UModelIndex & index, const
     // Mark normal items
     else {
         UINT32 currentOffset = model->base(index);
-        UINT32 currentSize = (UINT32)(model->header(index).size() + model->body(index).size() + model->tail(index).size());
+        UINT32 currentSize = (UINT32)(model->headerSize(index) + model->bodySize(index) + model->tailSize(index));
         
         if (std::min(currentOffset + currentSize, range.Offset + range.Size) > std::max(currentOffset, range.Offset)) {
             if (range.Offset <= currentOffset && currentOffset + currentSize <= range.Offset + range.Size) { // Mark as fully in range
@@ -4148,8 +4409,8 @@ USTATUS FfsParser::parseVendorHashFile(const UByteArray & fileGuid, const UModel
 
 USTATUS FfsParser::parseMicrocodeVolumeBody(const UModelIndex & index)
 {
-    const UINT32 headerSize = (UINT32)model->header(index).size();
-    const UINT32 bodySize = (UINT32)model->body(index).size();
+    const UINT32 headerSize = (UINT32)model->headerSize(index);
+    const UINT32 bodySize = (UINT32)model->bodySize(index);
     UINT32 offset = 0;
     USTATUS result = U_SUCCESS;
     
@@ -4159,7 +4420,8 @@ USTATUS FfsParser::parseMicrocodeVolumeBody(const UModelIndex & index)
         UByteArray ucode = model->body(index).mid(offset);
         
         // Check for empty area
-        if (ucode.size() == ucode.count('\xFF') || ucode.size() == ucode.count('\x00')) {
+        auto c = checkSingle(ucode);
+        if (c == 0 || c == 0xFF) {
             result = U_INVALID_MICROCODE;
         }
         else {
@@ -4174,13 +4436,17 @@ USTATUS FfsParser::parseMicrocodeVolumeBody(const UModelIndex & index)
                 UString info = usprintf("Full size: %Xh (%u)", (UINT32)ucode.size(), (UINT32)ucode.size());
                 
                 // Add tree item
-                model->addItem(headerSize + offset, Types::Padding, getPaddingType(ucode), name, UString(), info, UByteArray(), ucode, UByteArray(), Fixed, index);
+                model->addItem(
+                    headerSize + offset, Types::Padding, getPaddingType(ucode),
+                    name, UString(), info,
+                    0, ucode.size(), 0,
+                    Fixed, index);
             }
             return U_SUCCESS;
         }
         
         // Get to next candidate
-        offset += model->header(currentMicrocode).size() + model->body(currentMicrocode).size() + model->tail(currentMicrocode).size();
+        offset += model->headerSize(currentMicrocode) + model->bodySize(currentMicrocode) + model->tailSize(currentMicrocode);
         if (offset >= bodySize)
             break;
     }
@@ -4268,15 +4534,15 @@ USTATUS FfsParser::parseIntelMicrocodeHeader(const UByteArray & microcode, const
                 
                 // Recalculate checksum after patching
                 tempUcodeHeader->Checksum = 0;
-                tempUcodeHeader->ProcessorFlags = entry->ProcessorFlags;
+                tempUcodeHeader->PlatformIds = entry->PlatformIds;
                 tempUcodeHeader->ProcessorSignature = entry->ProcessorSignature;
                 UINT32 entryCalculated = calculateChecksum32((const UINT32*)tempMicrocode.constData(), sizeof(INTEL_MICROCODE_HEADER) + dataSize);
-                
-                extendedHeaderInfo += usprintf("\nCPU signature #%u: %08Xh\nCPU flags #%u: %02Xh\nChecksum #%u: %08Xh, ",
-                                               i + 1, entry->ProcessorSignature,
-                                               i + 1, entry->ProcessorFlags,
-                                               i + 1, entry->Checksum)
-                + (entry->Checksum == entryCalculated ? UString("valid") : usprintf("invalid, should be %08Xh", entryCalculated));
+
+                extendedHeaderInfo += usprintf("\nCPU signature #%u: %08Xh\nCPU platform Id #%u: %08Xh\nChecksum #%u: %08Xh, ",
+                    i + 1, entry->ProcessorSignature,
+                    i + 1, entry->PlatformIds,
+                    i + 1, entry->Checksum)
+                    + (entry->Checksum == entryCalculated ? UString("valid") : usprintf("invalid, should be %08Xh", entryCalculated));
             }
         }
         else {
@@ -4288,26 +4554,31 @@ USTATUS FfsParser::parseIntelMicrocodeHeader(const UByteArray & microcode, const
     }
     
     // Get microcode binary
-    UByteArray microcodeBinary = microcode.left(ucodeHeader->TotalSize);
+    UINT32 microcodeBinarySize = microcode.size() < ucodeHeader->TotalSize ? microcode.size() : ucodeHeader->TotalSize;
     
     // Add info
     UString name("Intel microcode");
     UString info = usprintf("Full size: %Xh (%u)\nHeader size: 0h (0u)\nBody size: %Xh (%u)\nTail size: 0h (0u)\n"
-                            "Date: %02X.%02X.%04x\nCPU signature: %08Xh\nRevision: %08Xh\nCPU flags: %02Xh\nChecksum: %08Xh, ",
-                            (UINT32)microcodeBinary.size(), (UINT32)microcodeBinary.size(),
-                            (UINT32)microcodeBinary.size(), (UINT32)microcodeBinary.size(),
+                            "Date: %02X.%02X.%04x\nCPU signature: %08Xh\nRevision: %08Xh\nMinimal update revision: %08Xh\nCPU platform Id: %08Xh\nChecksum: %08Xh, ",
+                            microcodeBinarySize, microcodeBinarySize,
+                            microcodeBinarySize, microcodeBinarySize,
                             ucodeHeader->DateDay,
                             ucodeHeader->DateMonth,
                             ucodeHeader->DateYear,
                             ucodeHeader->ProcessorSignature,
                             ucodeHeader->UpdateRevision,
-                            ucodeHeader->ProcessorFlags,
+                            ucodeHeader->UpdateRevisionMin,
+                            ucodeHeader->PlatformIds,
                             ucodeHeader->Checksum)
     + (ucodeHeader->Checksum == calculated ? UString("valid") : usprintf("invalid, should be %08Xh", calculated))
     + extendedHeaderInfo;
     
     // Add tree item
-    index = model->addItem(localOffset, Types::Microcode, Subtypes::IntelMicrocode, name, UString(), info, UByteArray(), microcodeBinary, UByteArray(), Fixed, parent);
+    index = model->addItem(
+        localOffset, Types::Microcode, Subtypes::IntelMicrocode,
+        name, UString(), info,
+        0, microcodeBinarySize, 0,
+        Fixed, parent);
     if (msgInvalidChecksum)
         msg(usprintf("%s: invalid microcode checksum %08Xh, should be %08Xh", __FUNCTION__, ucodeHeader->Checksum, calculated), index);
     if (msgUnknownOrDamagedMicrocodeTail)
@@ -4339,15 +4610,14 @@ USTATUS FfsParser::parseBpdtRegion(const UByteArray & region, const UINT32 local
     }
     
     // Get info
-    UByteArray header = region.left(sizeof(BPDT_HEADER));
-    UByteArray body = region.mid(sizeof(BPDT_HEADER), ptBodySize);
+    UINT32 headerSize = sizeof(BPDT_HEADER);
     
     UString name = UString("BPDT partition table");
     UString info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\n"
                             "Number of entries: %u\nVersion: %02Xh\nRedundancyFlag: %Xh\n"
                             "IFWI version: %Xh\nFITC version: %u.%u.%u.%u",
                             ptSize, ptSize,
-                            (UINT32)header.size(), (UINT32)header.size(),
+                            headerSize, headerSize,
                             ptBodySize, ptBodySize,
                             ptHeader->NumEntries,
                             ptHeader->HeaderVersion,
@@ -4356,7 +4626,11 @@ USTATUS FfsParser::parseBpdtRegion(const UByteArray & region, const UINT32 local
                             ptHeader->FitcMajor, ptHeader->FitcMinor, ptHeader->FitcHotfix, ptHeader->FitcBuild);
     
     // Add tree item
-    index = model->addItem(localOffset, Types::BpdtStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
+    index = model->addItem(
+        localOffset, Types::BpdtStore, 0,
+        name, UString(), info,
+        headerSize, ptBodySize, 0,
+        Fixed, parent);
     
     // Adjust offset
     UINT32 offset = sizeof(BPDT_HEADER);
@@ -4382,7 +4656,11 @@ USTATUS FfsParser::parseBpdtRegion(const UByteArray & region, const UINT32 local
         UString("\nUMA cacheable: ") + (ptEntry->UmaCacheable ? "Yes" : "No");
         
         // Add tree item
-        UModelIndex entryIndex = model->addItem(localOffset + offset, Types::BpdtEntry, 0, name, UString(), info, UByteArray(), UByteArray((const char*)ptEntry, sizeof(BPDT_ENTRY)), UByteArray(), Fixed, index);
+        UModelIndex entryIndex = model->addItem(
+            localOffset + offset, Types::BpdtEntry, 0,
+            name, UString(), info,
+            0, sizeof(BPDT_ENTRY), 0,
+            Fixed, index);
         
         // Adjust offset
         offset += sizeof(BPDT_ENTRY);
@@ -4496,7 +4774,11 @@ make_partition_table_consistent:
             UString text = bpdtEntryTypeToUString(partitions[i].ptEntry.Type);
             
             // Add tree item
-            UModelIndex partitionIndex = model->addItem(localOffset + partitions[i].ptEntry.Offset, Types::BpdtPartition, 0, name, text, info, UByteArray(), partition, UByteArray(), Fixed, parent);
+            UModelIndex partitionIndex = model->addItem(
+                localOffset + partitions[i].ptEntry.Offset, Types::BpdtPartition, 0,
+                name, text, info,
+                0, partition.size(), 0,
+                Fixed, parent);
             
             // Special case of S-BPDT
             if (partitions[i].ptEntry.Type == BPDT_ENTRY_TYPE_S_BPDT) {
@@ -4525,7 +4807,11 @@ make_partition_table_consistent:
                             (UINT32)padding.size(), (UINT32)padding.size());
             
             // Add tree item
-            model->addItem(localOffset + partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, parent);
+            model->addItem(
+                localOffset + partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(padding),
+                name, UString(), info,
+                0, padding.size(), 0,
+                Fixed, parent);
         }
     }
     
@@ -4540,7 +4826,11 @@ make_partition_table_consistent:
                         (UINT32)padding.size(), (UINT32)padding.size());
         
         // Add tree item
-        model->addItem(localOffset + partitions.back().ptEntry.Offset + partitions.back().ptEntry.Size, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, parent);
+        model->addItem(
+            localOffset + partitions.back().ptEntry.Offset + partitions.back().ptEntry.Size, Types::Padding, getPaddingType(padding),
+            name, UString(), info,
+            0, padding.size(), 0,
+            Fixed, parent);
     }
     
     return U_SUCCESS;
@@ -4580,40 +4870,45 @@ USTATUS FfsParser::parseCpdRegion(const UByteArray & region, const UINT32 localO
     }
     
     // Get info
-    UByteArray header = region.left(ptHeaderSize);
-    UByteArray body = region.mid(ptHeaderSize, ptBodySize);
     UString name = usprintf("CPD partition table");
     UString info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nNumber of entries: %u\n"
                             "Header version: %u\nEntry version: %u",
                             ptSize, ptSize,
-                            (UINT32)header.size(), (UINT32)header.size(),
-                            (UINT32)body.size(), (UINT32)body.size(),
+                            ptHeaderSize, ptHeaderSize,
+                            ptBodySize, ptBodySize,
                             cpdHeader->NumEntries,
                             cpdHeader->HeaderVersion,
                             cpdHeader->EntryVersion);
     
     // Add tree item
-    index = model->addItem(localOffset, Types::CpdStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
+    index = model->addItem(
+        localOffset, Types::CpdStore, 0,
+        name, UString(), info,
+        ptHeaderSize, ptBodySize, 0,
+        Fixed, parent);
     
     // Add partition table entries
     std::vector<CPD_PARTITION_INFO> partitions;
     UINT32 offset = ptHeaderSize;
-    const CPD_ENTRY* firstCpdEntry = (const CPD_ENTRY*)(body.constData());
+    const CPD_ENTRY* firstCpdEntry = (const CPD_ENTRY*)(region.constData() + ptHeaderSize);
     for (UINT32 i = 0; i < cpdHeader->NumEntries; i++) {
         // Populate entry header
         const CPD_ENTRY* cpdEntry = firstCpdEntry + i;
-        UByteArray entry((const char*)cpdEntry, sizeof(CPD_ENTRY));
         
         // Get info
         name = usprintf("%.12s", cpdEntry->EntryName);
         info = usprintf("Full size: %Xh (%u)\nEntry offset: %Xh\nEntry length: %Xh\nHuffman compressed: ",
-                        (UINT32)entry.size(), (UINT32)entry.size(),
+                        sizeof(CPD_ENTRY), sizeof(CPD_ENTRY),
                         cpdEntry->Offset.Offset,
                         cpdEntry->Length)
         + (cpdEntry->Offset.HuffmanCompressed ? "Yes" : "No");
         
         // Add tree item
-        UModelIndex entryIndex = model->addItem(offset, Types::CpdEntry, 0, name, UString(), info, UByteArray(), entry, UByteArray(), Fixed, index);
+        UModelIndex entryIndex = model->addItem(
+            offset, Types::CpdEntry, 0,
+            name, UString(), info,
+            0, sizeof(CPD_ENTRY), 0,
+            Fixed, index);
         
         // Adjust offset
         offset += sizeof(CPD_ENTRY);
@@ -4639,7 +4934,11 @@ USTATUS FfsParser::parseCpdRegion(const UByteArray & region, const UINT32 localO
                         (UINT32)partition.size(), (UINT32)partition.size());
         
         // Add tree item
-        model->addItem(localOffset + ptSize, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
+        model->addItem(
+            localOffset + ptSize, Types::Padding, getPaddingType(partition),
+            name, UString(), info,
+            0, partition.size(), 0,
+            Fixed, parent);
         
         return U_SUCCESS;
     }
@@ -4815,15 +5114,15 @@ make_partition_table_consistent:
                     && partitions[i].ptEntry.Length >= sizeof(CPD_MANIFEST_HEADER)) {
                     const CPD_MANIFEST_HEADER* manifestHeader = (const CPD_MANIFEST_HEADER*) partition.constData();
                     if (manifestHeader->HeaderId == ME_MANIFEST_HEADER_ID) {
-                        UByteArray header = partition.left(manifestHeader->HeaderLength * sizeof(UINT32));
-                        UByteArray body = partition.mid(manifestHeader->HeaderLength * sizeof(UINT32));
+                        UINT32 headerSize = manifestHeader->HeaderLength * sizeof(UINT32);
+                        UINT32 bodySize = partition.size() - headerSize;
                         
                         info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)"
                                         "\nHeader type: %u\nHeader length: %Xh (%u)\nHeader version: %Xh\nFlags: %08Xh\nVendor: %Xh\n"
                                         "Date: %Xh\nSize: %Xh (%u)\nVersion: %u.%u.%u.%u\nSecurity version number: %u\nModulus size: %Xh (%u)\nExponent size: %Xh (%u)",
                                         (UINT32)partition.size(), (UINT32)partition.size(),
-                                        (UINT32)header.size(), (UINT32)header.size(),
-                                        (UINT32)body.size(), (UINT32)body.size(),
+                                        headerSize, headerSize,
+                                        bodySize, bodySize,
                                         manifestHeader->HeaderType,
                                         manifestHeader->HeaderLength * (UINT32)sizeof(UINT32), manifestHeader->HeaderLength * (UINT32)sizeof(UINT32),
                                         manifestHeader->HeaderVersion,
@@ -4837,12 +5136,17 @@ make_partition_table_consistent:
                                         manifestHeader->ExponentSize * (UINT32)sizeof(UINT32), manifestHeader->ExponentSize * (UINT32)sizeof(UINT32));
                         
                         // Add tree item
-                        UModelIndex partitionIndex = model->addItem(localOffset + partitions[i].ptEntry.Offset.Offset, Types::CpdPartition, Subtypes::ManifestCpdPartition, name, UString(), info, header, body, UByteArray(), Fixed, parent);
+                        UModelIndex partitionIndex = model->addItem(
+                            localOffset + partitions[i].ptEntry.Offset.Offset, Types::CpdPartition, Subtypes::ManifestCpdPartition,
+                            name, UString(), info,
+                            headerSize, bodySize, 0,
+                            Fixed, parent);
                         
                         // Parse data as extensions area
-                        // Add the header size as a local offset
-                        // Since the body starts after the header length
-                        parseCpdExtensionsArea(partitionIndex, (UINT32)header.size());
+			// Add the header size as a local offset
+			// Since the body starts after the
+			// header length
+                        parseCpdExtensionsArea(partitionIndex, headerSize);
                     }
                 }
             }
@@ -4858,7 +5162,11 @@ make_partition_table_consistent:
                 info += UString("\nMetadata hash: ") + UString(hash.toHex().constData());
                 
                 // Add three item
-                UModelIndex partitionIndex = model->addItem(localOffset + partitions[i].ptEntry.Offset.Offset, Types::CpdPartition,  Subtypes::MetadataCpdPartition, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
+                UModelIndex partitionIndex = model->addItem(
+                    localOffset + partitions[i].ptEntry.Offset.Offset, Types::CpdPartition,  Subtypes::MetadataCpdPartition,
+                    name, UString(), info,
+                    0, partition.size(), 0,
+                    Fixed, parent);
                 
                 // Parse data as extensions area
                 parseCpdExtensionsArea(partitionIndex, 0);
@@ -4874,7 +5182,11 @@ make_partition_table_consistent:
                 sha256(partition.constData(), partition.size(), hash.data());
                 info += UString("\nHash: ") + UString(hash.toHex().constData());
                 
-                UModelIndex codeIndex = model->addItem(localOffset + partitions[i].ptEntry.Offset.Offset, Types::CpdPartition, Subtypes::CodeCpdPartition, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
+                UModelIndex codeIndex = model->addItem(
+                    localOffset + partitions[i].ptEntry.Offset.Offset, Types::CpdPartition, Subtypes::CodeCpdPartition,
+                    name, UString(), info,
+                    0, partition.size(), 0,
+                    Fixed, parent);
                 (void)parseRawArea(codeIndex);
             }
         }
@@ -4886,7 +5198,11 @@ make_partition_table_consistent:
             info = usprintf("Full size: %Xh (%u)", (UINT32)partition.size(), (UINT32)partition.size());
             
             // Add tree item
-            model->addItem(localOffset + partitions[i].ptEntry.Offset.Offset, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
+            model->addItem(
+                localOffset + partitions[i].ptEntry.Offset.Offset, Types::Padding, getPaddingType(partition),
+                name, UString(), info,
+                0, partition.size(), 0,
+                Fixed, parent);
         }
         else {
             msg(usprintf("%s: CPD partition of unknown type found", __FUNCTION__), parent);
@@ -4917,17 +5233,17 @@ USTATUS FfsParser::parseCpdExtensionsArea(const UModelIndex & index, const UINT3
             // Parse Signed Package Info a bit further
             UModelIndex extIndex;
             if (extHeader->Type == CPD_EXT_TYPE_SIGNED_PACKAGE_INFO) {
-                UByteArray header = partition.left(sizeof(CPD_EXT_SIGNED_PACKAGE_INFO));
-                UByteArray data = partition.mid(header.size());
+                UINT32 headerSize = sizeof(CPD_EXT_SIGNED_PACKAGE_INFO);
+                UINT32 bodySize = partition.size() - headerSize;
                 
-                const CPD_EXT_SIGNED_PACKAGE_INFO* infoHeader = (const CPD_EXT_SIGNED_PACKAGE_INFO*)header.constData();
+                const CPD_EXT_SIGNED_PACKAGE_INFO* infoHeader = (const CPD_EXT_SIGNED_PACKAGE_INFO*)partition.constData();
                 
                 info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %Xh\n"
                                 "Package name: %.4s\nVersion control number: %Xh\nSecurity version number: %Xh\n"
                                 "Usage bitmap: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
                                 (UINT32)partition.size(), (UINT32)partition.size(),
-                                (UINT32)header.size(), (UINT32)header.size(),
-                                (UINT32)body.size(), (UINT32)body.size(),
+                                headerSize, headerSize,
+                                bodySize, bodySize,
                                 infoHeader->ExtensionType,
                                 infoHeader->PackageName,
                                 infoHeader->Vcn,
@@ -4938,7 +5254,11 @@ USTATUS FfsParser::parseCpdExtensionsArea(const UModelIndex & index, const UINT3
                                 infoHeader->UsageBitmap[12], infoHeader->UsageBitmap[13], infoHeader->UsageBitmap[14], infoHeader->UsageBitmap[15]);
                 
                 // Add tree item
-                extIndex = model->addItem(offset + localOffset, Types::CpdExtension, 0, name, UString(), info, header, data, UByteArray(), Fixed, index);
+                extIndex = model->addItem(
+                    offset + localOffset, Types::CpdExtension, 0,
+                    name, UString(), info,
+                    headerSize, bodySize, 0,
+                    Fixed, index);
                 parseSignedPackageInfoData(extIndex);
             }
             // Parse IFWI Partition Manifest a bit further
@@ -4981,7 +5301,11 @@ USTATUS FfsParser::parseCpdExtensionsArea(const UModelIndex & index, const UINT3
                 + UString("\nPartition hash: ") +  UString(hash.toHex().constData());
                 
                 // Add tree item
-                extIndex = model->addItem(offset + localOffset, Types::CpdExtension, 0, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, index);
+                extIndex = model->addItem(
+                    offset + localOffset, Types::CpdExtension, 0,
+                    name, UString(), info,
+                    0, partition.size(), 0,
+                    Fixed, index);
                 if (msgHashSizeMismatch) {
                     msg(usprintf("%s: IFWI Partition Manifest hash size is %u, maximum allowed is %u, truncated", __FUNCTION__, attrHeader->HashSize, (UINT32)sizeof(attrHeader->CompletePartitionHash)), extIndex);
                 }
@@ -5006,12 +5330,20 @@ USTATUS FfsParser::parseCpdExtensionsArea(const UModelIndex & index, const UINT3
                                 attrHeader->GlobalModuleId) + UString(hash.toHex().constData());
                 
                 // Add tree item
-                extIndex = model->addItem(offset + localOffset, Types::CpdExtension, 0, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, index);
+                extIndex = model->addItem(
+                    offset + localOffset, Types::CpdExtension, 0,
+                    name, UString(), info,
+                    0, partition.size(), 0,
+                    Fixed, index);
             }
             // Parse everything else
             else {
                 // Add tree item, if needed
-                extIndex = model->addItem(offset + localOffset, Types::CpdExtension, 0, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, index);
+                extIndex = model->addItem(
+                    offset + localOffset, Types::CpdExtension, 0,
+                    name, UString(), info,
+                    0, partition.size(), 0,
+                    Fixed, index);
             }
             
             // There needs to be a more generic way to do it, but it is fine for now
@@ -5045,7 +5377,7 @@ USTATUS FfsParser::parseSignedPackageInfoData(const UModelIndex & index)
         const CPD_EXT_SIGNED_PACKAGE_INFO_MODULE* moduleHeader = (const CPD_EXT_SIGNED_PACKAGE_INFO_MODULE*)(body.constData() + offset);
         if (sizeof(CPD_EXT_SIGNED_PACKAGE_INFO_MODULE) <= ((UINT32)body.size() - offset)) {
             // TODO: check sanity of moduleHeader->HashSize
-            UByteArray module((const char*)moduleHeader, CpdExtSignedPkgMetadataHashOffset + moduleHeader->HashSize);
+            UINT32 moduleSize = CpdExtSignedPkgMetadataHashOffset + moduleHeader->HashSize;
             UString name = usprintf("%.12s", moduleHeader->Name);
             
             // This hash is stored reversed
@@ -5054,14 +5386,18 @@ USTATUS FfsParser::parseSignedPackageInfoData(const UModelIndex & index)
             std::reverse(hash.begin(), hash.end());
             
             UString info = usprintf("Full size: %Xh (%u)\nType: %Xh\nHash algorithm: %Xh\nHash size: %Xh (%u)\nMetadata size: %Xh (%u)\nMetadata hash: ",
-                                    (UINT32)module.size(), (UINT32)module.size(),
+                                    moduleSize, moduleSize,
                                     moduleHeader->Type,
                                     moduleHeader->HashAlgorithm,
                                     moduleHeader->HashSize, moduleHeader->HashSize,
                                     moduleHeader->MetadataSize, moduleHeader->MetadataSize) + UString(hash.toHex().constData());
             // Add tree otem
-            model->addItem(offset, Types::CpdSpiEntry, 0, name, UString(), info, UByteArray(), module, UByteArray(), Fixed, index);
-            offset += module.size();
+            model->addItem(
+                offset, Types::CpdSpiEntry, 0,
+                name, UString(), info,
+                0, moduleSize, 0,
+                Fixed, index);
+            offset += moduleSize;
         }
         else break;
         // TODO: add padding at the end
diff --git a/common/ffsparser.h b/common/ffsparser.h
index ef7ccc4..fcf6038 100644
--- a/common/ffsparser.h
+++ b/common/ffsparser.h
@@ -14,6 +14,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #define FFSPARSER_H
 
 #include <vector>
+#include <unordered_map>
 
 #include "basetypes.h"
 #include "ustring.h"
@@ -115,6 +116,8 @@ private:
     UModelIndex lastVtf;
     UINT32 imageBase;
     UINT64 addressDiff;
+    REGION_INFO biosRegionInfo;
+    std::unordered_map<UINT64, int> baseAddressesMap;
     
     UString securityInfo;
 
@@ -126,6 +129,7 @@ private:
     USTATUS performFirstPass(const UByteArray & imageFile, UModelIndex & index);
 
     USTATUS parseCapsule(const UByteArray & capsule, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
+    USTATUS parseImage(const UByteArray& buffer, const UINT32 localOffset, const UModelIndex& parent, UModelIndex& index);
     USTATUS parseIntelImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
     USTATUS parseGenericImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
 
@@ -136,9 +140,9 @@ private:
     
     USTATUS parseRawArea(const UModelIndex & index);
     USTATUS parseVolumeHeader(const UByteArray & volume, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
-    USTATUS parseVolumeBody(const UModelIndex & index);
+    USTATUS parseVolumeBody(const UModelIndex & index, const bool probe = false);
     USTATUS parseMicrocodeVolumeBody(const UModelIndex & index);
-    USTATUS parseFileHeader(const UByteArray & file, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
+    USTATUS parseFileHeader(const UByteArray & file, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const bool probe = false);
     USTATUS parseFileBody(const UModelIndex & index);
     USTATUS parseSectionHeader(const UByteArray & section, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const bool insertIntoTree);
     USTATUS parseSectionBody(const UModelIndex & index);
@@ -167,8 +171,8 @@ private:
     USTATUS parseDepexSectionBody(const UModelIndex & index);
     USTATUS parseUiSectionBody(const UModelIndex & index);
     USTATUS parseRawSectionBody(const UModelIndex & index);
-    USTATUS parsePeImageSectionBody(const UModelIndex & index);
-    USTATUS parseTeImageSectionBody(const UModelIndex & index);
+    USTATUS parsePeImageSectionBody(const UModelIndex & index, const bool probe = false);
+    USTATUS parseTeImageSectionBody(const UModelIndex & index, const bool probe = false);
 
     USTATUS parseAprioriRawSection(const UByteArray & body, UString & parsed);
     USTATUS findNextRawAreaItem(const UModelIndex & index, const UINT32 localOffset, UINT8 & nextItemType, UINT32 & nextItemOffset, UINT32 & nextItemSize, UINT32 & nextItemAlternativeSize);
diff --git a/common/fitparser.cpp b/common/fitparser.cpp
index 641d07f..f40385c 100644
--- a/common/fitparser.cpp
+++ b/common/fitparser.cpp
@@ -200,7 +200,7 @@ USTATUS FitParser::parseFit(const UModelIndex & index)
     return U_SUCCESS;
 }
 
-void FitParser::findFitRecursive(const UModelIndex & index, UModelIndex & found, UINT32 & fitOffset)
+void FitParser::findFitRecursive(const UModelIndex& index, UModelIndex & found, UINT32 & fitOffset)
 {
     // Sanity check
     if (!index.isValid()) {
@@ -217,28 +217,30 @@ void FitParser::findFitRecursive(const UModelIndex & index, UModelIndex & found,
         }
     }
     
-    // Check for all FIT signatures in item body
-    UByteArray lastVtfBody = model->body(ffsParser->lastVtf);
+    // Check for all FIT signatures in item body - we want to log 'em all
+    UByteArray lastVtfBody = model->header(ffsParser->lastVtf) + model->body(ffsParser->lastVtf) + model->tail(ffsParser->lastVtf);
     UINT64 fitSignatureValue = INTEL_FIT_SIGNATURE;
     UByteArray fitSignature((const char*)&fitSignatureValue, sizeof(fitSignatureValue));
-    UINT32 storedFitAddress = *(const UINT32*)(lastVtfBody.constData() + lastVtfBody.size() - INTEL_FIT_POINTER_OFFSET);
+    UINT32 storedFitAddress = *(const UINT32*)(lastVtfBody.constData() + UEFI_UPPER_INVALID_ADDRESS - INTEL_FIT_POINTER_OFFSET
+        - model->base(ffsParser->lastVtf) - ffsParser->addressDiff);
     for (INT32 offset = (INT32)model->body(index).indexOf(fitSignature);
          offset >= 0;
          offset = (INT32)model->body(index).indexOf(fitSignature, offset + 1)) {
         // FIT candidate found, calculate its physical address
-        UINT32 fitAddress = (UINT32)(model->base(index) + (UINT32)ffsParser->addressDiff + model->header(index).size() + (UINT32)offset);
+        UINT32 fitAddress = (UINT32)(model->base(index) + (UINT32)ffsParser->addressDiff + model->headerSize(index) + (UINT32)offset);
         
         // Check FIT address to be stored in the last VTF
         if (fitAddress == storedFitAddress) {
             // Valid FIT table must have at least two entries
-            if ((UINT32)model->body(index).size() < offset + 2*sizeof(INTEL_FIT_ENTRY)) {
+            if ((UINT32)model->bodySize(index) < offset + 2*sizeof(INTEL_FIT_ENTRY)) {
                 msg(usprintf("%s: FIT table candidate found, too small to contain real FIT", __FUNCTION__), index);
             }
             else {
                 // Real FIT found
                 found = index;
                 fitOffset = offset;
-                msg(usprintf("%s: real FIT table found at physical address %08Xh", __FUNCTION__, fitAddress), found);
+                msg(usprintf("%s: real FIT table found at physical address %08Xh (offset %Xh)", __FUNCTION__,
+                    fitAddress, fitOffset), found);
                 break;
             }
         }
@@ -709,8 +711,8 @@ USTATUS FitParser::parseFitEntryBootGuardBootPolicy(const UByteArray & bootPolic
                 else {
                     // Add postIbbHash protected range
                     UByteArray postIbbHash(ibbs_body->post_ibb_hash()->hash().data(), ibbs_body->post_ibb_hash()->len_hash());
-                    if (postIbbHash.count('\x00') != postIbbHash.size()
-                        && postIbbHash.count('\xFF') != postIbbHash.size()) {
+                    auto c = checkSingle(postIbbHash);
+                    if (c != 0 && c != 0xFF) {
                         PROTECTED_RANGE range = {};
                         range.Type = PROTECTED_RANGE_INTEL_BOOT_GUARD_POST_IBB;
                         range.AlgorithmId = ibbs_body->post_ibb_hash()->hash_algorithm_id();
@@ -990,8 +992,8 @@ USTATUS FitParser::parseFitEntryBootGuardBootPolicy(const UByteArray & bootPolic
                 else {
                     // Add postIbbHash protected range
                     UByteArray postIbbHash(ibbs_body->post_ibb_digest()->hash().data(), ibbs_body->post_ibb_digest()->len_hash());
-                    if (postIbbHash.count('\x00') != postIbbHash.size()
-                        && postIbbHash.count('\xFF') != postIbbHash.size()) {
+                    auto c = checkSingle(postIbbHash);
+                    if (c != 0 && c != 0xFF) {
                         PROTECTED_RANGE range = {};
                         range.Type = PROTECTED_RANGE_INTEL_BOOT_GUARD_POST_IBB;
                         range.AlgorithmId = ibbs_body->post_ibb_digest()->hash_algorithm_id();
@@ -1021,8 +1023,8 @@ USTATUS FitParser::parseFitEntryBootGuardBootPolicy(const UByteArray & bootPolic
                     
                     // Add ObbHash protected range
                     UByteArray obbHash(ibbs_body->obb_digest()->hash().data(), ibbs_body->obb_digest()->len_hash());
-                    if (obbHash.count('\x00') != obbHash.size()
-                        && obbHash.count('\xFF') != obbHash.size()) {
+                    auto c = checkSingle(obbHash);
+                    if (c != 0 && c != 0xFF) {
                         PROTECTED_RANGE range = {};
                         range.Type = PROTECTED_RANGE_INTEL_BOOT_GUARD_OBB;
                         range.AlgorithmId = ibbs_body->obb_digest()->hash_algorithm_id();
diff --git a/common/intel_microcode.h b/common/intel_microcode.h
index c6a3d89..04354ce 100644
--- a/common/intel_microcode.h
+++ b/common/intel_microcode.h
@@ -21,7 +21,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 
 // This structure is described in Section 9.11.1 of the Intel Software Developer manual Volume 3A Part 1
 typedef struct INTEL_MICROCODE_HEADER_ {
-    UINT32 HeaderVersion;             // 0x00000001
+    UINT32 HeaderType;                // 0x00000001 for Microcode (we do not need to support IFS yet)
     UINT32 UpdateRevision;
     UINT16 DateYear;                  // BCD
     UINT8  DateDay;                   // BCD
@@ -31,8 +31,7 @@ typedef struct INTEL_MICROCODE_HEADER_ {
                                       // Checksum is correct when the summation of all the DWORDs (including the extended Processor Signature Table)
                                       // that comprise the microcode update result in 00000000H.
     UINT32 LoaderRevision;            // 0x00000001
-    UINT8  ProcessorFlags;
-    UINT8  ProcessorFlagsReserved[3]; // Zeroes
+    UINT32 PlatformIds;               // Platform Ids
     UINT32 DataSize;                  // Specifies the size of the encrypted data in bytes, and must be a multiple of DWORDs.
                                       // If this value is 00000000H, then the microcode update encrypted data is 2000 bytes (or 500 DWORDs).
                                       // Sane values are less than 0x1000000
@@ -40,7 +39,9 @@ typedef struct INTEL_MICROCODE_HEADER_ {
                                       // It is the summation of the header size, the encrypted data size and the size of the optional extended signature table.
                                       // This value is always a multiple of 1024 according to the spec, but Intel already breached it several times.
                                       // Sane values are less than 0x1000000
-    UINT8  Reserved[12];              // Zeroes
+    UINT32 MetadataSize;              // Reserved in Microcode headers
+    UINT32 UpdateRevisionMin;         // Minimum required version for OS Kernel Late Loading
+    UINT32 Reserved;                  // Zeroes
 } INTEL_MICROCODE_HEADER;
 
 #define INTEL_MICROCODE_REAL_DATA_SIZE_ON_ZERO 2000
@@ -57,8 +58,8 @@ typedef struct INTEL_MICROCODE_EXTENDED_HEADER_ {
 
 typedef struct INTEL_MICROCODE_EXTENDED_HEADER_ENTRY_ {
     UINT32 ProcessorSignature;
-    UINT32 ProcessorFlags;
-    UINT32 Checksum;          // To calculate the Checksum, substitute the Primary Processor Signature entry and the Processor Flags entry with the corresponding Extended Patch entry.
+    UINT32 PlatformIds;
+    UINT32 Checksum;          // To calculate the Checksum, substitute the Primary Processor Signature entry and the Platform Ids entry with the corresponding Extended Patch entry.
                               // Delete the Extended Processor Signature Table entries.
                               // Checksum is correct when the summation of all DWORDs that comprise the created Extended Processor Patch results in 00000000H.
 } INTEL_MICROCODE_EXTENDED_HEADER_ENTRY;
diff --git a/common/meparser.cpp b/common/meparser.cpp
index aea1ae0..622159d 100755
--- a/common/meparser.cpp
+++ b/common/meparser.cpp
@@ -126,8 +126,7 @@ USTATUS MeParser::parseFptRegion(const UByteArray & region, const UModelIndex &
     }
     
     // Get info
-    UByteArray header = region.left(romBypassVectorSize + sizeof(FPT_HEADER));
-    UByteArray body = region.mid(header.size(), ptBodySize);
+    UINT32 headerSize = romBypassVectorSize + sizeof(FPT_HEADER);
     
     UString name = UString("FPT partition table");
     UString info;
@@ -139,7 +138,7 @@ USTATUS MeParser::parseFptRegion(const UByteArray & region, const UModelIndex &
         info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nROM bypass vector: %s\nNumber of entries: %u\nHeader version: %02Xh\nEntry version: %02Xh\n"
                         "Header length: %02Xh\nFlags: %Xh\nTicks to add: %04Xh\nTokens to add: %04Xh\nSPS Flags: %Xh\nFITC version: %u.%u.%u.%u\nCRC32 Checksum: %08Xh",
                         ptSize, ptSize,
-                        (UINT32)header.size(), (UINT32)header.size(),
+                        headerSize, headerSize,
                         ptBodySize, ptBodySize,
                         (romBypassVectorSize ? "present" : "absent"),
                         ptHeader21->NumEntries,
@@ -159,7 +158,7 @@ USTATUS MeParser::parseFptRegion(const UByteArray & region, const UModelIndex &
         info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nROM bypass vector: %s\nNumber of entries: %u\nHeader version: %02Xh\nEntry version: %02Xh\n"
                         "Header length: %02Xh\nFlash cycle life: %04Xh\nFlash cycle limit: %04Xh\nUMA size: %Xh\nFlags: %Xh\nFITC version: %u.%u.%u.%u\nChecksum: %02Xh",
                         ptSize, ptSize,
-                        (UINT32)header.size(), (UINT32)header.size(),
+                        headerSize, headerSize,
                         ptBodySize, ptBodySize,
                         (romBypassVectorSize ? "present" : "absent"),
                         ptHeader->NumEntries,
@@ -176,11 +175,15 @@ USTATUS MeParser::parseFptRegion(const UByteArray & region, const UModelIndex &
     }
     
     // Add tree item
-    index = model->addItem(0, Types::FptStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
+    index = model->addItem(
+        0, Types::FptStore, 0,
+        name, UString(), info,
+        headerSize, ptBodySize, 0,
+        Fixed, parent);
     
     // Add partition table entries
     std::vector<FPT_PARTITION_INFO> partitions;
-    UINT32 offset = (UINT32)header.size();
+    UINT32 offset = headerSize;
     UINT32 numEntries = ptHeader->NumEntries;
     const FPT_HEADER_ENTRY* firstPtEntry = (const FPT_HEADER_ENTRY*)(region.constData() + offset);
     for (UINT32 i = 0; i < numEntries; i++) {
@@ -197,7 +200,11 @@ USTATUS MeParser::parseFptRegion(const UByteArray & region, const UModelIndex &
         
         // Add tree item
         const UINT8 type = (ptEntry->Offset != 0 && ptEntry->Offset != 0xFFFFFFFF && ptEntry->Size != 0 && ptEntry->EntryValid != 0xFF) ? Subtypes::ValidFptEntry : Subtypes::InvalidFptEntry;
-        UModelIndex entryIndex = model->addItem(offset, Types::FptEntry, type, name, UString(), info, UByteArray(), UByteArray((const char*)ptEntry, sizeof(FPT_HEADER_ENTRY)), UByteArray(), Fixed, index);
+        UModelIndex entryIndex = model->addItem(
+            offset, Types::FptEntry, type,
+            name, UString(), info,
+            0, sizeof(FPT_HEADER_ENTRY), 0,
+            Fixed, index);
         
         // Adjust offset
         offset += sizeof(FPT_HEADER_ENTRY);
@@ -311,7 +318,11 @@ make_partition_table_consistent:
             
             // Add tree item
             UINT8 type = Subtypes::CodeFptPartition + partitions[i].ptEntry.Type;
-            partitionIndex = model->addItem(partitions[i].ptEntry.Offset, Types::FptPartition, type, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
+            partitionIndex = model->addItem(
+                partitions[i].ptEntry.Offset, Types::FptPartition, type,
+                name, UString(), info,
+                0, partition.size(), 0,
+                Fixed, parent);
             if (type == Subtypes::CodeFptPartition && partition.size() >= (int) sizeof(UINT32) && readUnaligned((const UINT32*)partition.constData()) == CPD_SIGNATURE) {
                 // Parse code partition contents
                 UModelIndex cpdIndex;
@@ -324,7 +335,11 @@ make_partition_table_consistent:
             info = usprintf("Full size: %Xh (%u)", (UINT32)partition.size(), (UINT32)partition.size());
             
             // Add tree item
-            model->addItem(partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
+            model->addItem(
+                partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition),
+                name, UString(), info,
+                0, partition.size(), 0,
+                Fixed, parent);
         }
     }
     
@@ -343,7 +358,7 @@ USTATUS MeParser::parseIfwi16Region(const UByteArray & region, const UModelIndex
     
     // Add header
     UINT32 ptSize = sizeof(IFWI_16_LAYOUT_HEADER);
-    UByteArray header = region.left(ptSize);
+    UINT32 headerSize = ptSize > region.size() ? region.size() : ptSize;
     
     UString name = UString("IFWI 1.6 header");
     UString info = usprintf("Full size: %Xh (%u)\n"
@@ -354,7 +369,7 @@ USTATUS MeParser::parseIfwi16Region(const UByteArray & region, const UModelIndex
                             "Boot4 partition offset: %Xh\nBoot4 partition size:   %Xh\n"
                             "Boot5 partition offset: %Xh\nBoot5 partition size:   %Xh\n"
                             "Checksum: %" PRIX64 "h",
-                            (UINT32)header.size(), (UINT32)header.size(),
+                            headerSize, headerSize,
                             ifwiHeader->DataPartition.Offset, ifwiHeader->DataPartition.Size,
                             ifwiHeader->BootPartition[0].Offset, ifwiHeader->BootPartition[0].Size,
                             ifwiHeader->BootPartition[1].Offset, ifwiHeader->BootPartition[1].Size,
@@ -363,7 +378,11 @@ USTATUS MeParser::parseIfwi16Region(const UByteArray & region, const UModelIndex
                             ifwiHeader->BootPartition[4].Offset, ifwiHeader->BootPartition[4].Size,
                             ifwiHeader->Checksum);
     // Add tree item
-    index = model->addItem(0, Types::IfwiHeader, 0, name, UString(), info, UByteArray(), header, UByteArray(), Fixed, parent);
+    index = model->addItem(
+        0, Types::IfwiHeader, 0,
+        name, UString(), info,
+        0, headerSize, 0,
+        Fixed, parent);
     
     std::vector<IFWI_PARTITION_INFO> partitions;
     // Add data partition
@@ -474,7 +493,11 @@ make_partition_table_consistent:
             info = usprintf("Full size: %Xh (%u)\n", (UINT32)partition.size(), (UINT32)partition.size());
             
             // Add tree item
-            partitionIndex = model->addItem(partitions[i].ptEntry.Offset, partitions[i].type, partitions[i].subtype, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
+            partitionIndex = model->addItem(
+                partitions[i].ptEntry.Offset, partitions[i].type, partitions[i].subtype,
+                name, UString(), info,
+                0, partition.size(), 0,
+                Fixed, parent);
             
             // Parse partition further
             if (partitions[i].subtype == Subtypes::DataIfwiPartition) {
@@ -493,7 +516,11 @@ make_partition_table_consistent:
             info = usprintf("Full size: %Xh (%u)", (UINT32)partition.size(), (UINT32)partition.size());
             
             // Add tree item
-            model->addItem(partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
+            model->addItem(
+                partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition),
+                name, UString(), info,
+                0, partition.size(), 0,
+                Fixed, parent);
         }
     }
     
@@ -513,7 +540,7 @@ USTATUS MeParser::parseIfwi17Region(const UByteArray & region, const UModelIndex
     
     // Add header
     UINT32 ptSize = sizeof(IFWI_17_LAYOUT_HEADER);
-    UByteArray header = region.left(ptSize);
+    UINT32 headerSize = ptSize > region.size() ? region.size() : ptSize;
     
     UString name = UString("IFWI 1.7 header");
     UString info = usprintf("Full size: %Xh (%u)\n"
@@ -527,7 +554,7 @@ USTATUS MeParser::parseIfwi17Region(const UByteArray & region, const UModelIndex
                             "Boot4 partition offset: %Xh\nBoot4 partition size:   %Xh\n"
                             "Boot5 partition offset: %Xh\nBoot5 partition size:   %Xh\n"
                             "Temp page offset:       %Xh\nTemp page size:         %Xh\n",
-                            (UINT32)header.size(), (UINT32)header.size(),
+                            headerSize, headerSize,
                             ifwiHeader->Flags,
                             ifwiHeader->Reserved,
                             ifwiHeader->Checksum,
@@ -539,7 +566,11 @@ USTATUS MeParser::parseIfwi17Region(const UByteArray & region, const UModelIndex
                             ifwiHeader->BootPartition[4].Offset, ifwiHeader->BootPartition[4].Size,
                             ifwiHeader->TempPage.Offset, ifwiHeader->TempPage.Size);
     // Add tree item
-    index = model->addItem(0, Types::IfwiHeader, 0, name, UString(), info, UByteArray(), header, UByteArray(), Fixed, parent);
+    index = model->addItem(
+        0, Types::IfwiHeader, 0,
+        name, UString(), info,
+        0, headerSize, 0,
+        Fixed, parent);
     
     std::vector<IFWI_PARTITION_INFO> partitions;
     // Add data partition
@@ -662,7 +693,11 @@ make_partition_table_consistent:
             info = usprintf("Full size: %Xh (%u)\n", (UINT32)partition.size(), (UINT32)partition.size());
             
             // Add tree item
-            partitionIndex = model->addItem(partitions[i].ptEntry.Offset, partitions[i].type, partitions[i].subtype, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
+            partitionIndex = model->addItem(
+                partitions[i].ptEntry.Offset, partitions[i].type, partitions[i].subtype,
+                name, UString(), info,
+                0, partition.size(), 0,
+                Fixed, parent);
             
             // Parse partition further
             if (partitions[i].subtype == Subtypes::DataIfwiPartition) {
@@ -688,7 +723,11 @@ make_partition_table_consistent:
             info = usprintf("Full size: %Xh (%u)", (UINT32)partition.size(), (UINT32)partition.size());
             
             // Add tree item
-            model->addItem(partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
+            model->addItem(
+                partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition),
+                name, UString(), info,
+                0, partition.size(), 0,
+                Fixed, parent);
         }
     }
     
diff --git a/common/nvramparser.cpp b/common/nvramparser.cpp
index d7c4791..3cfa04b 100644
--- a/common/nvramparser.cpp
+++ b/common/nvramparser.cpp
@@ -40,7 +40,7 @@
 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
 #endif
 
-USTATUS NvramParser::parseNvarStore(const UModelIndex & index)
+USTATUS NvramParser::parseNvarStore(const UModelIndex & index, const bool probe)
 {
     // Sanity check
     if (!index.isValid())
@@ -50,7 +50,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index)
 
     // Nothing to parse in an empty store
     if (nvar.isEmpty())
-        return U_SUCCESS;
+        return probe ? U_STORES_NOT_FOUND : U_SUCCESS;
 
     // Obtain required fields from parsing data
     UINT8 emptyByte = 0xFF;
@@ -59,9 +59,9 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index)
         const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData();
         emptyByte = pdata->emptyByte;
     }
-    
+
     try {
-        const UINT32 localOffset = (UINT32)model->header(index).size();
+        const UINT32 localOffset = (UINT32)model->headerSize(index);
         umemstream is(nvar.constData(), nvar.size());
         kaitai::kstream ks(&is);
         ami_nvar_t parsed(&ks);
@@ -74,9 +74,6 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index)
             UString text;
             UString info;
             UString guid;
-            UByteArray header;
-            UByteArray body;
-            UByteArray tail;
 
             // This is a terminating entry, needs special processing
             if (entry->_is_null_signature_rest()) {
@@ -89,30 +86,47 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index)
                 // Get info
                 UString info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size());
 
-                if ((UINT32)padding.count(emptyByte) == unparsedSize) { // Free space
+                auto c = checkSingle(padding, (unsigned char)emptyByte);
+                if (c == emptyByte && padding.size() == unparsedSize) { // Free space
+                    if (probe && nvar.size() == unparsedSize)
+                        return U_STORES_NOT_FOUND;
                     // Add tree item
-                    model->addItem(localOffset + entry->offset(), Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
+                    model->addItem(
+                        localOffset + entry->offset(), Types::FreeSpace, 0,
+                        UString("Free space"), UString(), info,
+                        0, padding.size(), 0,
+                        Fixed, index);
                 }
                 else {
                     // Nothing is parsed yet, but the file is not empty
                     if (entry->offset() == 0) {
-                        msg(usprintf("%s: file can't be parsed as NVAR variable store", __FUNCTION__), index);
-                        return U_SUCCESS;
+                        if (!probe)
+                            msg(usprintf("%s: file can't be parsed as NVAR variable store", __FUNCTION__), index);
+                        return U_INVALID_FILE;
                     }
 
                     // Add tree item
-                    model->addItem(localOffset + entry->offset(), Types::Padding, getPaddingType(padding), UString("Padding"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
+                    model->addItem(
+                        localOffset + entry->offset(), Types::Padding, getPaddingType(padding),
+                        UString("Padding"), UString(), info,
+                        0, padding.size(), 0,
+                        Fixed, index);
                 }
 
                 // Add GUID store area
-                UByteArray guidArea = nvar.right(guidAreaSize);
+                if (guidAreaSize > nvar.size())
+                    guidAreaSize = nvar.size();
                 // Get info
                 name = UString("GUID store");
                 info = usprintf("Full size: %Xh (%u)\nGUIDs in store: %u",
-                                (UINT32)guidArea.size(), (UINT32)guidArea.size(),
+                                guidAreaSize, guidAreaSize,
                                 guidsInStore);
                 // Add tree item
-                model->addItem((UINT32)(localOffset + entry->offset() + padding.size()), Types::NvarGuidStore, 0, name, UString(), info, UByteArray(), guidArea, UByteArray(), Fixed, index);
+                model->addItem(
+                    (UINT32)(localOffset + entry->offset() + padding.size()), Types::NvarGuidStore, 0,
+                    name, UString(), info,
+                    0, guidAreaSize, 0,
+                    Fixed, index);
 
                 return U_SUCCESS;
             }
@@ -210,9 +224,9 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index)
 
 processing_done:
             // This feels hacky, but I haven't found a way to ask Kaitai for raw bytes
-            header = nvar.mid(entry->offset(), sizeof(NVAR_ENTRY_HEADER) + entry_body->data_start_offset());
-            body = nvar.mid(entry->offset() + sizeof(NVAR_ENTRY_HEADER) + entry_body->data_start_offset(), entry_body->data_size());
-            tail = nvar.mid(entry->end_offset() - entry_body->extended_header_size(), entry_body->extended_header_size());
+            UINT32 headerSize = sizeof(NVAR_ENTRY_HEADER) + entry_body->data_start_offset();
+            UByteArray nvarData = nvar.mid(entry->offset(), headerSize + entry_body->data_size())
+                + nvar.mid(entry->end_offset() - entry_body->extended_header_size(), entry_body->extended_header_size());
 
             // Add GUID info for valid entries
             if (!guid.isEmpty())
@@ -225,12 +239,12 @@ processing_done:
             // Add header, body and extended data info
             info += usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nTail size: %Xh (%u)",
                              entry->size(), entry->size(),
-                             (UINT32)header.size(), (UINT32)header.size(),
-                             (UINT32)body.size(), (UINT32)body.size(),
-                             (UINT32)tail.size(), (UINT32)tail.size());
+                             headerSize, headerSize,
+                             entry_body->data_size(), entry_body->data_size(),
+                             entry_body->extended_header_size(), entry_body->extended_header_size());
 
             // Add attributes info
-            const NVAR_ENTRY_HEADER entryHeader = readUnaligned((NVAR_ENTRY_HEADER*)header.constData());
+            const NVAR_ENTRY_HEADER entryHeader = readUnaligned((NVAR_ENTRY_HEADER*)nvarData.constData());
             info += usprintf("\nAttributes: %02Xh", entryHeader.Attributes);
 
             // Translate attributes to text
@@ -246,17 +260,16 @@ processing_done:
                 info += usprintf("\nExtended header size: %Xh (%u)",
                                  entry_body->extended_header_size(), entry_body->extended_header_size());
 
-                const UINT8 extendedAttributes = *tail.constData();
+                const UINT8 extendedAttributes = *(nvar.constData() + entry->end_offset() - entry_body->extended_header_size());//tail.constData();
                 info += usprintf("\nExtended attributes: %02Xh (", extendedAttributes) + nvarExtendedAttributesToUString(extendedAttributes) + UString(")");
 
                 // Add checksum
                 if (!entry_body->_is_null_extended_header_checksum()) {
                     UINT8 calculatedChecksum = 0;
-                    UByteArray wholeBody = body + tail;
 
                     // Include entry body
-                    UINT8* start = (UINT8*)wholeBody.constData();
-                    for (UINT8* p = start; p < start + wholeBody.size(); p++) {
+                    UINT8* start = (UINT8*)nvarData.constData();
+                    for (UINT8* p = start; p < start + headerSize + entry_body->data_size(); p++) {
                         calculatedChecksum += *p;
                     }
                     // Include entry size and flags
@@ -282,7 +295,11 @@ processing_done:
             }
 
             // Add tree item
-            UModelIndex varIndex = model->addItem(localOffset + entry->offset(), Types::NvarEntry, subtype, name, text, info, header, body, tail, Fixed, index);
+            UModelIndex varIndex = model->addItem(
+                localOffset + entry->offset(), Types::NvarEntry, subtype,
+                name, text, info,
+                headerSize, entry_body->data_size(), entry_body->extended_header_size(),
+                Fixed, index);
             currentEntryIndex++;
 
             // Set parsing data
@@ -290,23 +307,25 @@ processing_done:
 
             // Try parsing the entry data as NVAR storage if it begins with NVAR signature
             if ((subtype == Subtypes::DataNvarEntry || subtype == Subtypes::FullNvarEntry)
-                && body.size() >= 4 && readUnaligned((const UINT32*)body.constData()) == NVRAM_NVAR_ENTRY_SIGNATURE)
+                && entry_body->data_size() >= 4 && readUnaligned((const UINT32*)(nvarData.constData() + headerSize)) == NVRAM_NVAR_ENTRY_SIGNATURE)
                 (void)parseNvarStore(varIndex);
         }
     }
     catch (...) {
+        if (!probe)
+            msg(usprintf("%s: unable to parse AMI NVAR storage", __FUNCTION__), index);
         return U_INVALID_STORE;
     }
 
     return U_SUCCESS;
 }
 
-USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 fdcStoreSizeOverride)
+USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex& index, const UINT32 fdcStoreSizeOverride)
 {
     // Sanity check
     if (!index.isValid())
         return U_INVALID_PARAMETER;
-    
+
     // Obtain required fields from parsing data
     UINT8 emptyByte = 0xFF;
     if (model->hasEmptyParsingData(index) == false) {
@@ -314,10 +333,10 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32
         const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData();
         emptyByte = pdata->emptyByte;
     }
-    
+
     // Get local offset
-    const UINT32 localOffset = (UINT32)model->header(index).size();
-    
+    const UINT32 localOffset = (UINT32)model->headerSize(index);
+
     // Get item data
     UByteArray volumeBody = model->body(index);
     const UINT32 volumeBodySize = (UINT32)volumeBody.size();
@@ -326,18 +345,18 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32
     UByteArray outerPadding;
     UINT32 previousStoreEndOffset = 0;
     for (UINT32 storeOffset = 0;
-         storeOffset < volumeBodySize;
-         storeOffset++) {
+        storeOffset < volumeBodySize;
+        storeOffset++) {
         UString name, text, info;
-        UByteArray header, body;
-        
+        UINT32 headerSize, bodySize;
+
         // VSS
         try {
             if (volumeBodySize - storeOffset < sizeof(VSS_VARIABLE_STORE_HEADER)) {
                 // No need to parse further, the rest of the volume is too small
                 goto not_vss;
             }
-            
+
             // Perform initial sanity check
             const VSS_VARIABLE_STORE_HEADER* storeHeader = (const VSS_VARIABLE_STORE_HEADER*)(volumeBody.constData() + storeOffset);
             if ((storeHeader->Signature != NVRAM_VSS_STORE_SIGNATURE
@@ -348,10 +367,10 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32
                 goto not_vss;
             }
             UINT32 storeSize = MIN(volumeBodySize - storeOffset, storeHeader->Size); //TODO: consider this check to become hard bail as it was before
-            
+
             // This copy is required for possible FDC workaround
             UByteArray vss = volumeBody.mid(storeOffset, storeSize);
-            
+
             // Check if we are here to parse a special case of FDC store with size override
             UINT32 originalStoreSize = 0;
             bool fdcHeaderSizeOverrideRequired = (fdcStoreSizeOverride > 0 && storeHeader->Signature == NVRAM_VSS_STORE_SIGNATURE && storeHeader->Size == 0xFFFFFFFF);
@@ -360,12 +379,12 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32
                 originalStoreSize = vssHeader->Size;
                 vssHeader->Size = fdcStoreSizeOverride;
             }
-            
+
             // Try parsing VSS store candidate
             umemstream is(vss.constData(), vss.size());
             kaitai::kstream ks(&is);
             edk2_vss_t parsed(&ks);
-            
+
             // Restore original store size, if needed
             if (fdcHeaderSizeOverrideRequired) {
                 VSS_VARIABLE_STORE_HEADER* vssHeader = (VSS_VARIABLE_STORE_HEADER*)vss.data();
@@ -376,14 +395,18 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32
             // Check if we need to add a padding before it
             if (!outerPadding.isEmpty()) {
                 UString info = usprintf("Full size: %Xh (%u)", (UINT32)outerPadding.size(), (UINT32)outerPadding.size());
-                model->addItem(localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding), UString("Padding"), UString(), info, UByteArray(), outerPadding, UByteArray(), Fixed, index);
+                model->addItem(
+                    localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding),
+                    UString("Padding"), UString(), info,
+                    0, outerPadding.size(), 0,
+                    Fixed, index);
                 outerPadding.clear();
             }
 
-            // Construct header and body
-            header = vss.left(parsed.len_vss_store_header());
-            body = vss.mid(header.size(), storeSize - header.size());
-            
+            // Obtain header and body size
+            headerSize = parsed.len_vss_store_header();
+            bodySize = storeSize - headerSize;
+
             // Add info
             if (parsed.signature() == NVRAM_APPLE_SVS_STORE_SIGNATURE) {
                 name = UString("Apple SVS store");
@@ -394,25 +417,29 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32
             else {
                 name = UString("VSS store");
             }
-            
+
             info = usprintf("Signature: %Xh (", parsed.signature()) + fourCC(parsed.signature()) + UString(")\n");
             info += usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nFormat: %02Xh\nState: %02Xh\nReserved: %02Xh\nReserved1: %04Xh",
-                            storeSize , storeSize,
-                            (UINT32)header.size(), (UINT32)header.size(),
-                            (UINT32)body.size(), (UINT32)body.size(),
-                            parsed.format(),
-                            parsed.state(),
-                            parsed.reserved(),
-                            parsed.reserved1());
-            
+                             storeSize, storeSize,
+                             headerSize, headerSize,
+                             bodySize, bodySize,
+                             parsed.format(),
+                             parsed.state(),
+                             parsed.reserved(),
+                             parsed.reserved1());
+
             // Add header tree item
-            UModelIndex headerIndex = model->addItem(localOffset + storeOffset, Types::VssStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index);
-            
+            UModelIndex headerIndex = model->addItem(
+                localOffset + storeOffset, Types::VssStore, 0,
+                name, UString(), info,
+                headerSize, bodySize, 0,
+                Fixed, index);
+
             // Add variables
             UINT32 entryOffset = parsed.len_vss_store_header();
-            for (const auto & variable : *parsed.body()->variables()) {
+            for (const auto& variable : *parsed.body()->variables()) {
                 UINT8 subtype;
-                
+
                 // This is the terminating entry, needs special processing
                 if (variable->_is_null_signature_last()) {
                     // Add free space or padding after all variables, if needed
@@ -420,39 +447,48 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32
                         UByteArray freeSpace = vss.mid(entryOffset, storeSize - entryOffset);
                         // Add info
                         info = usprintf("Full size: %Xh (%u)", (UINT32)freeSpace.size(), (UINT32)freeSpace.size());
-                        
+
                         // Check that remaining unparsed bytes are actually empty
-                        if (freeSpace.count(emptyByte) == freeSpace.size()) { // Free space
+                        auto c = checkSingle(freeSpace, (unsigned char)emptyByte);
+                        if (c == emptyByte) { // Free space
                             // Add tree item
-                            model->addItem(entryOffset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), freeSpace, UByteArray(), Fixed, headerIndex);
+                            model->addItem(
+                                entryOffset, Types::FreeSpace, 0,
+                                UString("Free space"), UString(), info,
+                                0, freeSpace.size(), 0,
+                                Fixed, headerIndex);
                         }
                         else {
                             // Add tree item
-                            model->addItem(entryOffset, Types::Padding, getPaddingType(freeSpace), UString("Padding"), UString(), info, UByteArray(), freeSpace, UByteArray(), Fixed, headerIndex);
+                            model->addItem(
+                                entryOffset, Types::Padding, getPaddingType(freeSpace),
+                                UString("Padding"), UString(), info,
+                                0, freeSpace.size(), 0,
+                                Fixed, headerIndex);
                         }
                     }
                     break;
                 }
-                
+
                 // This is a normal entry
                 UINT32 variableSize;
                 if (variable->is_intel_legacy()) { // Intel legacy
                     subtype = Subtypes::IntelVssEntry;
                     // Needs some additional parsing of variable->intel_legacy_data to separate the name from the value
                     text = uFromUcs2(variable->intel_legacy_data().c_str());
-                    UINT32 textLengthInBytes = (UINT32)text.length()*2+2;
-                    header = vss.mid(entryOffset, variable->len_intel_legacy_header() + textLengthInBytes);
-                    body = vss.mid(entryOffset + header.size(), variable->len_total() - variable->len_intel_legacy_header() - textLengthInBytes);
-                    variableSize = (UINT32)(header.size() + body.size());
+                    UINT32 textLengthInBytes = (UINT32)text.length() * 2 + 2;
+                    headerSize = variable->len_intel_legacy_header() + textLengthInBytes;
+                    bodySize = variable->len_total() - headerSize;
+                    variableSize = headerSize + bodySize;
                     const EFI_GUID variableGuid = readUnaligned((const EFI_GUID*)(variable->vendor_guid().c_str()));
                     name = guidToUString(variableGuid);
                     info = UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n";
                 }
                 else if (variable->is_auth()) { // Authenticated
                     subtype = Subtypes::AuthVssEntry;
-                    header = vss.mid(entryOffset, variable->len_auth_header() + variable->len_name_auth());
-                    body = vss.mid(entryOffset + header.size(), variable->len_data_auth());
-                    variableSize = (UINT32)(header.size() + body.size());
+                    headerSize = variable->len_auth_header() + variable->len_name_auth();
+                    bodySize = variable->len_data_auth();
+                    variableSize = headerSize + bodySize;
                     const EFI_GUID variableGuid = readUnaligned((const EFI_GUID*)(variable->vendor_guid().c_str()));
                     name = guidToUString(variableGuid);
                     text = uFromUcs2(variable->name_auth().c_str());
@@ -460,9 +496,9 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32
                 }
                 else if (!variable->_is_null_apple_data_crc32()) { // Apple CRC32
                     subtype = Subtypes::AppleVssEntry;
-                    header = vss.mid(entryOffset, variable->len_apple_header() + variable->len_name());
-                    body = vss.mid(entryOffset + header.size(), variable->len_data());
-                    variableSize = (UINT32)(header.size() + body.size());
+                    headerSize = variable->len_apple_header() + variable->len_name();
+                    bodySize = variable->len_data();
+                    variableSize = headerSize + bodySize;
                     const EFI_GUID variableGuid = readUnaligned((const EFI_GUID*)(variable->vendor_guid().c_str()));
                     name = guidToUString(variableGuid);
                     text = uFromUcs2(variable->name().c_str());
@@ -470,79 +506,84 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32
                 }
                 else { // Standard
                     subtype = Subtypes::StandardVssEntry;
-                    header = vss.mid(entryOffset, variable->len_standard_header() + variable->len_name());
-                    body = vss.mid(entryOffset + header.size(), variable->len_data());
-                    variableSize = (UINT32)(header.size() + body.size());
+                    headerSize = variable->len_standard_header() + variable->len_name();
+                    bodySize = variable->len_data();
+                    variableSize = headerSize + bodySize;
                     const EFI_GUID variableGuid = readUnaligned((const EFI_GUID*)(variable->vendor_guid().c_str()));
                     name = guidToUString(variableGuid);
                     text = uFromUcs2(variable->name().c_str());
                     info = UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n";
                 }
-                
+
                 // Override variable type to Invalid, if needed
                 if (!variable->is_valid()) {
                     subtype = Subtypes::InvalidVssEntry;
                     name = UString("Invalid");
                     text.clear();
                 }
-                
+
                 const UINT32 variableAttributes = variable->attributes()->non_volatile()
-                + (variable->attributes()->boot_service() << 1)
-                + (variable->attributes()->runtime() << 2)
-                + (variable->attributes()->hw_error_record() << 3)
-                + (variable->attributes()->auth_write() << 4)
-                + (variable->attributes()->time_based_auth() << 5)
-                + (variable->attributes()->append_write() << 6)
-                + (UINT32)(variable->attributes()->reserved() << 7)
-                + (UINT32)(variable->attributes()->apple_data_checksum() << 31);
-                
+                    + (variable->attributes()->boot_service() << 1)
+                    + (variable->attributes()->runtime() << 2)
+                    + (variable->attributes()->hw_error_record() << 3)
+                    + (variable->attributes()->auth_write() << 4)
+                    + (variable->attributes()->time_based_auth() << 5)
+                    + (variable->attributes()->append_write() << 6)
+                    + (UINT32)(variable->attributes()->reserved() << 7)
+                    + (UINT32)(variable->attributes()->apple_data_checksum() << 31);
+
                 // Add generic info
                 info += usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nState: %02Xh\nReserved: %02Xh\nAttributes: %08Xh (",
                                  variableSize, variableSize,
-                                 (UINT32)header.size(), (UINT32)header.size(),
-                                 (UINT32)body.size(), (UINT32)body.size(),
+                                 headerSize, headerSize,
+                                 bodySize, bodySize,
                                  variable->state(),
                                  variable->reserved(),
                                  variableAttributes) + vssAttributesToUString(variableAttributes) + UString(")");
-                
+
                 // Add specific info
                 if (variable->is_auth()) {
                     UINT64 monotonicCounter = (UINT64)variable->len_name() + ((UINT64)variable->len_data() << 32);
                     info += usprintf("\nMonotonic counter: %" PRIX64 "h\nTimestamp: ", monotonicCounter) + efiTimeToUString(*(const EFI_TIME*)variable->timestamp().c_str())
-                    + usprintf("\nPubKey index: %u", variable->pubkey_index());
+                        + usprintf("\nPubKey index: %u", variable->pubkey_index());
                 }
                 else if (!variable->_is_null_apple_data_crc32()) {
                     // Calculate CRC32 of the variable data
-                    UINT32 calculatedCrc32 = (UINT32)crc32(0, (const UINT8*)body.constData(), (uInt)body.size());
-                    
+                    UINT32 calculatedCrc32 = (UINT32)crc32(0, (const UINT8*)(vss.constData() + entryOffset + headerSize), bodySize);
+
                     info += usprintf("\nData checksum: %08Xh", variable->apple_data_crc32()) +
-                    (variable->apple_data_crc32() != calculatedCrc32 ? usprintf(", invalid, should be %08Xh", calculatedCrc32) : UString(", valid"));
+                        (variable->apple_data_crc32() != calculatedCrc32 ? usprintf(", invalid, should be %08Xh", calculatedCrc32) : UString(", valid"));
                 }
-                
+
                 // Add tree item
-                model->addItem(entryOffset, Types::VssEntry, subtype, name, text, info, header, body, UByteArray(), Fixed, headerIndex);
-                
+                model->addItem(
+                    entryOffset, Types::VssEntry, subtype,
+                    name, text, info,
+                    headerSize, bodySize, 0,
+                    Fixed, headerIndex);
+
                 entryOffset += variableSize;
             }
-            
+
             storeOffset += storeSize - 1;
             previousStoreEndOffset = storeOffset + 1;
             continue;
-        } catch (...) {
-           // Parsing failed, try something else
         }
-not_vss:
+        catch (...) {
+            // Parsing failed, try something else
+        }
+    not_vss:
         // VSS2
         try {
             if (volumeBodySize - storeOffset < sizeof(VSS2_VARIABLE_STORE_HEADER)) {
                 // No need to parse further, the rest of the volume is too small
                 goto not_vss2;
             }
-            
+
             // Perform initial sanity check
             const VSS2_VARIABLE_STORE_HEADER* storeHeader = (const VSS2_VARIABLE_STORE_HEADER*)(volumeBody.constData() + storeOffset);
             UByteArray guid = UByteArray((const char*)&storeHeader->Signature, sizeof(EFI_GUID));
-            
+
             if ((guid != NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID
                 && guid != NVRAM_VSS2_STORE_GUID
                 && guid != NVRAM_FDC_STORE_GUID)
@@ -551,10 +592,10 @@ not_vss:
                 goto not_vss2;
             }
             UINT32 storeSize = MIN(volumeBodySize - storeOffset, storeHeader->Size);
-            
+
             // This copy is required for possible FDC workaround
             UByteArray vss2 = volumeBody.mid(storeOffset, storeSize);
-            
+
             // Check if we are here to parse a special case of FDC store with size override
             UINT32 originalStoreSize = 0;
             bool fdcHeaderSizeOverrideRequired = (fdcStoreSizeOverride > 0 && guid == NVRAM_FDC_STORE_GUID && storeHeader->Size == 0xFFFFFFFF);
@@ -563,30 +604,34 @@ not_vss:
                 originalStoreSize = vss2Header->Size;
                 vss2Header->Size = fdcStoreSizeOverride;
             }
-            
+
             // Try parsing VSS store candidate
             umemstream is(vss2.constData(), vss2.size());
             kaitai::kstream ks(&is);
             edk2_vss2_t parsed(&ks);
-            
+
             // Restore original store size, if needed
             if (fdcHeaderSizeOverrideRequired) {
                 VSS2_VARIABLE_STORE_HEADER* vss2Header = (VSS2_VARIABLE_STORE_HEADER*)vss2.data();
                 vss2Header->Size = originalStoreSize;
             }
-            
+
             // VSS2 store at current offset parsed correctly
             // Check if we need to add a padding before it
             if (!outerPadding.isEmpty()) {
                 info = usprintf("Full size: %Xh (%u)", (UINT32)outerPadding.size(), (UINT32)outerPadding.size());
-                model->addItem(localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding), UString("Padding"), UString(), info, UByteArray(), outerPadding, UByteArray(), Fixed, index);
+                model->addItem(
+                    localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding),
+                    UString("Padding"), UString(), info,
+                    0, outerPadding.size(), 0,
+                    Fixed, index);
                 outerPadding.clear();
             }
 
-            // Construct header and body
-            header = vss2.left(parsed.len_vss2_store_header());
-            body = vss2.mid(header.size(), storeSize - header.size());
-            
+            // Obtain header and body size
+            headerSize = parsed.len_vss2_store_header();
+            bodySize = storeSize - headerSize;
+
             // Add info
             name = UString("VSS2 store");
             if (guid == NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID) {
@@ -598,24 +643,28 @@ not_vss:
             else {
                 info = UString("Signature: DDCF3617-3275-4164-98B6-FE85707FFE7D\n");
             }
-            
+
             info += usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nFormat: %02Xh\nState: %02Xh\nReserved: %02Xh\nReserved1: %04Xh",
-                            storeSize, storeSize,
-                            (UINT32)header.size(), (UINT32)header.size(),
-                            (UINT32)body.size(), (UINT32)body.size(),
-                            parsed.format(),
-                            parsed.state(),
-                            parsed.reserved(),
-                            parsed.reserved1());
-            
+                             storeSize, storeSize,
+                             headerSize, headerSize,
+                             bodySize, bodySize,
+                             parsed.format(),
+                             parsed.state(),
+                             parsed.reserved(),
+                             parsed.reserved1());
+
             // Add header tree item
-            UModelIndex headerIndex = model->addItem(localOffset + storeOffset, Types::Vss2Store, 0, name, UString(), info, header, body, UByteArray(), Fixed, index);
-            
+            UModelIndex headerIndex = model->addItem(
+                localOffset + storeOffset, Types::Vss2Store, 0,
+                name, UString(), info,
+                headerSize, bodySize, 0,
+                Fixed, index);
+
             // Add variables
             UINT32 entryOffset = parsed.len_vss2_store_header();
-            for (const auto & variable : *parsed.body()->variables()) {
+            for (const auto& variable : *parsed.body()->variables()) {
                 UINT8 subtype;
-                
+
                 // This is the terminating entry, needs special processing
                 if (variable->_is_null_signature_last()) {
                     // Add free space or padding after all variables, if needed
@@ -623,28 +672,37 @@ not_vss:
                         UByteArray freeSpace = vss2.mid(entryOffset, storeSize - entryOffset);
                         // Add info
                         info = usprintf("Full size: %Xh (%u)", (UINT32)freeSpace.size(), (UINT32)freeSpace.size());
-                        
+
                         // Check that remaining unparsed bytes are actually empty
-                        if (freeSpace.count(emptyByte) == freeSpace.size()) { // Free space
+                        auto c = checkSingle(freeSpace, (unsigned char)emptyByte);
+                        if (c == emptyByte) { // Free space
                             // Add tree item
-                            model->addItem(entryOffset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), freeSpace, UByteArray(), Fixed, headerIndex);
+                            model->addItem(
+                                entryOffset, Types::FreeSpace, 0,
+                                UString("Free space"), UString(), info,
+                                0, freeSpace.size(), 0,
+                                Fixed, headerIndex);
                         }
                         else {
                             // Add tree item
-                            model->addItem(entryOffset, Types::Padding, getPaddingType(freeSpace), UString("Padding"), UString(), info, UByteArray(), freeSpace, UByteArray(), Fixed, headerIndex);
+                            model->addItem(
+                                entryOffset, Types::Padding, getPaddingType(freeSpace),
+                                UString("Padding"), UString(), info,
+                                0, freeSpace.size(), 0,
+                                Fixed, headerIndex);
                         }
                     }
                     break;
                 }
-                
+
                 // This is a normal entry
                 UINT32 variableSize;
                 UINT32 alignmentSize;
                 if (variable->is_auth()) { // Authenticated
                     subtype = Subtypes::AuthVssEntry;
-                    header = vss2.mid(entryOffset, variable->len_auth_header() + variable->len_name_auth());
-                    body = vss2.mid(entryOffset + header.size(), variable->len_data_auth());
-                    variableSize = (UINT32)(header.size() + body.size());
+                    headerSize = variable->len_auth_header() + variable->len_name_auth();
+                    bodySize = variable->len_data_auth();
+                    variableSize = headerSize + bodySize;
                     alignmentSize = variable->len_alignment_padding_auth();
                     const EFI_GUID variableGuid = readUnaligned((const EFI_GUID*)(variable->vendor_guid().c_str()));
                     name = guidToUString(variableGuid);
@@ -653,66 +711,71 @@ not_vss:
                 }
                 else { // Standard
                     subtype = Subtypes::StandardVssEntry;
-                    header = vss2.mid(entryOffset, variable->len_standard_header() + variable->len_name());
-                    body = vss2.mid(entryOffset + header.size(), variable->len_data());
-                    variableSize = (UINT32)(header.size() + body.size());
+                    headerSize = variable->len_standard_header() + variable->len_name();
+                    bodySize = variable->len_data();
+                    variableSize = headerSize + bodySize;
                     alignmentSize = variable->len_alignment_padding();
                     const EFI_GUID variableGuid = readUnaligned((const EFI_GUID*)(variable->vendor_guid().c_str()));
                     name = guidToUString(variableGuid);
                     text = uFromUcs2(variable->name().c_str());
                     info = UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n";
                 }
-                
+
                 // Override variable type to Invalid if needed
                 if (!variable->is_valid()) {
                     subtype = Subtypes::InvalidVssEntry;
                     name = UString("Invalid");
                     text.clear();
                 }
-                
+
                 const UINT32 variableAttributes = variable->attributes()->non_volatile()
-                + (variable->attributes()->boot_service() << 1)
-                + (variable->attributes()->runtime() << 2)
-                + (variable->attributes()->hw_error_record() << 3)
-                + (variable->attributes()->auth_write() << 4)
-                + (variable->attributes()->time_based_auth() << 5)
-                + (variable->attributes()->append_write() << 6)
-                + (UINT32)(variable->attributes()->reserved() << 7);
-                
+                    + (variable->attributes()->boot_service() << 1)
+                    + (variable->attributes()->runtime() << 2)
+                    + (variable->attributes()->hw_error_record() << 3)
+                    + (variable->attributes()->auth_write() << 4)
+                    + (variable->attributes()->time_based_auth() << 5)
+                    + (variable->attributes()->append_write() << 6)
+                    + (UINT32)(variable->attributes()->reserved() << 7);
+
                 // Add generic info
                 info += usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nState: %02Xh\nReserved: %02Xh\nAttributes: %08Xh (",
                                  variableSize, variableSize,
-                                 (UINT32)header.size(), (UINT32)header.size(),
-                                 (UINT32)body.size(), (UINT32)body.size(),
+                                 headerSize, headerSize,
+                                 bodySize, bodySize,
                                  variable->state(),
                                  variable->reserved(),
                                  variableAttributes) + vssAttributesToUString(variableAttributes) + UString(")");
-                
+
                 // Add specific info
                 if (variable->is_auth()) {
                     UINT64 monotonicCounter = (UINT64)variable->len_name() + ((UINT64)variable->len_data() << 32);
                     info += usprintf("\nMonotonic counter: %" PRIX64 "h\nTimestamp: ", monotonicCounter) + efiTimeToUString(*(const EFI_TIME*)variable->timestamp().c_str())
-                    + usprintf("\nPubKey index: %u", variable->pubkey_index());
+                        + usprintf("\nPubKey index: %u", variable->pubkey_index());
                 }
-                
+
                 // Add tree item
-                model->addItem(entryOffset, Types::VssEntry, subtype, name, text, info, header, body, UByteArray(), Fixed, headerIndex);
-                
+                model->addItem(
+                    entryOffset, Types::VssEntry, subtype,
+                    name, text, info,
+                    headerSize, bodySize, 0,
+                    Fixed, headerIndex);
+
                 entryOffset += (variableSize + alignmentSize);
             }
-            
+
             storeOffset += storeSize - 1;
             previousStoreEndOffset = storeOffset + 1;
             continue;
-        } catch (...) {
-           // Parsing failed, try something else
         }
-not_vss2:
+        catch (...) {
+            // Parsing failed, try something else
+        }
+    not_vss2:
         // Do not try any other parsers if we are here for FDC store parsing
         if (fdcStoreSizeOverride != 0) {
             continue;
         }
-        
+
         // FTW
         try {
             if (volumeBodySize - storeOffset < sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32)) {
@@ -743,20 +806,20 @@ not_vss2:
                 goto not_ftw;
             }
             storeSize = MIN(volumeBodySize - storeOffset, storeSize);
-        
+
             umemstream is(volumeBody.constData() + storeOffset, storeSize);
             kaitai::kstream ks(&is);
             edk2_ftw_t parsed(&ks);
-            
+
             // Construct header and calculate header checksum
-            UINT32 headerSize;
             UINT32 calculatedCrc;
+            UByteArray crcHeader = volumeBody.mid(storeOffset, std::max(
+                sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32), sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64)));
             if (parsed._is_null_len_write_queue_64()) {
                 headerSize = sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32);
-                header = volumeBody.mid(storeOffset, headerSize);
-                
+
+
                 // Check block header checksum
-                UByteArray crcHeader = header;
                 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32* crcFtwBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32*)crcHeader.data();
                 crcFtwBlockHeader->Crc = emptyByte ? 0xFFFFFFFF : 0;
                 crcFtwBlockHeader->State = emptyByte ? 0xFF : 0;
@@ -764,47 +827,52 @@ not_vss2:
             }
             else {
                 headerSize = sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64);
-                header = volumeBody.mid(storeOffset, headerSize);
-                
+
                 // Check block header checksum
-                UByteArray crcHeader = header;
                 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64* crcFtwBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64*)crcHeader.data();
                 crcFtwBlockHeader->Crc = emptyByte ? 0xFFFFFFFF : 0;
                 crcFtwBlockHeader->State = emptyByte ? 0xFF : 0;
                 calculatedCrc = (UINT32)crc32(0, (const UINT8*)crcFtwBlockHeader, (UINT32)headerSize);
             }
-            
+            bodySize = storeSize - headerSize;
+
             // FTW store at current offset parsed correctly
             // Check if we need to add a padding before it
             if (!outerPadding.isEmpty()) {
                 UString info = usprintf("Full size: %Xh (%u)", (UINT32)outerPadding.size(), (UINT32)outerPadding.size());
-                model->addItem(localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding), UString("Padding"), UString(), info, UByteArray(), outerPadding, UByteArray(), Fixed, index);
+                model->addItem(
+                    localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding),
+                    UString("Padding"), UString(), info,
+                    0, outerPadding.size(), 0,
+                    Fixed, index);
                 outerPadding.clear();
             }
-            
-            // Construct body
-            body = volumeBody.mid(storeOffset + header.size(), storeSize - header.size());
-            
+
             // Add info
             name = UString("FTW store");
             info = UString("Signature: ") + guidToUString(*(const EFI_GUID*)guid.constData(), false);
             info += usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nState: %02Xh\nHeader CRC32: %08Xh",
-                             (UINT32)storeSize, (UINT32)storeSize,
-                             (UINT32)header.size(), (UINT32)header.size(),
-                             (UINT32)body.size(), (UINT32)body.size(),
+                             storeSize, storeSize,
+                             headerSize, headerSize,
+                             bodySize, bodySize,
                              parsed.state(),
                              parsed.crc()) + (parsed.crc() != calculatedCrc ? usprintf(", invalid, should be %08Xh", calculatedCrc) : UString(", valid"));
-            
+
             // Add header tree item
-            model->addItem(localOffset + storeOffset, Types::FtwStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index);
-            
+            model->addItem(
+                localOffset + storeOffset, Types::FtwStore, 0,
+                name, UString(), info,
+                headerSize, bodySize, 0,
+                Fixed, index);
+
             storeOffset += storeSize - 1;
             previousStoreEndOffset = storeOffset + 1;
             continue;
-        } catch (...) {
+        }
+        catch (...) {
             // Parsing failed, try something else
         }
-not_ftw:
+    not_ftw:
         // Insyde FDC
         try {
             if (volumeBodySize - storeOffset < sizeof(INSYDE_FDC_STORE_HEADER)) {
@@ -818,43 +886,52 @@ not_ftw:
                 goto not_fdc;
             }
             UINT32 storeSize = MIN(volumeBodySize - storeOffset, storeHeader->Size);
-            
+
             umemstream is(volumeBody.constData() + storeOffset, storeSize);
             kaitai::kstream ks(&is);
             insyde_fdc_t parsed(&ks);
-            
+
             // Insyde FDC store at current offset parsed correctly
             // Check if we need to add a padding before it
             if (!outerPadding.isEmpty()) {
                 UString info = usprintf("Full size: %Xh (%u)", (UINT32)outerPadding.size(), (UINT32)outerPadding.size());
-                model->addItem(localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding), UString("Padding"), UString(), info, UByteArray(), outerPadding, UByteArray(), Fixed, index);
+                model->addItem(
+                    localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding),
+                    UString("Padding"), UString(), info,
+                    0, outerPadding.size(), 0,
+                    Fixed, index);
                 outerPadding.clear();
             }
-            
-            // Construct header and body
-            header = volumeBody.mid(storeOffset, sizeof(INSYDE_FDC_STORE_HEADER));
-            body = volumeBody.mid(storeOffset + header.size(), storeSize - header.size());
-            
+
+            // Obtain header and body size
+            headerSize = sizeof(INSYDE_FDC_STORE_HEADER);
+            bodySize = storeSize - headerSize;
+
             // Add info
             name = UString("Insyde FDC store");
             info = usprintf("Signature: _FDC\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)",
-                                    storeSize, storeSize,
-                                    (UINT32)header.size(), (UINT32)header.size(),
-                                    (UINT32)body.size(), (UINT32)body.size());
-            
+                            storeSize, storeSize,
+                            headerSize, headerSize,
+                            bodySize, bodySize);
+
             // Add header tree item
-            UModelIndex headerIndex = model->addItem(localOffset + storeOffset, Types::FdcStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index);
-            
+            UModelIndex headerIndex = model->addItem(
+                localOffset + storeOffset, Types::FdcStore, 0,
+                name, UString(), info,
+                headerSize, bodySize, 0,
+                Fixed, index);
+
             // Parse FDC body as normal VSS/VSS2 storage with size override
-            parseNvramVolumeBody(headerIndex, (UINT32)body.size());
-            
+            parseNvramVolumeBody(headerIndex, bodySize);
+
             storeOffset += storeSize - 1;
             previousStoreEndOffset = storeOffset + 1;
             continue;
-        } catch (...) {
+        }
+        catch (...) {
             // Parsing failed, try something else
         }
-not_fdc:
+    not_fdc:
         // Apple SysF
         try {
             if (volumeBodySize - storeOffset < sizeof(APPLE_SYSF_STORE_HEADER)) {
@@ -869,26 +946,30 @@ not_fdc:
                 goto not_sysf;
             }
             UINT32 storeSize = MIN(volumeBodySize - storeOffset, storeHeader->Size);
-            
+
             umemstream is(volumeBody.constData() + storeOffset, storeSize);
             kaitai::kstream ks(&is);
             apple_sysf_t parsed(&ks);
-            
+
             // Apple SysF/Diag store at current offset parsed correctly
             // Check if we need to add a padding before it
             if (!outerPadding.isEmpty()) {
                 info = usprintf("Full size: %Xh (%u)", (UINT32)outerPadding.size(), (UINT32)outerPadding.size());
-                model->addItem(localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding), UString("Padding"), UString(), info, UByteArray(), outerPadding, UByteArray(), Fixed, index);
+                model->addItem(
+                    localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding),
+                    UString("Padding"), UString(), info,
+                    0, outerPadding.size(), 0,
+                    Fixed, index);
                 outerPadding.clear();
             }
-            
-            // Construct header and body
-            header = volumeBody.mid(storeOffset, sizeof(APPLE_SYSF_STORE_HEADER));
-            body = volumeBody.mid(storeOffset + header.size(), storeSize - header.size());
-            
+
+            // Obtain header and body size
+            headerSize = sizeof(APPLE_SYSF_STORE_HEADER);
+            bodySize = storeSize - headerSize;
+
             // Check store checksum
             UINT32 calculatedCrc = (UINT32)crc32(0, (const UINT8*)(volumeBody.constData() + storeOffset), storeSize - sizeof(UINT32));
-            
+
             // Add info
             if (storeHeader->Signature == NVRAM_APPLE_SYSF_STORE_SIGNATURE) {
                 name = UString("Apple SysF store");
@@ -899,21 +980,25 @@ not_fdc:
                 info = UString("Signature: Gaid\n");
             }
             info += usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nUnknown: %02Xh\nUnknown1: %08Xh\nCRC32: %08Xh",
-                            storeSize, storeSize,
-                            (UINT32)header.size(), (UINT32)header.size(),
-                            (UINT32)body.size(), (UINT32)body.size(),
-                            parsed.unknown(),
-                            parsed.unknown1(),
-                            parsed.crc())  + (parsed.crc() != calculatedCrc ? usprintf(", invalid, should be %08Xh", calculatedCrc) : UString(", valid"));
-            
+                             storeSize, storeSize,
+                             headerSize, headerSize,
+                             bodySize, bodySize,
+                             parsed.unknown(),
+                             parsed.unknown1(),
+                             parsed.crc()) + (parsed.crc() != calculatedCrc ? usprintf(", invalid, should be %08Xh", calculatedCrc) : UString(", valid"));
+
             // Add header tree item
-            UModelIndex headerIndex = model->addItem(localOffset + storeOffset, Types::SysFStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index);
-            
+            UModelIndex headerIndex = model->addItem(
+                localOffset + storeOffset, Types::SysFStore, 0,
+                name, UString(), info,
+                headerSize, bodySize, 0,
+                Fixed, index);
+
             // Add variables
             UINT32 entryOffset = sizeof(APPLE_SYSF_STORE_HEADER);
-            for (const auto & variable : *parsed.body()->variables()) {
+            for (const auto& variable : *parsed.body()->variables()) {
                 UINT8 subtype;
-                
+
                 if (variable->invalid_flag()) {
                     subtype = Subtypes::InvalidSysFEntry;
                     name = UString("Invalid");
@@ -922,51 +1007,66 @@ not_fdc:
                     subtype = Subtypes::NormalSysFEntry;
                     name = usprintf("%s", variable->name().c_str());
                 }
-                
+
                 if (variable->len_name() == 3 && variable->name() == "EOF") {
-                    header = volumeBody.mid(storeOffset + entryOffset, 4);
+                    headerSize = 4;
+                    ///??? Where is the body?
                 }
                 else {
-                    header = volumeBody.mid(storeOffset + entryOffset, sizeof(UINT8) + (UINT32)variable->len_name() + sizeof(UINT16));
-                    body = volumeBody.mid(storeOffset + entryOffset + header.size(), (UINT32)variable->len_data());
+                    headerSize = sizeof(UINT8) + (UINT32)variable->len_name() + sizeof(UINT16);
+                    bodySize = (UINT32)variable->len_data();
                 }
                 // Add generic info
-                UINT32 variableSize = (UINT32)header.size() + (UINT32)body.size();
+                UINT32 variableSize = headerSize + bodySize;
                 info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\n",
-                                 variableSize, variableSize,
-                                 (UINT32)header.size(), (UINT32)header.size(),
-                                 (UINT32)body.size(), (UINT32)body.size());
-                
+                                variableSize, variableSize,
+                                headerSize, headerSize,
+                                bodySize, bodySize);
+
                 // Add tree item
-                model->addItem(entryOffset, Types::SysFEntry, subtype, name, UString(), info, header, body, UByteArray(), Fixed, headerIndex);
-                
+                model->addItem(
+                    entryOffset, Types::SysFEntry, subtype,
+                    name, UString(), info,
+                    headerSize, bodySize, 0,
+                    Fixed, headerIndex);
+
                 entryOffset += variableSize;
             }
-            
+
             // Add free space or padding after all variables, if needed
             if (entryOffset < storeSize) {
                 UByteArray freeSpace = volumeBody.mid(storeOffset + entryOffset, storeSize - entryOffset);
                 // Add info
                 info = usprintf("Full size: %Xh (%u)", (UINT32)freeSpace.size(), (UINT32)freeSpace.size());
-                
+
                 // Check that remaining unparsed bytes are actually zeroes
-                if (freeSpace.count('\x00') == freeSpace.size() - 4) { // Free space, 4 last bytes are always CRC32
+                auto c = checkSingle(freeSpace.left(freeSpace.size() - 4), 0); // Free space, 4 last bytes are always CRC32
+                if (c == 0) { 
                     // Add tree item
-                    model->addItem(entryOffset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), freeSpace, UByteArray(), Fixed, headerIndex);
+                    model->addItem(
+                        entryOffset, Types::FreeSpace, 0,
+                        UString("Free space"), UString(), info,
+                        0, freeSpace.size(), 0,
+                        Fixed, headerIndex);
                 }
                 else {
                     // Add tree item
-                    model->addItem(entryOffset, Types::Padding, getPaddingType(freeSpace), UString("Padding"), UString(), info, UByteArray(), freeSpace, UByteArray(), Fixed, headerIndex);
+                    model->addItem(
+                        entryOffset, Types::Padding, getPaddingType(freeSpace),
+                        UString("Padding"), UString(), info,
+                        0, freeSpace.size(), 0,
+                        Fixed, headerIndex);
                 }
             }
-            
+
             storeOffset += storeSize - 1;
             previousStoreEndOffset = storeOffset + 1;
             continue;
-        } catch (...) {
+        }
+        catch (...) {
             // Parsing failed, try something else
         }
-not_sysf:
+    not_sysf:
         // Phoenix Flash Map
         try {
             if (volumeBodySize - storeOffset < sizeof(PHOENIX_FLASH_MAP_HEADER)) {
@@ -981,40 +1081,47 @@ not_sysf:
                 goto not_flm;
             }
             UINT32 storeSize = sizeof(PHOENIX_FLASH_MAP_HEADER) + storeHeader->NumEntries * sizeof(PHOENIX_FLASH_MAP_ENTRY);
-            
+
             umemstream is(volumeBody.constData() + storeOffset, storeSize);
             kaitai::kstream ks(&is);
             phoenix_flm_t parsed(&ks);
-            
+
             // Phoenix FlashMap store at current offset parsed correctly
             // Check if we need to add a padding before it
             if (!outerPadding.isEmpty()) {
                 info = usprintf("Full size: %Xh (%u)", (UINT32)outerPadding.size(), (UINT32)outerPadding.size());
-                model->addItem(localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding), UString("Padding"), UString(), info, UByteArray(), outerPadding, UByteArray(), Fixed, index);
+                model->addItem(
+                    localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding),
+                    UString("Padding"), UString(), info,
+                    0, outerPadding.size(), 0,
+                    Fixed, index);
                 outerPadding.clear();
             }
-            
+
             // Construct header and body
-            header = volumeBody.left(storeOffset + sizeof(PHOENIX_FLASH_MAP_HEADER));
-            body = volumeBody.mid(storeOffset + header.size(), storeSize - header.size());
-            
+            headerSize = sizeof(PHOENIX_FLASH_MAP_HEADER); ///??? was erroneous "header = volumeBody.left(storeOffset + sizeof(PHOENIX_FLASH_MAP_HEADER))" in original
+            bodySize = storeSize - headerSize;
             // Add info
             name = UString("Phoenix SCT flash map");
             info = usprintf("Signature: _FLASH_MAP\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nEntries: %u\nReserved: %08Xh",
-                                    storeSize, storeSize,
-                                    (UINT32)header.size(), (UINT32)header.size(),
-                                    (UINT32)body.size(), (UINT32)body.size(),
-                                    parsed.num_entries(),
-                                    parsed.reserved());
-            
+                             storeSize, storeSize,
+                             headerSize, headerSize,
+                             bodySize, bodySize,
+                             parsed.num_entries(),
+                             parsed.reserved());
+
             // Add header tree item
-            UModelIndex headerIndex = model->addItem(localOffset + storeOffset, Types::PhoenixFlashMapStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index);
-            
+            UModelIndex headerIndex = model->addItem(
+                localOffset + storeOffset, Types::PhoenixFlashMapStore, 0,
+                name, UString(), info,
+                headerSize, bodySize, 0,
+                Fixed, index);
+
             // Add entries
             UINT32 entryOffset = sizeof(PHOENIX_FLASH_MAP_HEADER);
-            for (const auto & entry : *parsed.entries()) {
+            for (const auto& entry : *parsed.entries()) {
                 UINT8 subtype;
-                
+
                 if (entry->data_type() == NVRAM_PHOENIX_FLASH_MAP_ENTRY_DATA_TYPE_VOLUME) {
                     subtype = Subtypes::VolumeFlashMapEntry;
                 }
@@ -1024,36 +1131,41 @@ not_sysf:
                 else {
                     subtype = Subtypes::UnknownFlashMapEntry;
                 }
-                
+
                 const EFI_GUID guid = readUnaligned((const EFI_GUID*)entry->guid().c_str());
                 name = guidToUString(guid);
                 text = phoenixFlashMapGuidToUString(guid);
-                header = volumeBody.mid(storeOffset + entryOffset, sizeof(PHOENIX_FLASH_MAP_ENTRY));
+                headerSize = sizeof(PHOENIX_FLASH_MAP_ENTRY);
 
                 // Add info
-                UINT32 entrySize = (UINT32)header.size();
+                UINT32 entrySize = headerSize;
                 info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: 0h (0)\nData type: %04Xh\nEntry type: %04Xh\nSize: %08Xh\nOffset: %08Xh\nPhysical address: %" PRIX64 "h",
                                 entrySize, entrySize,
-                                (UINT32)header.size(), (UINT32)header.size(),
+                                headerSize, headerSize,
                                 entry->data_type(),
                                 entry->entry_type(),
                                 entry->size(),
                                 entry->offset(),
                                 entry->physical_address());
-                
+
                 // Add tree item
-                model->addItem(entryOffset, Types::PhoenixFlashMapEntry, subtype, name, text, info, header, UByteArray(), UByteArray(), Fixed, headerIndex);
-                
+                model->addItem(
+                    entryOffset, Types::PhoenixFlashMapEntry, subtype,
+                    name, text, info,
+                    headerSize, 0, 0,
+                    Fixed, headerIndex);
+
                 entryOffset += entrySize;
             }
-            
+
             storeOffset += storeSize - 1;
             previousStoreEndOffset = storeOffset + 1;
             continue;
-        } catch (...) {
+        }
+        catch (...) {
             // Parsing failed, try something else
         }
-not_flm:
+    not_flm:
         // Phoenix EVSA store
         try {
             if (volumeBodySize - storeOffset < sizeof(EVSA_STORE_ENTRY)) {
@@ -1069,48 +1181,56 @@ not_flm:
                 goto not_evsa;
             }
             UINT32 storeSize = MIN(volumeBodySize - storeOffset, storeHeader->StoreSize);
-            
+
             umemstream is(volumeBody.constData() + storeOffset, storeSize);
             kaitai::kstream ks(&is);
             phoenix_evsa_t parsed(&ks);
-            
+
             // Phoenix EVSA store at current offset parsed correctly
             // Check if we need to add a padding before it
             if (!outerPadding.isEmpty()) {
                 info = usprintf("Full size: %Xh (%u)", (UINT32)outerPadding.size(), (UINT32)outerPadding.size());
-                model->addItem(localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding), UString("Padding"), UString(), info, UByteArray(), outerPadding, UByteArray(), Fixed, index);
+                model->addItem(
+                    localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding),
+                    UString("Padding"), UString(), info,
+                    0, outerPadding.size(), 0,
+                    Fixed, index);
                 outerPadding.clear();
             }
-            
-            // Construct header and body
-            header = volumeBody.mid(storeOffset, sizeof(EVSA_STORE_ENTRY));
-            body = volumeBody.mid(storeOffset + header.size(), storeSize - header.size());
-            
+
+            // Obtain header and body size
+            headerSize = sizeof(EVSA_STORE_ENTRY);
+            bodySize = storeSize - headerSize;
+
             // Calculate header checksum
             UINT8 calculated = calculateChecksum8(((const UINT8*)storeHeader) + 2, storeHeader->Header.Size - 2);
-            
+
             // Add info
             name = UString("Phoenix EVSA store");
             info = usprintf("Signature: EVSA\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nAttributes: %08Xh\nReserved: %08Xh\nChecksum: %02Xh",
                             storeSize, storeSize,
-                            (UINT32)header.size(), (UINT32)header.size(),
-                            (UINT32)body.size(), (UINT32)body.size(),
+                            headerSize, headerSize,
+                            bodySize, bodySize,
                             parsed.attributes(),
                             parsed.reserved(),
                             parsed.checksum())
-            + (parsed.checksum() != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid"));
-            
+                            + (parsed.checksum() != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid"));
+
             // Add header tree item
-            UModelIndex headerIndex = model->addItem(localOffset + storeOffset, Types::EvsaStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index);
-            
+            UModelIndex headerIndex = model->addItem(
+                localOffset + storeOffset, Types::EvsaStore, 0,
+                name, UString(), info,
+                headerSize, bodySize, 0,
+                Fixed, index);
+
             // Add entries
             std::map<UINT16, EFI_GUID> guidMap;
             std::map<UINT16, UString> nameMap;
             UINT32 entryOffset = parsed.len_evsa_store_header();
-            for (const auto & entry : *parsed.body()->entries()) {
+            for (const auto& entry : *parsed.body()->entries()) {
                 UINT8 subtype;
                 UINT32 entrySize;
-                
+
                 // This is the terminating entry, needs special processing
                 if (entry->_is_null_checksum()) {
                     // Add free space or padding after all variables, if needed
@@ -1118,114 +1238,127 @@ not_flm:
                         UByteArray freeSpace = volumeBody.mid(storeOffset + entryOffset, storeSize - entryOffset);
                         // Add info
                         info = usprintf("Full size: %Xh (%u)", (UINT32)freeSpace.size(), (UINT32)freeSpace.size());
-                        
+
                         // Check that remaining unparsed bytes are actually empty
-                        if (freeSpace.count(emptyByte) == freeSpace.size()) { // Free space
+                        auto c = checkSingle(freeSpace, (unsigned char)emptyByte);
+                        if (c == emptyByte) { // Free space
                             // Add tree item
-                            model->addItem(entryOffset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), freeSpace, UByteArray(), Fixed, headerIndex);
+                            model->addItem(
+                                entryOffset, Types::FreeSpace, 0,
+                                UString("Free space"), UString(), info,
+                                0, freeSpace.size(), 0,
+                                Fixed, headerIndex);
                         }
                         else {
                             // Add tree item
-                            model->addItem(entryOffset, Types::Padding, getPaddingType(freeSpace), UString("Padding"), UString(), info, UByteArray(), freeSpace, UByteArray(), Fixed, headerIndex);
+                            model->addItem(
+                                entryOffset, Types::Padding, getPaddingType(freeSpace),
+                                UString("Padding"), UString(), info,
+                                0, freeSpace.size(), 0,
+                                Fixed, headerIndex);
                         }
                     }
                     break;
                 }
-                
+
                 const EVSA_ENTRY_HEADER* entryHeader = (const EVSA_ENTRY_HEADER*)(volumeBody.constData() + storeOffset + entryOffset);
                 calculated = calculateChecksum8(((const UINT8*)entryHeader) + 2, entryHeader->Size - 2);
-                
+
                 // GUID entry
                 if (entry->entry_type() == NVRAM_EVSA_ENTRY_TYPE_GUID1 || entry->entry_type() == NVRAM_EVSA_ENTRY_TYPE_GUID2) {
                     const phoenix_evsa_t::evsa_guid_t* guidEntry = (const phoenix_evsa_t::evsa_guid_t*)(entry->body());
-                    header = volumeBody.mid(storeOffset + entryOffset, sizeof(EVSA_GUID_ENTRY));
-                    body = volumeBody.mid(storeOffset + entryOffset + sizeof(EVSA_GUID_ENTRY), entry->len_evsa_entry() - header.size());
-                    entrySize = (UINT32)(header.size() + body.size());
+                    headerSize = sizeof(EVSA_GUID_ENTRY);
+                    bodySize = entry->len_evsa_entry() - headerSize;
+                    entrySize = headerSize + bodySize;
                     EFI_GUID guid = *(const EFI_GUID*)(guidEntry->guid().c_str());
                     name = guidToUString(guid);
                     info = UString("GUID: ") + guidToUString(guid, false)
-                    + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nChecksum: %02Xh",
-                               entrySize, entrySize,
-                               (UINT32)header.size(), (UINT32)header.size(),
-                               (UINT32)body.size(), (UINT32)body.size(),
-                               entry->entry_type(),
-                               entry->checksum())
-                    + (entry->checksum() != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid"))
-                    + usprintf("\nGuidId: %04Xh", guidEntry->guid_id());
+                        + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nChecksum: %02Xh",
+                                   entrySize, entrySize,
+                                   headerSize, headerSize,
+                                   bodySize, bodySize,
+                                   entry->entry_type(),
+                                   entry->checksum())
+                        + (entry->checksum() != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid"))
+                        + usprintf("\nGuidId: %04Xh", guidEntry->guid_id());
                     subtype = Subtypes::GuidEvsaEntry;
                     guidMap.insert(std::pair<UINT16, EFI_GUID>(guidEntry->guid_id(), guid));
                 }
                 // Name entry
                 else if (entry->entry_type() == NVRAM_EVSA_ENTRY_TYPE_NAME1 || entry->entry_type() == NVRAM_EVSA_ENTRY_TYPE_NAME2) {
                     const phoenix_evsa_t::evsa_name_t* nameEntry = (const phoenix_evsa_t::evsa_name_t*)(entry->body());
-                    header = volumeBody.mid(storeOffset + entryOffset, sizeof(EVSA_NAME_ENTRY));
-                    body = volumeBody.mid(storeOffset + entryOffset + sizeof(EVSA_NAME_ENTRY), entry->len_evsa_entry() - header.size());
-                    entrySize = (UINT32)(header.size() + body.size());
-                    name = uFromUcs2(body.constData());
+                    headerSize = sizeof(EVSA_NAME_ENTRY);
+                    bodySize = entry->len_evsa_entry() - headerSize;
+                    entrySize = headerSize + bodySize;
+                    name = uFromUcs2(volumeBody.constData() + storeOffset + entryOffset + headerSize);
                     info = UString("Name: ") + name
-                    + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nChecksum: %02Xh",
-                               entrySize, entrySize,
-                               (UINT32)header.size(), (UINT32)header.size(),
-                               (UINT32)body.size(), (UINT32)body.size(),
-                               entry->entry_type(),
-                               entry->checksum())
-                    + (entry->checksum() != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid"))
-                    + usprintf("\nVarId: %04Xh", nameEntry->var_id());
+                        + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nChecksum: %02Xh",
+                                   entrySize, entrySize,
+                                   headerSize, headerSize,
+                                   bodySize, bodySize,
+                                   entry->entry_type(),
+                                   entry->checksum())
+                        + (entry->checksum() != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid"))
+                        + usprintf("\nVarId: %04Xh", nameEntry->var_id());
                     subtype = Subtypes::NameEvsaEntry;
                     nameMap.insert(std::pair<UINT16, UString>(nameEntry->var_id(), name));
                 }
                 // Data entry
                 else if (entry->entry_type() == NVRAM_EVSA_ENTRY_TYPE_DATA1
-                         || entry->entry_type() == NVRAM_EVSA_ENTRY_TYPE_DATA2
-                         || entry->entry_type() == NVRAM_EVSA_ENTRY_TYPE_DATA_INVALID) {
+                    || entry->entry_type() == NVRAM_EVSA_ENTRY_TYPE_DATA2
+                    || entry->entry_type() == NVRAM_EVSA_ENTRY_TYPE_DATA_INVALID) {
                     phoenix_evsa_t::evsa_data_t* dataEntry = (phoenix_evsa_t::evsa_data_t*)(entry->body());
                     if (dataEntry->_is_null_len_data_ext()) {
-                        header = volumeBody.mid(storeOffset + entryOffset, sizeof(EVSA_DATA_ENTRY));
-                        body = volumeBody.mid(storeOffset + entryOffset + sizeof(EVSA_DATA_ENTRY), entry->len_evsa_entry() - header.size());
+                        headerSize = sizeof(EVSA_DATA_ENTRY);
+                        bodySize = entry->len_evsa_entry() - headerSize;
                     }
                     else {
-                        header = volumeBody.mid(storeOffset + entryOffset, sizeof(EVSA_DATA_ENTRY_EXTENDED));
-                        body = volumeBody.mid(storeOffset + entryOffset + sizeof(EVSA_DATA_ENTRY_EXTENDED), dataEntry->len_data_ext());
+                        headerSize = sizeof(EVSA_DATA_ENTRY_EXTENDED);
+                        bodySize = dataEntry->len_data_ext();
                     }
-                    entrySize = (UINT32)(header.size() + body.size());
+                    entrySize = headerSize + bodySize;
                     name = UString("Data");
                     subtype = Subtypes::DataEvsaEntry;
-                    
+
                     const UINT32 attributes = dataEntry->attributes()->non_volatile()
-                    + (dataEntry->attributes()->boot_service() << 1)
-                    + (dataEntry->attributes()->runtime() << 2)
-                    + (dataEntry->attributes()->hw_error_record() << 3)
-                    + (dataEntry->attributes()->auth_write() << 4)
-                    + (dataEntry->attributes()->time_based_auth() << 5)
-                    + (dataEntry->attributes()->append_write() << 6)
-                    + (UINT32)(dataEntry->attributes()->reserved() << 7)
-                    + (dataEntry->attributes()->extended_header() << 28)
-                    + (UINT32)(dataEntry->attributes()->reserved1() << 29);
-                    
+                        + (dataEntry->attributes()->boot_service() << 1)
+                        + (dataEntry->attributes()->runtime() << 2)
+                        + (dataEntry->attributes()->hw_error_record() << 3)
+                        + (dataEntry->attributes()->auth_write() << 4)
+                        + (dataEntry->attributes()->time_based_auth() << 5)
+                        + (dataEntry->attributes()->append_write() << 6)
+                        + (UINT32)(dataEntry->attributes()->reserved() << 7)
+                        + (dataEntry->attributes()->extended_header() << 28)
+                        + (UINT32)(dataEntry->attributes()->reserved1() << 29);
+
                     info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nChecksum: %02Xh",
                                     entrySize, entrySize,
-                                    (UINT32)header.size(), (UINT32)header.size(),
-                                    (UINT32)body.size(), (UINT32)body.size(),
+                                    headerSize, headerSize,
+                                    bodySize, bodySize,
                                     entry->entry_type(),
                                     entry->checksum())
-                    + (entry->checksum() != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid"))
-                    + usprintf("\nVarId: %04Xh\nGuidId: %04Xh\nAttributes: %08Xh (",
-                               dataEntry->var_id(),
-                               dataEntry->guid_id(),
-                               attributes)
-                    + evsaAttributesToUString(attributes) + UString(")");
+                                    + (entry->checksum() != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid"))
+                                    + usprintf("\nVarId: %04Xh\nGuidId: %04Xh\nAttributes: %08Xh (",
+                                               dataEntry->var_id(),
+                                               dataEntry->guid_id(),
+                                               attributes)
+                                    + evsaAttributesToUString(attributes) + UString(")");
                 }
-                
+
                 // Add tree item
-                model->addItem(entryOffset, Types::EvsaEntry, subtype, name, text, info, header, body, UByteArray(), Fixed, headerIndex);
-                
+                model->addItem(
+                    entryOffset, Types::EvsaEntry, subtype,
+                    name, text, info,
+                    headerSize, bodySize, 0,
+                    Fixed, headerIndex);
+
                 entryOffset += entrySize;
             }
-            
+
             // Reparse all data variables to detect invalid ones and assign name and test to valid ones
             for (int i = 0; i < model->rowCount(headerIndex); i++) {
                 UModelIndex current = headerIndex.model()->index(i, 0, headerIndex);
-                
+
                 if (model->subtype(current) == Subtypes::DataEvsaEntry) {
                     UByteArray header = model->header(current);
                     const EVSA_DATA_ENTRY* dataHeader = (const EVSA_DATA_ENTRY*)header.constData();
@@ -1235,7 +1368,7 @@ not_flm:
                     UString name;
                     if (nameMap.count(dataHeader->VarId))
                         name = nameMap[dataHeader->VarId];
-                    
+
                     // Check for variable validity
                     if (guid.isEmpty() && name.isEmpty()) { // Both name and guid aren't found
                         model->setSubtype(current, Subtypes::InvalidEvsaEntry);
@@ -1269,14 +1402,15 @@ not_flm:
                     }
                 }
             }
-            
+
             storeOffset += storeSize - 1;
             previousStoreEndOffset = storeOffset + 1;
             continue;
-        } catch (...) {
+        }
+        catch (...) {
             // Parsing failed, try something else
         }
- not_evsa:
+    not_evsa:
         // Phoenix CMDB store
         try {
             if (volumeBodySize - storeOffset < NVRAM_PHOENIX_CMDB_SIZE) {
@@ -1290,36 +1424,45 @@ not_flm:
                 goto not_cmdb;
             }
             UINT32 storeSize = NVRAM_PHOENIX_CMDB_SIZE;
-            
+
             // CMDB store at current offset parsed correctly
             // Check if we need to add a padding before it
             if (!outerPadding.isEmpty()) {
                 info = usprintf("Full size: %Xh (%u)", (UINT32)outerPadding.size(), (UINT32)outerPadding.size());
-                model->addItem(localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding), UString("Padding"), UString(), info, UByteArray(), outerPadding, UByteArray(), Fixed, index);
+                model->addItem(
+                    localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding),
+                    UString("Padding"), UString(), info,
+                    0, outerPadding.size(), 0,
+                    Fixed, index);
                 outerPadding.clear();
             }
-            
-            // Construct header and body
-            header = volumeBody.mid(storeOffset, storeHeader->TotalSize);
-            body = volumeBody.mid(storeOffset + header.size(), storeSize - header.size());
-            
+
+            // Obtain header and body size
+            headerSize = storeHeader->TotalSize;
+            bodySize = storeSize - headerSize;
+
             // Add info
             name = UString("Phoenix CMDB store");
             info = usprintf("Signature: CMDB\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)",
                             storeSize, storeSize,
-                            (UINT32)header.size(), (UINT32)header.size(),
-                            (UINT32)body.size(), (UINT32)body.size());
-            
+                            headerSize, headerSize,
+                            bodySize, bodySize);
+
             // Add tree item
-            model->addItem(localOffset + storeOffset, Types::CmdbStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index);
-            
+            model->addItem(
+                localOffset + storeOffset, Types::CmdbStore, 0,
+                name, UString(), info,
+                headerSize, bodySize, 0,
+                Fixed, index);
+
             storeOffset += storeSize - 1;
             previousStoreEndOffset = storeOffset + 1;
             continue;
-        } catch (...) {
+        }
+        catch (...) {
             // Parsing failed, try something else
         }
-not_cmdb:
+    not_cmdb:
         // SLIC PubKey
         try {
             if (volumeBodySize - storeOffset < sizeof(OEM_ACTIVATION_PUBKEY)) {
@@ -1335,22 +1478,26 @@ not_cmdb:
                 goto not_pubkey;
             }
             UINT32 storeSize = sizeof(OEM_ACTIVATION_PUBKEY);
-            
+
             umemstream is(volumeBody.constData() + storeOffset, storeSize);
             kaitai::kstream ks(&is);
             ms_slic_pubkey_t parsed(&ks);
-            
+
             // SLIC PubKey at current offset parsed correctly
             // Check if we need to add a padding before it
             if (!outerPadding.isEmpty()) {
                 info = usprintf("Full size: %Xh (%u)", (UINT32)outerPadding.size(), (UINT32)outerPadding.size());
-                model->addItem(localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding), UString("Padding"), UString(), info, UByteArray(), outerPadding, UByteArray(), Fixed, index);
+                model->addItem(
+                    localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding),
+                    UString("Padding"), UString(), info,
+                    0, outerPadding.size(), 0,
+                    Fixed, index);
                 outerPadding.clear();
             }
-            
-            // Construct header
-            header = volumeBody.mid(storeOffset, storeSize);
-            
+
+            // Obtain header size
+            headerSize = storeSize;
+
             // Add info
             name = UString("SLIC pubkey");
             info = usprintf("Type: 0h\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: 0h (0)\n"
@@ -1362,17 +1509,22 @@ not_cmdb:
                             parsed.algorithm(),
                             parsed.bit_length(),
                             parsed.exponent());
-            
+
             // Add tree item
-            model->addItem(localOffset + storeOffset, Types::SlicData, Subtypes::PubkeySlicData, name, UString(), info, header, UByteArray(), UByteArray(), Fixed, index);
-            
+            model->addItem(
+                localOffset + storeOffset, Types::SlicData, Subtypes::PubkeySlicData,
+                name, UString(), info,
+                headerSize, 0, 0,
+                Fixed, index);
+
             storeOffset += storeSize - 1;
             previousStoreEndOffset = storeOffset + 1;
             continue;
-        } catch (...) {
+        }
+        catch (...) {
             // Parsing failed, try something else
         }
-not_pubkey:
+    not_pubkey:
         // SLIC marker
         try {
             if (volumeBodySize - storeOffset < sizeof(OEM_ACTIVATION_MARKER)) {
@@ -1395,22 +1547,26 @@ not_pubkey:
                 }
             }
             UINT32 storeSize = sizeof(OEM_ACTIVATION_MARKER);
-            
+
             umemstream is(volumeBody.constData() + storeOffset, storeSize);
             kaitai::kstream ks(&is);
             ms_slic_marker_t parsed(&ks);
-            
+
             // SLIC marker at current offset parsed correctly
             // Check if we need to add a padding before it
             if (!outerPadding.isEmpty()) {
                 info = usprintf("Full size: %Xh (%u)", (UINT32)outerPadding.size(), (UINT32)outerPadding.size());
-                model->addItem(localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding), UString("Padding"), UString(), info, UByteArray(), outerPadding, UByteArray(), Fixed, index);
+                model->addItem(
+                    localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding),
+                    UString("Padding"), UString(), info,
+                    0, outerPadding.size(), 0,
+                    Fixed, index);
                 outerPadding.clear();
             }
-            
-            // Construct header
-            header = volumeBody.mid(storeOffset, storeSize);
-            
+
+            // Obtain header size
+            headerSize = storeSize;
+
             // Add info
             name = UString("SLIC marker");
             info = usprintf("Type: 1h\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: 0h (0)\n"
@@ -1421,98 +1577,109 @@ not_pubkey:
                             parsed.oem_id().c_str(),
                             parsed.oem_table_id().c_str(),
                             parsed.slic_version());
-            
+
             // Add tree item
-            model->addItem(localOffset + storeOffset, Types::SlicData, Subtypes::MarkerSlicData, name, UString(), info, header, UByteArray(), UByteArray(), Fixed, index);
-            
+            model->addItem(
+                localOffset + storeOffset, Types::SlicData, Subtypes::MarkerSlicData,
+                name, UString(), info,
+                headerSize, 0, 0,
+                Fixed, index);
+
             storeOffset += storeSize - 1;
             previousStoreEndOffset = storeOffset + 1;
             continue;
-        } catch (...) {
+        }
+        catch (...) {
             // Parsing failed, try something else
         }
-not_marker:
+    not_marker:
         // Intel uCode
         try {
             // Check data size
             if (volumeBodySize - storeOffset < sizeof(INTEL_MICROCODE_HEADER)) {
                 goto not_ucode;
             }
-            
+
             const UINT32 currentUint32 = readUnaligned((const UINT32*)(volumeBody.constData() + storeOffset));
             if (currentUint32 != INTEL_MICROCODE_HEADER_VERSION_1) {
                 goto not_ucode;
             }
-            
+
             // Check microcode header candidate
             const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)(volumeBody.constData() + storeOffset);
             if (FALSE == ffsParser->microcodeHeaderValid(ucodeHeader)) {
                 goto not_ucode;
             }
-            
+
             // Check candidate size
             if (ucodeHeader->TotalSize == 0) {
                 goto not_ucode;
             }
-            
+
             // We still have enough data left to fit the whole TotalSize
             UINT32 storeSize = ucodeHeader->TotalSize;
             if (volumeBodySize - storeOffset < storeSize) {
                 goto not_ucode;
             }
-            
+
             // All checks passed, microcode found
             // Check if we need to add a padding before it
             if (!outerPadding.isEmpty()) {
                 info = usprintf("Full size: %Xh (%u)", (UINT32)outerPadding.size(), (UINT32)outerPadding.size());
-                model->addItem(localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding), UString("Padding"), UString(), info, UByteArray(), outerPadding, UByteArray(), Fixed, index);
+                model->addItem(
+                    localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding),
+                    UString("Padding"), UString(), info,
+                    0, outerPadding.size(), 0,
+                    Fixed, index);
                 outerPadding.clear();
             }
-            
+
             // Parse microcode header
             UByteArray ucode = volumeBody.mid(storeOffset);
             UModelIndex ucodeIndex;
             if (U_SUCCESS != ffsParser->parseIntelMicrocodeHeader(ucode, localOffset + storeOffset, index, ucodeIndex)) {
                 goto not_ucode;
             }
-            
+
             storeOffset += storeSize - 1;
             previousStoreEndOffset = storeOffset + 1;
             continue;
-        } catch (...) {
+        }
+        catch (...) {
             // Parsing failed, try something else
         }
-not_ucode:
+    not_ucode:
         // FFS volume
         try {
             // Check data size
             if (volumeBodySize - storeOffset < sizeof(EFI_FIRMWARE_VOLUME_HEADER)) {
                 goto not_ffs_volume;
             }
-            
+
             // Check volume header candidate
             const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(volumeBody.constData() + storeOffset);
             if (volumeHeader->Signature != EFI_FV_SIGNATURE) {
                 goto not_ffs_volume;
             }
-            
+
             // All checks passed, volume found
             UByteArray volume = volumeBody.mid(storeOffset);
             UModelIndex volumeIndex;
             if (U_SUCCESS != ffsParser->parseVolumeHeader(volume, localOffset + storeOffset, index, volumeIndex)) {
                 goto not_ffs_volume;
             }
-            
+
             (VOID)ffsParser->parseVolumeBody(volumeIndex);
-            UINT32 storeSize = (UINT32)(model->header(volumeIndex).size() + model->body(volumeIndex).size());
-            
+            UINT32 storeSize = (UINT32)(model->headerSize(volumeIndex) + model->bodySize(volumeIndex));
+
             storeOffset += storeSize - 1;
             previousStoreEndOffset = storeOffset + 1;
             continue;
-        } catch (...) {
+        }
+        catch (...) {
             // Parsing failed, try something else
         }
-not_ffs_volume:
+    not_ffs_volume:
         // Padding
         if (storeOffset < volumeBodySize) {
             outerPadding += volumeBody[storeOffset];
@@ -1523,15 +1690,24 @@ not_ffs_volume:
     if (!outerPadding.isEmpty()) {
         // Add info
         UString info = usprintf("Full size: %Xh (%u)", (UINT32)outerPadding.size(), (UINT32)outerPadding.size());
-        
+
         // Check that remaining unparsed bytes are actually empty
-        if (outerPadding.count(emptyByte) == outerPadding.size()) {
+        auto c = checkSingle(outerPadding);
+        if (c == emptyByte) {
             // Add tree item
-            model->addItem(localOffset + previousStoreEndOffset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), outerPadding, UByteArray(), Fixed, index);
+            model->addItem(
+                localOffset + previousStoreEndOffset, Types::FreeSpace, 0,
+                UString("Free space"), UString(), info,
+                0, outerPadding.size(), 0,
+                Fixed, index);
         }
         else {
             // Add tree item
-            model->addItem(localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding), UString("Padding"), UString(), info, UByteArray(), outerPadding, UByteArray(), Fixed, index);
+            model->addItem(
+                localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding),
+                UString("Padding"), UString(), info,
+                0, outerPadding.size(), 0,
+                Fixed, index);
         }
     }
 
diff --git a/common/nvramparser.h b/common/nvramparser.h
index a64e795..1716250 100644
--- a/common/nvramparser.h
+++ b/common/nvramparser.h
@@ -37,8 +37,8 @@ public:
     void clearMessages() { messagesVector.clear(); }
 
     // NVRAM parsing
-    USTATUS parseNvramVolumeBody(const UModelIndex & index, const UINT32 fdcStoreSizeOverride = 0);
-    USTATUS parseNvarStore(const UModelIndex & index);
+    USTATUS parseNvramVolumeBody(const UModelIndex& index, const UINT32 fdcStoreSizeOverride = 0);
+    USTATUS parseNvarStore(const UModelIndex & index, const bool probe = false);
     
 private:
     TreeModel *model;
@@ -63,7 +63,7 @@ public:
 
     // NVRAM parsing
     USTATUS parseNvramVolumeBody(const UModelIndex &) { return U_SUCCESS; }
-    USTATUS parseNvarStore(const UModelIndex &)  { return U_SUCCESS; }
+    USTATUS parseNvarStore(const UModelIndex &, const bool probe = false)  { return U_SUCCESS; }
 };
 #endif // U_ENABLE_NVRAM_PARSING_SUPPORT
 #endif // NVRAMPARSER_H
diff --git a/common/printf/printf.c b/common/printf/printf.c
new file mode 100644
index 0000000..77cfa1c
--- /dev/null
+++ b/common/printf/printf.c
@@ -0,0 +1,1509 @@
+/**
+ * @author (c) Eyal Rozenberg <eyalroz1@gmx.com>
+ *             2021-2023, Haifa, Palestine/Israel
+ * @author (c) Marco Paland (info@paland.com)
+ *             2014-2019, PALANDesign Hannover, Germany
+ *
+ * @note Others have made smaller contributions to this file: see the
+ * contributors page at https://github.com/eyalroz/printf/graphs/contributors
+ * or ask one of the authors. The original code for exponential specifiers was
+ * contributed by Martijn Jasperse <m.jasperse@gmail.com>.
+ *
+ * @brief Small stand-alone implementation of the printf family of functions
+ * (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems with
+ * limited resources.
+ *
+ * @note the implementations are thread-safe; re-entrant; use no functions from
+ * the standard library; and do not dynamically allocate any memory.
+ *
+ * @license The MIT License (MIT)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// Define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H=1 ...) to include the
+// printf_config.h header file
+#if PRINTF_INCLUDE_CONFIG_H
+#include "printf_config.h"
+#endif
+
+#include "printf/printf.h"
+
+#ifdef __cplusplus
+#include <cstdint>
+#include <climits>
+#else
+#include <stdint.h>
+#include <limits.h>
+#include <stdbool.h>
+#endif // __cplusplus
+
+#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD
+# define printf_    printf
+# define sprintf_   sprintf
+# define vsprintf_  vsprintf
+# define snprintf_  snprintf
+# define vsnprintf_ vsnprintf
+# define vprintf_   vprintf
+#endif
+
+
+// 'ntoa' conversion buffer size, this must be big enough to hold one converted
+// numeric number including padded zeros (dynamically created on stack)
+#ifndef PRINTF_INTEGER_BUFFER_SIZE
+#define PRINTF_INTEGER_BUFFER_SIZE    32
+#endif
+
+// size of the fixed (on-stack) buffer for printing individual decimal numbers.
+// this must be big enough to hold one converted floating-point value including
+// padded zeros.
+#ifndef PRINTF_DECIMAL_BUFFER_SIZE
+#define PRINTF_DECIMAL_BUFFER_SIZE    32
+#endif
+
+// Support for the decimal notation floating point conversion specifiers (%f, %F)
+#ifndef PRINTF_SUPPORT_DECIMAL_SPECIFIERS
+#define PRINTF_SUPPORT_DECIMAL_SPECIFIERS 1
+#endif
+
+// Support for the exponential notation floating point conversion specifiers (%e, %g, %E, %G)
+#ifndef PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
+#define PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS 1
+#endif
+
+// Support for the length write-back specifier (%n)
+#ifndef PRINTF_SUPPORT_WRITEBACK_SPECIFIER
+#define PRINTF_SUPPORT_WRITEBACK_SPECIFIER 1
+#endif
+
+// Default precision for the floating point conversion specifiers (the C standard sets this at 6)
+#ifndef PRINTF_DEFAULT_FLOAT_PRECISION
+#define PRINTF_DEFAULT_FLOAT_PRECISION  6
+#endif
+
+// Default choice of type to use for internal floating-point computations
+#ifndef PRINTF_USE_DOUBLE_INTERNALLY
+#define PRINTF_USE_DOUBLE_INTERNALLY  1
+#endif
+
+// According to the C languages standard, printf() and related functions must be able to print any
+// integral number in floating-point notation, regardless of length, when using the %f specifier -
+// possibly hundreds of characters, potentially overflowing your buffers. In this implementation,
+// all values beyond this threshold are switched to exponential notation.
+#ifndef PRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL
+#define PRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL 9
+#endif
+
+// Support for the long long integral types (with the ll, z and t length modifiers for specifiers
+// %d,%i,%o,%x,%X,%u, and with the %p specifier).
+#ifndef PRINTF_SUPPORT_LONG_LONG
+#define PRINTF_SUPPORT_LONG_LONG 1
+#endif
+
+// The number of terms in a Taylor series expansion of log_10(x) to
+// use for approximation - including the power-zero term (i.e. the
+// value at the point of expansion).
+#ifndef PRINTF_LOG10_TAYLOR_TERMS
+#define PRINTF_LOG10_TAYLOR_TERMS 4
+#endif
+
+#if PRINTF_LOG10_TAYLOR_TERMS <= 1
+#error "At least one non-constant Taylor expansion is necessary for the log10() calculation"
+#endif
+
+// Be extra-safe, and don't assume format specifiers are completed correctly
+// before the format string end.
+#ifndef PRINTF_CHECK_FOR_NUL_IN_FORMAT_SPECIFIER
+#define PRINTF_CHECK_FOR_NUL_IN_FORMAT_SPECIFIER 1
+#endif
+
+#define PRINTF_PREFER_DECIMAL     false
+#define PRINTF_PREFER_EXPONENTIAL true
+
+///////////////////////////////////////////////////////////////////////////////
+
+// The following will convert the number-of-digits into an exponential-notation literal
+#define PRINTF_CONCATENATE(s1, s2) s1##s2
+#define PRINTF_EXPAND_THEN_CONCATENATE(s1, s2) PRINTF_CONCATENATE(s1, s2)
+#define PRINTF_FLOAT_NOTATION_THRESHOLD ((floating_point_t) PRINTF_EXPAND_THEN_CONCATENATE(1e,PRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL))
+
+// internal flag definitions
+#define FLAGS_ZEROPAD     (1U <<  0U)
+#define FLAGS_LEFT        (1U <<  1U)
+#define FLAGS_PLUS        (1U <<  2U)
+#define FLAGS_SPACE       (1U <<  3U)
+#define FLAGS_HASH        (1U <<  4U)
+#define FLAGS_UPPERCASE   (1U <<  5U)
+#define FLAGS_CHAR        (1U <<  6U)
+#define FLAGS_SHORT       (1U <<  7U)
+#define FLAGS_INT         (1U <<  8U)
+  // Only used with PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS
+#define FLAGS_LONG        (1U <<  9U)
+#define FLAGS_LONG_LONG   (1U << 10U)
+#define FLAGS_PRECISION   (1U << 11U)
+#define FLAGS_ADAPT_EXP   (1U << 12U)
+#define FLAGS_POINTER     (1U << 13U)
+  // Note: Similar, but not identical, effect as FLAGS_HASH
+#define FLAGS_SIGNED      (1U << 14U)
+#define FLAGS_LONG_DOUBLE (1U << 15U)
+  // Only used with PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS
+
+#ifdef PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS
+
+#define FLAGS_INT8 FLAGS_CHAR
+
+
+#if   (SHRT_MAX   == 32767LL)
+#define FLAGS_INT16       FLAGS_SHORT
+#elif (INT_MAX    == 32767LL)
+#define FLAGS_INT16       FLAGS_INT
+#elif (LONG_MAX   == 32767LL)
+#define FLAGS_INT16       FLAGS_LONG
+#elif (LLONG_MAX  == 32767LL)
+#define FLAGS_INT16       FLAGS_LONG_LONG
+#else
+#error "No basic integer type has a size of 16 bits exactly"
+#endif
+
+#if   (SHRT_MAX   == 2147483647LL)
+#define FLAGS_INT32       FLAGS_SHORT
+#elif (INT_MAX    == 2147483647LL)
+#define FLAGS_INT32       FLAGS_INT
+#elif (LONG_MAX   == 2147483647LL)
+#define FLAGS_INT32       FLAGS_LONG
+#elif (LLONG_MAX  == 2147483647LL)
+#define FLAGS_INT32       FLAGS_LONG_LONG
+#else
+#error "No basic integer type has a size of 32 bits exactly"
+#endif
+
+#if   (SHRT_MAX   == 9223372036854775807LL)
+#define FLAGS_INT64       FLAGS_SHORT
+#elif (INT_MAX    == 9223372036854775807LL)
+#define FLAGS_INT64       FLAGS_INT
+#elif (LONG_MAX   == 9223372036854775807LL)
+#define FLAGS_INT64       FLAGS_LONG
+#elif (LLONG_MAX  == 9223372036854775807LL)
+#define FLAGS_INT64       FLAGS_LONG_LONG
+#else
+#error "No basic integer type has a size of 64 bits exactly"
+#endif
+
+#endif // PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS
+
+
+typedef unsigned int printf_flags_t;
+
+#define BASE_BINARY    2
+#define BASE_OCTAL     8
+#define BASE_DECIMAL  10
+#define BASE_HEX      16
+
+typedef uint8_t numeric_base_t;
+
+#if PRINTF_SUPPORT_LONG_LONG
+typedef unsigned long long printf_unsigned_value_t;
+typedef long long          printf_signed_value_t;
+#else
+typedef unsigned long printf_unsigned_value_t;
+typedef long          printf_signed_value_t;
+#endif
+
+// The printf()-family functions return an `int`; it is therefore
+// unnecessary/inappropriate to use size_t - often larger than int
+// in practice - for non-negative related values, such as widths,
+// precisions, offsets into buffers used for printing and the sizes
+// of these buffers. instead, we use:
+typedef unsigned int printf_size_t;
+#define PRINTF_MAX_POSSIBLE_BUFFER_SIZE INT_MAX
+  // If we were to nitpick, this would actually be INT_MAX + 1,
+  // since INT_MAX is the maximum return value, which excludes the
+  // trailing '\0'.
+
+#if (PRINTF_SUPPORT_DECIMAL_SPECIFIERS || PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS)
+#include <float.h>
+#if FLT_RADIX != 2
+#error "Non-binary-radix floating-point types are unsupported."
+#endif
+
+/**
+ * This library supports taking float-point arguments up to and including
+ * long double's; but - it currently does _not_ support internal
+ * representation and manipulation of values as long doubles; the options
+ * are either single-precision `float` or double-precision `double`.
+ */
+#if PRINTF_USE_DOUBLE_INTERNALLY
+typedef double floating_point_t;
+#define FP_TYPE_MANT_DIG DBL_MANT_DIG
+#else
+typedef float  floating_point_t;
+#define FP_TYPE_MANT_DIG FLT_MANT_DIG
+#endif
+
+#define NUM_DECIMAL_DIGITS_IN_INT64_T 18
+
+#if FP_TYPE_MANT_DIG == 24
+
+typedef uint32_t printf_fp_uint_t;
+#define FP_TYPE_SIZE_IN_BITS   32
+#define FP_TYPE_EXPONENT_MASK  0xFFU
+#define FP_TYPE_BASE_EXPONENT  127
+#define FP_TYPE_MAX            FLT_MAX
+#define FP_TYPE_MAX_10_EXP     FLT_MAX_10_EXP
+#define FP_TYPE_MAX_SUBNORMAL_EXPONENT_OF_10 -38
+#define FP_TYPE_MAX_SUBNORMAL_POWER_OF_10 1e-38f
+#define PRINTF_MAX_PRECOMPUTED_POWER_OF_10  10
+
+#elif FP_TYPE_MANT_DIG == 53
+
+typedef uint64_t printf_fp_uint_t;
+#define FP_TYPE_SIZE_IN_BITS   64
+#define FP_TYPE_EXPONENT_MASK  0x7FFU
+#define FP_TYPE_BASE_EXPONENT  1023
+#define FP_TYPE_MAX            DBL_MAX
+#define FP_TYPE_MAX_10_EXP     DBL_MAX_10_EXP
+#define FP_TYPE_MAX_10_EXP     DBL_MAX_10_EXP
+#define FP_TYPE_MAX_SUBNORMAL_EXPONENT_OF_10 -308
+#define FP_TYPE_MAX_SUBNORMAL_POWER_OF_10 1e-308
+#define PRINTF_MAX_PRECOMPUTED_POWER_OF_10  NUM_DECIMAL_DIGITS_IN_INT64_T - 1
+
+
+#else
+#error "Unsupported floating point type configuration"
+#endif
+#define FP_TYPE_STORED_MANTISSA_BITS (FP_TYPE_MANT_DIG - 1)
+
+typedef union {
+  printf_fp_uint_t  U;
+  floating_point_t  F;
+} floating_point_with_bit_access;
+
+// This is unnecessary in C99, since compound initializers can be used,
+// but:
+// 1. Some compilers are finicky about this;
+// 2. Some people may want to convert this to C89;
+// 3. If you try to use it as C++, only C++20 supports compound literals
+static inline floating_point_with_bit_access get_bit_access(floating_point_t x)
+{
+  floating_point_with_bit_access dwba;
+  dwba.F = x;
+  return dwba;
+}
+
+static inline int get_sign_bit(floating_point_t x)
+{
+  // The sign is stored in the highest bit
+  return (int) (get_bit_access(x).U >> (FP_TYPE_SIZE_IN_BITS - 1));
+}
+
+static inline int get_exp2(floating_point_with_bit_access x)
+{
+  // The exponent in an IEEE-754 floating-point number occupies a contiguous
+  // sequence of bits (e.g. 52..62 for 64-bit doubles), but with a non-trivial representation: An
+  // unsigned offset from some negative value (with the extremal offset values reserved for
+  // special use).
+  return (int)((x.U >> FP_TYPE_STORED_MANTISSA_BITS ) & FP_TYPE_EXPONENT_MASK) - FP_TYPE_BASE_EXPONENT;
+}
+#define PRINTF_ABS(_x) ( (_x) > 0 ? (_x) : -(_x) )
+
+#endif // (PRINTF_SUPPORT_DECIMAL_SPECIFIERS || PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS)
+
+// Note in particular the behavior here on LONG_MIN or LLONG_MIN; it is valid
+// and well-defined, but if you're not careful you can easily trigger undefined
+// behavior with -LONG_MIN or -LLONG_MIN
+#define ABS_FOR_PRINTING(_x) ((printf_unsigned_value_t) ( (_x) > 0 ? (_x) : -((printf_signed_value_t)_x) ))
+
+// wrapper (used as buffer) for output function type
+//
+// One of the following must hold:
+// 1. max_chars is 0
+// 2. buffer is non-null
+// 3. function is non-null
+//
+// ... otherwise bad things will happen.
+typedef struct {
+  void (*function)(char c, void* extra_arg);
+  void* extra_function_arg;
+  char* buffer;
+  printf_size_t pos;
+  printf_size_t max_chars;
+  bool flag_cstyle_Xh;
+} output_gadget_t;
+
+// Note: This function currently assumes it is not passed a '\0' c,
+// or alternatively, that '\0' can be passed to the function in the output
+// gadget. The former assumption holds within the printf library. It also
+// assumes that the output gadget has been properly initialized.
+static inline void putchar_via_gadget(output_gadget_t* gadget, char c)
+{
+  printf_size_t write_pos = gadget->pos++;
+    // We're _always_ increasing pos, so as to count how may characters
+    // _would_ have been written if not for the max_chars limitation
+  if (write_pos >= gadget->max_chars) {
+    return;
+  }
+  if (gadget->function != NULL) {
+    // No check for c == '\0' .
+    gadget->function(c, gadget->extra_function_arg);
+  }
+  else {
+    // it must be the case that gadget->buffer != NULL , due to the constraint
+    // on output_gadget_t ; and note we're relying on write_pos being non-negative.
+    gadget->buffer[write_pos] = c;
+  }
+}
+
+// Possibly-write the string-terminating '\0' character
+static inline void append_termination_with_gadget(output_gadget_t* gadget)
+{
+  if (gadget->function != NULL || gadget->max_chars == 0) {
+    return;
+  }
+  if (gadget->buffer == NULL) {
+    return;
+  }
+  printf_size_t null_char_pos = gadget->pos < gadget->max_chars ? gadget->pos : gadget->max_chars - 1;
+  gadget->buffer[null_char_pos] = '\0';
+}
+
+// We can't use putchar_ as is, since our output gadget
+// only takes pointers to functions with an extra argument
+static inline void putchar_wrapper(char c, void* unused)
+{
+  (void) unused;
+  putchar_(c);
+}
+
+static inline output_gadget_t discarding_gadget(void)
+{
+  output_gadget_t gadget;
+  gadget.function = NULL;
+  gadget.extra_function_arg = NULL;
+  gadget.buffer = NULL;
+  gadget.pos = 0;
+  gadget.max_chars = 0;
+  gadget.flag_cstyle_Xh = false;
+  return gadget;
+}
+
+static inline output_gadget_t buffer_gadget(char* buffer, size_t buffer_size)
+{
+  printf_size_t usable_buffer_size = (buffer_size > PRINTF_MAX_POSSIBLE_BUFFER_SIZE) ?
+    PRINTF_MAX_POSSIBLE_BUFFER_SIZE : (printf_size_t) buffer_size;
+  output_gadget_t result = discarding_gadget();
+  if (buffer != NULL) {
+    result.buffer = buffer;
+    result.max_chars = usable_buffer_size;
+  }
+  return result;
+}
+
+static inline output_gadget_t function_gadget(void (*function)(char, void*), void* extra_arg)
+{
+  output_gadget_t result = discarding_gadget();
+  result.function = function;
+  result.extra_function_arg = extra_arg;
+  result.max_chars = PRINTF_MAX_POSSIBLE_BUFFER_SIZE;
+  return result;
+}
+
+static inline output_gadget_t extern_putchar_gadget(void)
+{
+  return function_gadget(putchar_wrapper, NULL);
+}
+
+// internal secure strlen
+// @return The length of the string (excluding the terminating 0) limited by 'maxsize'
+// @note strlen uses size_t, but wes only use this function with printf_size_t
+// variables - hence the signature.
+static inline printf_size_t strnlen_s_(const char* str, printf_size_t maxsize)
+{
+  const char* s;
+  for (s = str; *s && maxsize--; ++s);
+  return (printf_size_t)(s - str);
+}
+
+
+// internal test if char is a digit (0-9)
+// @return true if char is a digit
+static inline bool is_digit_(char ch)
+{
+  return (ch >= '0') && (ch <= '9');
+}
+
+
+// internal ASCII string to printf_size_t conversion
+static printf_size_t atou_(const char** str)
+{
+  printf_size_t i = 0U;
+  while (is_digit_(**str)) {
+    i = i * 10U + (printf_size_t)(*((*str)++) - '0');
+  }
+  return i;
+}
+
+
+// output the specified string in reverse, taking care of any zero-padding
+static void out_rev_(output_gadget_t* output, const char* buf, printf_size_t len, printf_size_t width, printf_flags_t flags)
+{
+  const printf_size_t start_pos = output->pos;
+
+  // pad spaces up to given width
+  if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
+    for (printf_size_t i = len; i < width; i++) {
+      putchar_via_gadget(output, ' ');
+    }
+  }
+
+  // reverse string
+  while (len) {
+    putchar_via_gadget(output, buf[--len]);
+  }
+
+  // append pad spaces up to given width
+  if (flags & FLAGS_LEFT) {
+    while (output->pos - start_pos < width) {
+      putchar_via_gadget(output, ' ');
+    }
+  }
+}
+
+
+// Invoked by print_integer after the actual number has been printed, performing necessary
+// work on the number's prefix (as the number is initially printed in reverse order)
+static void print_integer_finalization(output_gadget_t* output, char* buf, printf_size_t len, bool negative, numeric_base_t base, printf_size_t precision, printf_size_t width, printf_flags_t flags)
+{
+  printf_size_t unpadded_len = len;
+
+  // pad with leading zeros
+  {
+    if (!(flags & FLAGS_LEFT)) {
+      if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
+        width--;
+      }
+      while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_INTEGER_BUFFER_SIZE)) {
+        buf[len++] = '0';
+      }
+    }
+
+    while ((len < precision) && (len < PRINTF_INTEGER_BUFFER_SIZE)) {
+      buf[len++] = '0';
+    }
+
+    if (base == BASE_OCTAL && (len > unpadded_len)) {
+      // Since we've written some zeros, we've satisfied the alternative format leading space requirement
+      flags &= ~FLAGS_HASH;
+    }
+  }
+
+  // handle hash
+  if (flags & (FLAGS_HASH | FLAGS_POINTER)) {
+    if (!(flags & FLAGS_PRECISION) && len && ((len == precision) || (len == width))) {
+      // Let's take back some padding digits to fit in what will eventually
+      // be the format-specific prefix
+      if (unpadded_len < len) {
+        len--; // This should suffice for BASE_OCTAL
+      }
+      if (len && (base == BASE_HEX || base == BASE_BINARY) && (unpadded_len < len)) {
+        len--; // ... and an extra one for 0x or 0b
+      }
+    }
+    if ((base == BASE_HEX) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_INTEGER_BUFFER_SIZE)) {
+      buf[len++] = 'x';
+    }
+    else if ((base == BASE_HEX) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_INTEGER_BUFFER_SIZE)) {
+      buf[len++] = 'X';
+    }
+    else if ((base == BASE_BINARY) && (len < PRINTF_INTEGER_BUFFER_SIZE)) {
+      buf[len++] = 'b';
+    }
+    if (len < PRINTF_INTEGER_BUFFER_SIZE) {
+      buf[len++] = '0';
+    }
+  }
+
+  if (len < PRINTF_INTEGER_BUFFER_SIZE) {
+    if (negative) {
+      buf[len++] = '-';
+    }
+    else if (flags & FLAGS_PLUS) {
+      buf[len++] = '+';  // ignore the space if the '+' exists
+    }
+    else if (flags & FLAGS_SPACE) {
+      buf[len++] = ' ';
+    }
+  }
+
+  out_rev_(output, buf, len, width, flags);
+}
+
+// An internal itoa-like function
+static void print_integer(output_gadget_t* output, printf_unsigned_value_t value, bool negative, numeric_base_t base, printf_size_t precision, printf_size_t width, printf_flags_t flags)
+{
+  char buf[PRINTF_INTEGER_BUFFER_SIZE];
+  printf_size_t len = 0U;
+
+  if (!value) {
+    if ( !(flags & FLAGS_PRECISION) ) {
+      buf[len++] = '0';
+      flags &= ~FLAGS_HASH;
+      // We drop this flag this since either the alternative and regular modes of the specifier
+      // don't differ on 0 values, or (in the case of octal) we've already provided the special
+      // handling for this mode.
+    }
+    else if (base == BASE_HEX) {
+      flags &= ~FLAGS_HASH;
+      // We drop this flag this since either the alternative and regular modes of the specifier
+      // don't differ on 0 values
+    }
+  }
+  else {
+    do {
+      const char digit = (char)(value % base);
+      buf[len++] = (char)(digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10);
+      value /= base;
+    } while (value && (len < PRINTF_INTEGER_BUFFER_SIZE));
+  }
+
+  print_integer_finalization(output, buf, len, negative, base, precision, width, flags);
+}
+
+#if (PRINTF_SUPPORT_DECIMAL_SPECIFIERS || PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS)
+
+// Stores a fixed-precision representation of a floating-point number relative
+// to a fixed precision (which cannot be determined by examining this structure)
+struct floating_point_components {
+  int_fast64_t integral;
+  int_fast64_t fractional;
+    // ... truncation of the actual fractional part of the floating_point_t value, scaled
+    // by the precision value
+  bool is_negative;
+};
+
+static const floating_point_t powers_of_10[PRINTF_MAX_PRECOMPUTED_POWER_OF_10 + 1] = {
+  1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, 1e10
+#if PRINTF_MAX_PRECOMPUTED_POWER_OF_10 > 10
+  , 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17
+#endif
+};
+
+// Note: This value does not mean that all floating-point values printed with the
+// library will be correct up to this precision; it is just an upper-bound for
+// avoiding buffer overruns and such
+#define PRINTF_MAX_SUPPORTED_PRECISION (NUM_DECIMAL_DIGITS_IN_INT64_T - 1)
+
+
+// Break up a floating-point number - which is known to be a finite non-negative number -
+// into its base-10 parts: integral - before the decimal point, and fractional - after it.
+// Taken the precision into account, but does not change it even internally.
+static struct floating_point_components get_components(floating_point_t number, printf_size_t precision)
+{
+  struct floating_point_components number_;
+  number_.is_negative = get_sign_bit(number);
+  floating_point_t abs_number = (number_.is_negative) ? -number : number;
+  number_.integral = (int_fast64_t) abs_number;
+  floating_point_t scaled_remainder = (abs_number - (floating_point_t) number_.integral) * powers_of_10[precision];
+  number_.fractional = (int_fast64_t) scaled_remainder; // for precision == 0U, this will be 0
+
+  floating_point_t remainder = scaled_remainder - (floating_point_t) number_.fractional;
+  const floating_point_t one_half = (floating_point_t)  0.5;
+
+  if (remainder > one_half) {
+    ++number_.fractional;
+    // handle rollover, e.g. case 0.99 with precision 1 is 1.0
+    if ((floating_point_t) number_.fractional >= powers_of_10[precision]) {
+      number_.fractional = 0;
+      ++number_.integral;
+    }
+  }
+  else if ((remainder == one_half) && (number_.fractional & 1U)) {
+    // Banker's rounding, i.e. round half to even:
+    // 1.5 -> 2, but 2.5 -> 2
+    ++number_.fractional;
+  }
+
+  if (precision == 0U) {
+    remainder = abs_number - (floating_point_t) number_.integral;
+    if ((remainder == one_half) && (number_.integral & 1U)) {
+      // Banker's rounding, i.e. round half to even:
+      // 1.5 -> 2, but 2.5 -> 2
+      ++number_.integral;
+    }
+  }
+  return number_;
+}
+
+#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
+struct scaling_factor {
+  floating_point_t raw_factor;
+  bool multiply; // if true, need to multiply by raw_factor; otherwise need to divide by it
+};
+
+static floating_point_t apply_scaling(floating_point_t num, struct scaling_factor normalization)
+{
+  return normalization.multiply ? num * normalization.raw_factor : num / normalization.raw_factor;
+}
+
+static floating_point_t unapply_scaling(floating_point_t normalized, struct scaling_factor normalization)
+{
+#ifdef __GNUC__
+// accounting for a static analysis bug in GCC 6.x and earlier
+#pragma GCC diagnostic push
+#if !defined(__has_warning)
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#elif __has_warning("-Wmaybe-uninitialized")
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+#endif
+  return normalization.multiply ? normalized / normalization.raw_factor : normalized * normalization.raw_factor;
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+}
+
+static struct scaling_factor update_normalization(struct scaling_factor sf, floating_point_t extra_multiplicative_factor)
+{
+  struct scaling_factor result;
+  if (sf.multiply) {
+    result.multiply = true;
+    result.raw_factor = sf.raw_factor * extra_multiplicative_factor;
+  }
+  else {
+    int factor_exp2 = get_exp2(get_bit_access(sf.raw_factor));
+    int extra_factor_exp2 = get_exp2(get_bit_access(extra_multiplicative_factor));
+
+    // Divide the larger-exponent raw raw_factor by the smaller
+    if (PRINTF_ABS(factor_exp2) > PRINTF_ABS(extra_factor_exp2)) {
+      result.multiply = false;
+      result.raw_factor = sf.raw_factor / extra_multiplicative_factor;
+    }
+    else {
+      result.multiply = true;
+      result.raw_factor = extra_multiplicative_factor / sf.raw_factor;
+    }
+  }
+  return result;
+}
+
+static struct floating_point_components get_normalized_components(bool negative, printf_size_t precision, floating_point_t non_normalized, struct scaling_factor normalization, int floored_exp10)
+{
+  struct floating_point_components components;
+  components.is_negative = negative;
+  floating_point_t scaled = apply_scaling(non_normalized, normalization);
+
+  bool close_to_representation_extremum = ( (-floored_exp10 + (int) precision) >= FP_TYPE_MAX_10_EXP - 1 );
+  if (close_to_representation_extremum) {
+    // We can't have a normalization factor which also accounts for the precision, i.e. moves
+    // some decimal digits into the mantissa, since it's unrepresentable, or nearly unrepresentable.
+    // So, we'll give up early on getting extra precision...
+    return get_components(negative ? -scaled : scaled, precision);
+  }
+  components.integral = (int_fast64_t) scaled;
+  floating_point_t remainder = non_normalized - unapply_scaling((floating_point_t) components.integral, normalization);
+  floating_point_t prec_power_of_10 = powers_of_10[precision];
+  struct scaling_factor account_for_precision = update_normalization(normalization, prec_power_of_10);
+  floating_point_t scaled_remainder = apply_scaling(remainder, account_for_precision);
+  floating_point_t rounding_threshold = 0.5;
+
+  components.fractional = (int_fast64_t) scaled_remainder; // when precision == 0, the assigned value should be 0
+  scaled_remainder -= (floating_point_t) components.fractional; //when precision == 0, this will not change scaled_remainder
+
+  components.fractional += (scaled_remainder >= rounding_threshold);
+  if (scaled_remainder == rounding_threshold) {
+    // banker's rounding: Round towards the even number (making the mean error 0)
+    components.fractional &= ~((int_fast64_t) 0x1);
+  }
+  // handle rollover, e.g. the case of 0.99 with precision 1 becoming (0,100),
+  // and must then be corrected into (1, 0).
+  // Note: for precision = 0, this will "translate" the rounding effect from
+  // the fractional part to the integral part where it should actually be
+  // felt (as prec_power_of_10 is 1)
+  if ((floating_point_t) components.fractional >= prec_power_of_10) {
+    components.fractional = 0;
+    ++components.integral;
+  }
+  return components;
+}
+#endif // PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
+
+static void print_broken_up_decimal(
+  struct floating_point_components number_, output_gadget_t* output, printf_size_t precision,
+  printf_size_t width, printf_flags_t flags, char *buf, printf_size_t len)
+{
+  if (precision != 0U) {
+    // do fractional part, as an unsigned number
+
+    printf_size_t count = precision;
+
+    // %g/%G mandates we skip the trailing 0 digits...
+    if ((flags & FLAGS_ADAPT_EXP) && !(flags & FLAGS_HASH) && (number_.fractional > 0)) {
+      while(true) {
+        int_fast64_t digit = number_.fractional % 10U;
+        if (digit != 0) {
+          break;
+        }
+        --count;
+        number_.fractional /= 10U;
+
+      }
+      // ... and even the decimal point if there are no
+      // non-zero fractional part digits (see below)
+    }
+
+    if (number_.fractional > 0 || !(flags & FLAGS_ADAPT_EXP) || (flags & FLAGS_HASH) ) {
+      while (len < PRINTF_DECIMAL_BUFFER_SIZE) {
+        --count;
+        buf[len++] = (char)('0' + number_.fractional % 10U);
+        if (!(number_.fractional /= 10U)) {
+          break;
+        }
+      }
+      // add extra 0s
+      while ((len < PRINTF_DECIMAL_BUFFER_SIZE) && (count > 0U)) {
+        buf[len++] = '0';
+        --count;
+      }
+      if (len < PRINTF_DECIMAL_BUFFER_SIZE) {
+        buf[len++] = '.';
+      }
+    }
+  }
+  else {
+    if ((flags & FLAGS_HASH) && (len < PRINTF_DECIMAL_BUFFER_SIZE)) {
+      buf[len++] = '.';
+    }
+  }
+
+  // Write the integer part of the number (it comes after the fractional
+  // since the character order is reversed)
+  while (len < PRINTF_DECIMAL_BUFFER_SIZE) {
+    buf[len++] = (char)('0' + (number_.integral % 10));
+    if (!(number_.integral /= 10)) {
+      break;
+    }
+  }
+
+  // pad leading zeros
+  if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
+    if (width && (number_.is_negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
+      width--;
+    }
+    while ((len < width) && (len < PRINTF_DECIMAL_BUFFER_SIZE)) {
+      buf[len++] = '0';
+    }
+  }
+
+  if (len < PRINTF_DECIMAL_BUFFER_SIZE) {
+    if (number_.is_negative) {
+      buf[len++] = '-';
+    }
+    else if (flags & FLAGS_PLUS) {
+      buf[len++] = '+';  // ignore the space if the '+' exists
+    }
+    else if (flags & FLAGS_SPACE) {
+      buf[len++] = ' ';
+    }
+  }
+
+  out_rev_(output, buf, len, width, flags);
+}
+
+// internal ftoa for fixed decimal floating point
+static void print_decimal_number(output_gadget_t* output, floating_point_t number, printf_size_t precision, printf_size_t width, printf_flags_t flags, char* buf, printf_size_t len)
+{
+  struct floating_point_components value_ = get_components(number, precision);
+  print_broken_up_decimal(value_, output, precision, width, flags, buf, len);
+}
+
+#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
+
+// A floor function - but one which only works for numbers whose
+// floor value is representable by an int.
+static int bastardized_floor(floating_point_t x)
+{
+  if (x >= 0) { return (int) x; }
+  int n = (int) x;
+  return ( ((floating_point_t) n) == x ) ? n : n-1;
+}
+
+// Computes the base-10 logarithm of the input number - which must be an actual
+// positive number (not infinity or NaN, nor a sub-normal)
+static floating_point_t log10_of_positive(floating_point_t positive_number)
+{
+  // The implementation follows David Gay (https://www.ampl.com/netlib/fp/dtoa.c).
+  //
+  // Since log_10 ( M * 2^x ) = log_10(M) + x , we can separate the components of
+  // our input number, and need only solve log_10(M) for M between 1 and 2 (as
+  // the base-2 mantissa is always 1-point-something). In that limited range, a
+  // Taylor series expansion of log10(x) should serve us well enough; and we'll
+  // take the mid-point, 1.5, as the point of expansion.
+
+  floating_point_with_bit_access dwba = get_bit_access(positive_number);
+  // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
+  int exp2 = get_exp2(dwba);
+  // drop the exponent, so dwba.F comes into the range [1,2)
+  dwba.U = (dwba.U & (((printf_fp_uint_t) (1) << FP_TYPE_STORED_MANTISSA_BITS) - 1U)) |
+           ((printf_fp_uint_t) FP_TYPE_BASE_EXPONENT << FP_TYPE_STORED_MANTISSA_BITS);
+  floating_point_t z = (dwba.F - (floating_point_t) 1.5);
+  return (
+    // Taylor expansion around 1.5:
+              (floating_point_t) 0.1760912590556812420           // Expansion term 0: ln(1.5)            / ln(10)
+    + z     * (floating_point_t) 0.2895296546021678851 // Expansion term 1: (M - 1.5)   * 2/3  / ln(10)
+#if PRINTF_LOG10_TAYLOR_TERMS > 2
+    - z*z   * (floating_point_t) 0.0965098848673892950 // Expansion term 2: (M - 1.5)^2 * 2/9  / ln(10)
+#if PRINTF_LOG10_TAYLOR_TERMS > 3
+    + z*z*z * (floating_point_t) 0.0428932821632841311 // Expansion term 2: (M - 1.5)^3 * 8/81 / ln(10)
+#endif
+#endif
+    // exact log_2 of the exponent x, with logarithm base change
+    + (floating_point_t) exp2 * (floating_point_t) 0.30102999566398119521 // = exp2 * log_10(2) = exp2 * ln(2)/ln(10)
+  );
+}
+
+
+static floating_point_t pow10_of_int(int floored_exp10)
+{
+  // A crude hack for avoiding undesired behavior with barely-normal or slightly-subnormal values.
+  if (floored_exp10 == FP_TYPE_MAX_SUBNORMAL_EXPONENT_OF_10) {
+    return FP_TYPE_MAX_SUBNORMAL_POWER_OF_10;
+  }
+  // Compute 10^(floored_exp10) but (try to) make sure that doesn't overflow
+  floating_point_with_bit_access dwba;
+  int exp2 = bastardized_floor((floating_point_t) (floored_exp10 * 3.321928094887362 + 0.5));
+  const floating_point_t z  = (floating_point_t) (floored_exp10 * 2.302585092994046 - exp2 * 0.6931471805599453);
+  const floating_point_t z2 = z * z;
+  dwba.U = ((printf_fp_uint_t)(exp2) + FP_TYPE_BASE_EXPONENT) << FP_TYPE_STORED_MANTISSA_BITS;
+  // compute exp(z) using continued fractions,
+  // see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
+  dwba.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
+  return dwba.F;
+}
+
+static void print_exponential_number(output_gadget_t* output, floating_point_t number, printf_size_t precision, printf_size_t width, printf_flags_t flags, char* buf, printf_size_t len)
+{
+  const bool negative = get_sign_bit(number);
+  // This number will decrease gradually (by factors of 10) as we "extract" the exponent out of it
+  floating_point_t abs_number =  negative ? -number : number;
+
+  int floored_exp10;
+  bool abs_exp10_covered_by_powers_table;
+  struct scaling_factor normalization;
+
+
+  // Determine the decimal exponent
+  if (abs_number == (floating_point_t) 0.0) {
+    // TODO: This is a special-case for 0.0 (and -0.0); but proper handling is required for denormals more generally.
+    floored_exp10 = 0; // ... and no need to set a normalization factor or check the powers table
+  }
+  else  {
+    floating_point_t exp10 = log10_of_positive(abs_number);
+    floored_exp10 = bastardized_floor(exp10);
+    floating_point_t p10 = pow10_of_int(floored_exp10);
+    // correct for rounding errors
+    if (abs_number < p10) {
+      floored_exp10--;
+      p10 /= 10;
+    }
+    abs_exp10_covered_by_powers_table = PRINTF_ABS(floored_exp10) < PRINTF_MAX_PRECOMPUTED_POWER_OF_10;
+    normalization.raw_factor = abs_exp10_covered_by_powers_table ? powers_of_10[PRINTF_ABS(floored_exp10)] : p10;
+  }
+
+  // We now begin accounting for the widths of the two parts of our printed field:
+  // the decimal part after decimal exponent extraction, and the base-10 exponent part.
+  // For both of these, the value of 0 has a special meaning, but not the same one:
+  // a 0 exponent-part width means "don't print the exponent"; a 0 decimal-part width
+  // means "use as many characters as necessary".
+
+  bool fall_back_to_decimal_only_mode = false;
+  if (flags & FLAGS_ADAPT_EXP) {
+    int required_significant_digits = (precision == 0) ? 1 : (int) precision;
+    // Should we want to fall-back to "%f" mode, and only print the decimal part?
+    fall_back_to_decimal_only_mode = (floored_exp10 >= -4 && floored_exp10 < required_significant_digits);
+    // Now, let's adjust the precision
+    // This also decided how we adjust the precision value - as in "%g" mode,
+    // "precision" is the number of _significant digits_, and this is when we "translate"
+    // the precision value to an actual number of decimal digits.
+    int precision_ = fall_back_to_decimal_only_mode ?
+                     (int) precision - 1 - floored_exp10 :
+        (int) precision - 1; // the presence of the exponent ensures only one significant digit comes before the decimal point
+    precision = (precision_ > 0 ? (unsigned) precision_ : 0U);
+    flags |= FLAGS_PRECISION;   // make sure print_broken_up_decimal respects our choice above
+  }
+
+#ifdef __GNUC__
+// accounting for a static analysis bug in GCC 6.x and earlier
+#pragma GCC diagnostic push
+#if !defined(__has_warning)
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#elif __has_warning("-Wmaybe-uninitialized")
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+#endif
+  normalization.multiply = (floored_exp10 < 0 && abs_exp10_covered_by_powers_table);
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+  bool should_skip_normalization = (fall_back_to_decimal_only_mode || floored_exp10 == 0);
+  struct floating_point_components decimal_part_components =
+    should_skip_normalization ?
+    get_components(negative ? -abs_number : abs_number, precision) :
+    get_normalized_components(negative, precision, abs_number, normalization, floored_exp10);
+
+  // Account for roll-over, e.g. rounding from 9.99 to 100.0 - which effects
+  // the exponent and may require additional tweaking of the parts
+  if (fall_back_to_decimal_only_mode) {
+    if ((flags & FLAGS_ADAPT_EXP) && floored_exp10 >= -1 && decimal_part_components.integral == powers_of_10[floored_exp10 + 1]) {
+      floored_exp10++; // Not strictly necessary, since floored_exp10 is no longer really used
+      if (precision > 0U) { precision--; }
+      // ... and it should already be the case that decimal_part_components.fractional == 0
+    }
+    // TODO: What about rollover strictly within the fractional part?
+  }
+  else {
+    if (decimal_part_components.integral >= 10) {
+      floored_exp10++;
+      decimal_part_components.integral = 1;
+      decimal_part_components.fractional = 0;
+    }
+  }
+
+  // the floored_exp10 format is "E%+03d" and largest possible floored_exp10 value for a 64-bit double
+  // is "307" (for 2^1023), so we set aside 4-5 characters overall
+  printf_size_t exp10_part_width = fall_back_to_decimal_only_mode ? 0U : (PRINTF_ABS(floored_exp10) < 100) ? 4U : 5U;
+
+  printf_size_t decimal_part_width =
+    ((flags & FLAGS_LEFT) && exp10_part_width) ?
+      // We're padding on the right, so the width constraint is the exponent part's
+      // problem, not the decimal part's, so we'll use as many characters as we need:
+      0U :
+      // We're padding on the left; so the width constraint is the decimal part's
+      // problem. Well, can both the decimal part and the exponent part fit within our overall width?
+      ((width > exp10_part_width) ?
+        // Yes, so we limit our decimal part's width.
+        // (Note this is trivially valid even if we've fallen back to "%f" mode)
+        width - exp10_part_width :
+        // No; we just give up on any restriction on the decimal part and use as many
+        // characters as we need
+        0U);
+
+  const printf_size_t printed_exponential_start_pos = output->pos;
+  print_broken_up_decimal(decimal_part_components, output, precision, decimal_part_width, flags, buf, len);
+
+  if (! fall_back_to_decimal_only_mode) {
+    putchar_via_gadget(output, (flags & FLAGS_UPPERCASE) ? 'E' : 'e');
+    print_integer(output,
+                  ABS_FOR_PRINTING(floored_exp10),
+                  floored_exp10 < 0, 10, 0, exp10_part_width - 1,
+                FLAGS_ZEROPAD | FLAGS_PLUS);
+    if (flags & FLAGS_LEFT) {
+      // We need to right-pad with spaces to meet the width requirement
+      while (output->pos - printed_exponential_start_pos < width) {
+        putchar_via_gadget(output, ' ');
+      }
+    }
+  }
+}
+#endif  // PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
+
+static void print_floating_point(output_gadget_t* output, floating_point_t value, printf_size_t precision, printf_size_t width, printf_flags_t flags, bool prefer_exponential)
+{
+  char buf[PRINTF_DECIMAL_BUFFER_SIZE];
+  printf_size_t len = 0U;
+
+  // test for special values
+  if (value != value) {
+    out_rev_(output, "nan", 3, width, flags);
+    return;
+  }
+  if (value < -FP_TYPE_MAX) {
+    out_rev_(output, "fni-", 4, width, flags);
+    return;
+  }
+  if (value > FP_TYPE_MAX) {
+    out_rev_(output, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
+    return;
+  }
+
+  if (!prefer_exponential &&
+      ((value > PRINTF_FLOAT_NOTATION_THRESHOLD) || (value < -PRINTF_FLOAT_NOTATION_THRESHOLD))) {
+    // The required behavior of standard printf is to print _every_ integral-part digit -- which could mean
+    // printing hundreds of characters, overflowing any fixed internal buffer and necessitating a more complicated
+    // implementation.
+#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
+    print_exponential_number(output, value, precision, width, flags, buf, len);
+#endif
+    return;
+  }
+
+  // set default precision, if not set explicitly
+  if (!(flags & FLAGS_PRECISION)) {
+    precision = PRINTF_DEFAULT_FLOAT_PRECISION;
+  }
+
+  // limit precision so that our integer holding the fractional part does not overflow
+  while ((len < PRINTF_DECIMAL_BUFFER_SIZE) && (precision > PRINTF_MAX_SUPPORTED_PRECISION)) {
+    buf[len++] = '0'; // This respects the precision in terms of result length only
+    precision--;
+  }
+
+#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
+  if (prefer_exponential)
+    print_exponential_number(output, value, precision, width, flags, buf, len);
+  else
+#endif
+    print_decimal_number(output, value, precision, width, flags, buf, len);
+}
+
+#endif  // (PRINTF_SUPPORT_DECIMAL_SPECIFIERS || PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS)
+
+// Advances the format pointer past the flags, and returns the parsed flags
+// due to the characters passed
+static printf_flags_t parse_flags(const char** format)
+{
+  printf_flags_t flags = 0U;
+  do {
+    switch (**format) {
+      case '0': flags |= FLAGS_ZEROPAD; (*format)++; break;
+      case '-': flags |= FLAGS_LEFT;    (*format)++; break;
+      case '+': flags |= FLAGS_PLUS;    (*format)++; break;
+      case ' ': flags |= FLAGS_SPACE;   (*format)++; break;
+      case '#': flags |= FLAGS_HASH;    (*format)++; break;
+      default : return flags;
+    }
+  } while (true);
+}
+
+static inline void format_string_loop(output_gadget_t* output, const char* format, va_list args)
+{
+#if PRINTF_CHECK_FOR_NUL_IN_FORMAT_SPECIFIER
+#define ADVANCE_IN_FORMAT_STRING(cptr_) do { (cptr_)++; if (!*(cptr_)) return; } while(0)
+#else
+#define ADVANCE_IN_FORMAT_STRING(cptr_) (cptr_)++
+#endif
+
+
+  while (*format)
+  {
+    if (*format != '%') {
+      // A regular content character
+      putchar_via_gadget(output, *format);
+      format++;
+      continue;
+    }
+    // We're parsing a format specifier: %[flags][width][.precision][length]
+    ADVANCE_IN_FORMAT_STRING(format);
+
+    printf_flags_t flags = parse_flags(&format);
+
+    // evaluate width field
+    printf_size_t width = 0U;
+    if (is_digit_(*format)) {
+      width = (printf_size_t) atou_(&format);
+    }
+    else if (*format == '*') {
+      const int w = va_arg(args, int);
+      if (w < 0) {
+        flags |= FLAGS_LEFT;    // reverse padding
+        width = (printf_size_t)-w;
+      }
+      else {
+        width = (printf_size_t)w;
+      }
+      ADVANCE_IN_FORMAT_STRING(format);
+    }
+
+    // evaluate precision field
+    printf_size_t precision = 0U;
+    if (*format == '.') {
+      flags |= FLAGS_PRECISION;
+      ADVANCE_IN_FORMAT_STRING(format);
+      if (is_digit_(*format)) {
+        precision = (printf_size_t) atou_(&format);
+      }
+      else if (*format == '*') {
+        const int precision_ = va_arg(args, int);
+        precision = precision_ > 0 ? (printf_size_t) precision_ : 0U;
+        ADVANCE_IN_FORMAT_STRING(format);
+      }
+    }
+
+    // evaluate length field
+    switch (*format) {
+#ifdef PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS
+      case 'I' : {
+        ADVANCE_IN_FORMAT_STRING(format);
+        // Greedily parse for size in bits: 8, 16, 32 or 64
+        switch(*format) {
+          case '8':               flags |= FLAGS_INT8;
+            ADVANCE_IN_FORMAT_STRING(format);
+            break;
+          case '1':
+            ADVANCE_IN_FORMAT_STRING(format);
+          if (*format == '6') { format++; flags |= FLAGS_INT16; }
+            break;
+          case '3':
+            ADVANCE_IN_FORMAT_STRING(format);
+            if (*format == '2') { ADVANCE_IN_FORMAT_STRING(format); flags |= FLAGS_INT32; }
+            break;
+          case '6':
+            ADVANCE_IN_FORMAT_STRING(format);
+            if (*format == '4') { ADVANCE_IN_FORMAT_STRING(format); flags |= FLAGS_INT64; }
+            break;
+          default: break;
+        }
+        break;
+      }
+#endif
+      case 'l' :
+        flags |= FLAGS_LONG;
+        ADVANCE_IN_FORMAT_STRING(format);
+        if (*format == 'l') {
+          flags |= FLAGS_LONG_LONG;
+          ADVANCE_IN_FORMAT_STRING(format);
+        }
+        break;
+      case 'L' :
+        flags |= FLAGS_LONG_DOUBLE;
+        ADVANCE_IN_FORMAT_STRING(format);
+        break;
+      case 'h' :
+        flags |= FLAGS_SHORT;
+        ADVANCE_IN_FORMAT_STRING(format);
+        if (*format == 'h') {
+          flags |= FLAGS_CHAR;
+          ADVANCE_IN_FORMAT_STRING(format);
+        }
+        break;
+      case 't' :
+        flags |= (sizeof(ptrdiff_t) <= sizeof(int) ) ? FLAGS_INT : (sizeof(ptrdiff_t) == sizeof(long)) ? FLAGS_LONG : FLAGS_LONG_LONG;
+        ADVANCE_IN_FORMAT_STRING(format);
+        break;
+      case 'j' :
+        flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
+        ADVANCE_IN_FORMAT_STRING(format);
+        break;
+      case 'z' :
+        flags |= (sizeof(size_t) <= sizeof(int) ) ? FLAGS_INT : (sizeof(size_t) == sizeof(long)) ? FLAGS_LONG : FLAGS_LONG_LONG;
+        ADVANCE_IN_FORMAT_STRING(format);
+        break;
+      default:
+        break;
+    }
+
+    // evaluate specifier
+    switch (*format) {
+      case 'd' :
+      case 'i' :
+      case 'u' :
+      case 'x' :
+      case 'X' :
+      case 'o' :
+      case 'b' : {
+
+        if (*format == 'd' || *format == 'i') {
+          flags |= FLAGS_SIGNED;
+        }
+
+        numeric_base_t base;
+        if (*format == 'x' || *format == 'X') {
+          base = BASE_HEX;
+        }
+        else if (*format == 'o') {
+          base =  BASE_OCTAL;
+        }
+        else if (*format == 'b') {
+          base =  BASE_BINARY;
+        }
+        else {
+          base = BASE_DECIMAL;
+          flags &= ~FLAGS_HASH; // decimal integers have no alternative presentation
+        }
+
+        if (*format == 'X') {
+          flags |= FLAGS_UPPERCASE;
+        }
+
+        format++;
+        if (base == BASE_HEX) {
+            if (*format == 'h' && output->flag_cstyle_Xh) {
+                putchar_via_gadget(output, '0');
+                putchar_via_gadget(output, 'x');
+                format++;
+            }
+        }
+        // ignore '0' flag when precision is given
+        if (flags & FLAGS_PRECISION) {
+          flags &= ~FLAGS_ZEROPAD;
+        }
+
+        if (flags & FLAGS_SIGNED) {
+          // A signed specifier: d, i or possibly I + bit size if enabled
+
+          if (flags & FLAGS_LONG_LONG) {
+#if PRINTF_SUPPORT_LONG_LONG
+            const long long value = va_arg(args, long long);
+            print_integer(output, ABS_FOR_PRINTING(value), value < 0, base, precision, width, flags);
+#endif
+          }
+          else if (flags & FLAGS_LONG) {
+            const long value = va_arg(args, long);
+            print_integer(output, ABS_FOR_PRINTING(value), value < 0, base, precision, width, flags);
+          }
+          else {
+            // We never try to interpret the argument as something potentially-smaller than int,
+            // due to integer promotion rules: Even if the user passed a short int, short unsigned
+            // etc. - these will come in after promotion, as int's (or unsigned for the case of
+            // short unsigned when it has the same size as int)
+            const int value =
+              (flags & FLAGS_CHAR) ? (signed char) va_arg(args, int) :
+              (flags & FLAGS_SHORT) ? (short int) va_arg(args, int) :
+              va_arg(args, int);
+            print_integer(output, ABS_FOR_PRINTING(value), value < 0, base, precision, width, flags);
+          }
+        }
+        else {
+          // An unsigned specifier: u, x, X, o, b
+
+          flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
+
+          if (flags & FLAGS_LONG_LONG) {
+#if PRINTF_SUPPORT_LONG_LONG
+            print_integer(output, (printf_unsigned_value_t) va_arg(args, unsigned long long), false, base, precision, width, flags);
+#endif
+          }
+          else if (flags & FLAGS_LONG) {
+            print_integer(output, (printf_unsigned_value_t) va_arg(args, unsigned long), false, base, precision, width, flags);
+          }
+          else {
+            const unsigned int value =
+              (flags & FLAGS_CHAR) ? (unsigned char)va_arg(args, unsigned int) :
+              (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(args, unsigned int) :
+              va_arg(args, unsigned int);
+            print_integer(output, (printf_unsigned_value_t) value, false, base, precision, width, flags);
+          }
+        }
+        break;
+      }
+#if PRINTF_SUPPORT_DECIMAL_SPECIFIERS
+      case 'f' :
+      case 'F' : {
+        floating_point_t value = (floating_point_t) (flags & FLAGS_LONG_DOUBLE ? va_arg(args, long double) : va_arg(args, double));
+        if (*format == 'F') flags |= FLAGS_UPPERCASE;
+        print_floating_point(output, value, precision, width, flags, PRINTF_PREFER_DECIMAL);
+        format++;
+        break;
+      }
+#endif
+#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
+      case 'e':
+      case 'E':
+      case 'g':
+      case 'G': {
+        floating_point_t value = (floating_point_t) (flags & FLAGS_LONG_DOUBLE ? va_arg(args, long double) : va_arg(args, double));
+        if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP;
+        if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE;
+        print_floating_point(output, value, precision, width, flags, PRINTF_PREFER_EXPONENTIAL);
+        format++;
+        break;
+      }
+#endif  // PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
+      case 'c' : {
+        printf_size_t l = 1U;
+        // pre padding
+        if (!(flags & FLAGS_LEFT)) {
+          while (l++ < width) {
+            putchar_via_gadget(output, ' ');
+          }
+        }
+        // char output
+        putchar_via_gadget(output, (char) va_arg(args, int) );
+        // post padding
+        if (flags & FLAGS_LEFT) {
+          while (l++ < width) {
+            putchar_via_gadget(output, ' ');
+          }
+        }
+        format++;
+        break;
+      }
+
+      case 's' : {
+        const char* p = va_arg(args, char*);
+        if (p == NULL) {
+          out_rev_(output, ")llun(", 6, width, flags);
+        }
+        else {
+          printf_size_t l = strnlen_s_(p, precision ? precision : PRINTF_MAX_POSSIBLE_BUFFER_SIZE);
+          // pre padding
+          if (flags & FLAGS_PRECISION) {
+            l = (l < precision ? l : precision);
+          }
+          if (!(flags & FLAGS_LEFT)) {
+            while (l++ < width) {
+              putchar_via_gadget(output, ' ');
+            }
+          }
+          // string output
+          while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision)) {
+            putchar_via_gadget(output, *(p++));
+            --precision;
+          }
+          // post padding
+          if (flags & FLAGS_LEFT) {
+            while (l++ < width) {
+              putchar_via_gadget(output, ' ');
+            }
+          }
+        }
+        format++;
+        break;
+      }
+
+      case 'p' : {
+        width = sizeof(void*) * 2U + 2; // 2 hex chars per byte + the "0x" prefix
+        flags |= FLAGS_ZEROPAD | FLAGS_POINTER;
+        uintptr_t value = (uintptr_t)va_arg(args, void*);
+        (value == (uintptr_t) NULL) ?
+          out_rev_(output, ")lin(", 5, width, flags) :
+          print_integer(output, (printf_unsigned_value_t) value, false, BASE_HEX, precision, width, flags);
+        format++;
+        break;
+      }
+
+      case '%' :
+        putchar_via_gadget(output, '%');
+        format++;
+        break;
+
+      // Many people prefer to disable support for %n, as it lets the caller
+      // engineer a write to an arbitrary location, of a value the caller
+      // effectively controls - which could be a security concern in some cases.
+#if PRINTF_SUPPORT_WRITEBACK_SPECIFIER
+      case 'n' : {
+        if       (flags & FLAGS_CHAR)      *(va_arg(args, char*))      = (char) output->pos;
+        else if  (flags & FLAGS_SHORT)     *(va_arg(args, short*))     = (short) output->pos;
+        else if  (flags & FLAGS_LONG)      *(va_arg(args, long*))      = (long) output->pos;
+#if PRINTF_SUPPORT_LONG_LONG
+        else if  (flags & FLAGS_LONG_LONG) *(va_arg(args, long long*)) = (long long int) output->pos;
+#endif // PRINTF_SUPPORT_LONG_LONG
+        else                               *(va_arg(args, int*))       = (int) output->pos;
+        format++;
+        break;
+      }
+#endif // PRINTF_SUPPORT_WRITEBACK_SPECIFIER
+
+      default :
+        putchar_via_gadget(output, *format);
+        format++;
+        break;
+    }
+  }
+}
+
+// internal vsnprintf - used for implementing _all library functions
+static int vsnprintf_impl(output_gadget_t* output, const char* format, va_list args)
+{
+  // Note: The library only calls vsnprintf_impl() with output->pos being 0. However, it is
+  // possible to call this function with a non-zero pos value for some "remedial printing".
+  format_string_loop(output, format, args);
+
+  // termination
+  append_termination_with_gadget(output);
+
+  // return written chars without terminating \0
+  return (int)output->pos;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+int vprintf_(const char* format, va_list arg)
+{
+  output_gadget_t gadget = extern_putchar_gadget();
+  return vsnprintf_impl(&gadget, format, arg);
+}
+
+int vsnprintf_(char* s, size_t n, const char* format, va_list arg)
+{
+  output_gadget_t gadget = buffer_gadget(s, n);
+  return vsnprintf_impl(&gadget, format, arg);
+}
+
+int vosnprintf_(char* s, size_t n, const char* format, va_list arg)
+{
+  output_gadget_t gadget = buffer_gadget(s, n);
+  gadget.flag_cstyle_Xh = s[0] == '\0' ? false : true;
+  return vsnprintf_impl(&gadget, format, arg);
+}
+
+int vsprintf_(char* s, const char* format, va_list arg)
+{
+  return vsnprintf_(s, PRINTF_MAX_POSSIBLE_BUFFER_SIZE, format, arg);
+}
+
+int vfctprintf(void (*out)(char c, void* extra_arg), void* extra_arg, const char* format, va_list arg)
+{
+  if (out == NULL) { return 0; }
+  output_gadget_t gadget = function_gadget(out, extra_arg);
+  return vsnprintf_impl(&gadget, format, arg);
+}
+
+int vofctprintf(void (*out)(char c, void* extra_arg), void* extra_arg, const char* format, va_list arg)
+{
+  if (out == NULL) { return 0; }
+  output_gadget_t gadget = function_gadget(out, extra_arg);
+  gadget.flag_cstyle_Xh = *((char *)extra_arg) == '\0' ? false : true;
+  return vsnprintf_impl(&gadget, format, arg);
+}
+
+int printf_(const char* format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  const int ret = vprintf_(format, args);
+  va_end(args);
+  return ret;
+}
+
+int sprintf_(char* s, const char* format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  const int ret = vsprintf_(s, format, args);
+  va_end(args);
+  return ret;
+}
+
+int snprintf_(char* s, size_t n, const char* format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  const int ret = vsnprintf_(s, n, format, args);
+  va_end(args);
+  return ret;
+}
+
+int fctprintf(void (*out)(char c, void* extra_arg), void* extra_arg, const char* format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  const int ret = vfctprintf(out, extra_arg, format, args);
+  va_end(args);
+  return ret;
+}
+
diff --git a/common/printf/printf.h b/common/printf/printf.h
new file mode 100644
index 0000000..5ef6c6a
--- /dev/null
+++ b/common/printf/printf.h
@@ -0,0 +1,240 @@
+/**
+ * @author (c) Eyal Rozenberg <eyalroz1@gmx.com>
+ *             2021-2023, Haifa, Palestine/Israel
+ * @author (c) Marco Paland (info@paland.com)
+ *             2014-2019, PALANDesign Hannover, Germany
+ *
+ * @note Others have made smaller contributions to this file: see the
+ * contributors page at https://github.com/eyalroz/printf/graphs/contributors
+ * or ask one of the authors.
+ *
+ * @brief Small stand-alone implementation of the printf family of functions
+ * (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems
+ * with a very limited resources.
+ *
+ * @note the implementations are thread-safe; re-entrant; use no functions from
+ * the standard library; and do not dynamically allocate any memory.
+ *
+ * @license The MIT License (MIT)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef PRINTF_H_
+#define PRINTF_H_
+
+#ifdef __cplusplus
+# include <cstdarg>
+# include <cstddef>
+extern "C" {
+#else
+# include <stdarg.h>
+# include <stddef.h>
+#endif
+
+#ifdef __GNUC__
+# if ((__GNUC__ == 4 && __GNUC_MINOR__>= 4) || __GNUC__ > 4)
+#  define ATTR_PRINTF(one_based_format_index, first_arg) \
+__attribute__((format(gnu_printf, (one_based_format_index), (first_arg))))
+# else
+# define ATTR_PRINTF(one_based_format_index, first_arg) \
+__attribute__((format(printf, (one_based_format_index), (first_arg))))
+# endif
+# define ATTR_VPRINTF(one_based_format_index) \
+ATTR_PRINTF((one_based_format_index), 0)
+#else
+# define ATTR_PRINTF(one_based_format_index, first_arg)
+# define ATTR_VPRINTF(one_based_format_index)
+#endif
+
+#ifndef PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT
+#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT 0
+#endif
+
+#ifndef PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD
+#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD 0
+#endif
+
+#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD
+# define printf_    printf
+# define sprintf_   sprintf
+# define vsprintf_  vsprintf
+# define snprintf_  snprintf
+# define vsnprintf_ vsnprintf
+# define vprintf_   vprintf
+#endif
+
+// If you want to include this implementation file directly rather than
+// link against it, this will let you control the functions' visibility,
+// e.g. make them static so as not to clash with other objects also
+// using them.
+#ifndef PRINTF_VISIBILITY
+#define PRINTF_VISIBILITY
+#endif
+
+/**
+ * Prints/send a single character to some opaque output entity
+ *
+ * @note This function is not implemented by the library, only declared; you
+ * must provide an implementation if you wish to use the @ref printf / @ref
+ * vprintf function (and possibly for linking against the library, if your
+ * toolchain does not support discarding unused functions)
+ *
+ * @note The output could be as simple as a wrapper for the `write()` system
+ * call on a Unix-like * system, or even libc's @ref putchar , for replicating
+ * actual functionality of libc's @ref printf * function; but on an embedded
+ * system it may involve interaction with a special output device, like a UART,
+ * etc.
+ *
+ * @note in libc's @ref putchar, the parameter type is an int; this was intended
+ * to support the representation of either a proper character or EOF in a
+ * variable - but this is really not meaningful to pass into @ref putchar and is
+ * discouraged today. See further discussion in:
+ * @link https://stackoverflow.com/q/17452847/1593077
+ *
+ * @param c the single character to print
+ */
+PRINTF_VISIBILITY
+void putchar_(char c);
+
+
+/**
+ * An implementation of the C standard's printf/vprintf
+ *
+ * @note you must implement a @ref putchar_ function for using this function -
+ * it invokes @ref putchar_ * rather than directly performing any I/O (which
+ * insulates it from any dependence on the operating system * and external
+ * libraries).
+ *
+ * @param format A string specifying the format of the output, with %-marked
+ *     specifiers of how to interpret additional arguments.
+ * @param arg Additional arguments to the function, one for each %-specifier in
+ *     @p format
+ * @return The number of characters written into @p s, not counting the
+ *     terminating null character
+ */
+ ///@{
+PRINTF_VISIBILITY
+int printf_(const char* format, ...) ATTR_PRINTF(1, 2);
+PRINTF_VISIBILITY
+int vprintf_(const char* format, va_list arg) ATTR_VPRINTF(1);
+///@}
+
+
+/**
+ * An implementation of the C standard's sprintf/vsprintf
+ *
+ * @note For security considerations (the potential for exceeding the buffer
+ * bounds), please consider using the size-constrained variant, @ref snprintf /
+ * @ref vsnprintf, instead.
+ *
+ * @param s An array in which to store the formatted string. It must be large
+ *     enough to fit the formatted output!
+ * @param format A string specifying the format of the output, with %-marked
+ *     specifiers of how to interpret additional arguments
+ * @param arg Additional arguments to the function, one for each specifier in
+ *     @p format
+ * @return The number of characters written into @p s, not counting the
+ *     terminating null character
+ */
+///@{
+PRINTF_VISIBILITY
+int  sprintf_(char* s, const char* format, ...) ATTR_PRINTF(2, 3);
+PRINTF_VISIBILITY
+int vsprintf_(char* s, const char* format, va_list arg) ATTR_VPRINTF(2);
+///@}
+
+
+/**
+ * An implementation of the C standard's snprintf/vsnprintf
+ *
+ * @param s An array in which to store the formatted string. It must be large
+ *     enough to fit either the entire formatted output, or at least @p n
+ *     characters. Alternatively, it can be NULL, in which case nothing will
+ *     be printed, and only the number of characters which _could_ have been
+ *     printed is tallied and returned.
+ * @param n The maximum number of characters to write to the array, including
+ *     a terminating null character
+ * @param format A string specifying the format of the output, with %-marked
+ *     specifiers of how to interpret additional arguments.
+ * @param arg Additional arguments to the function, one for each specifier in
+ *     @p format
+ * @return The number of characters that COULD have been written into @p s, not
+ *     counting the terminating null character. A value equal or larger than
+ *     @p n indicates truncation. Only when the returned value is non-negative
+ *     and less than @p n, the null-terminated string has been fully and
+ *     successfully printed.
+ */
+///@{
+PRINTF_VISIBILITY
+int  snprintf_(char* s, size_t count, const char* format, ...) ATTR_PRINTF(3, 4);
+PRINTF_VISIBILITY
+int vsnprintf_(char* s, size_t count, const char* format, va_list arg) ATTR_VPRINTF(3);
+PRINTF_VISIBILITY
+int vosnprintf_(char* s, size_t count, const char* format, va_list arg) ATTR_VPRINTF(3);
+///@}
+
+/**
+ * printf/vprintf with user-specified output function
+ *
+ * An alternative to @ref printf_, in which the output function is specified
+ * dynamically (rather than @ref putchar_ being used)
+ *
+ * @param out An output function which takes one character and a type-erased
+ *     additional parameters
+ * @param extra_arg The type-erased argument to pass to the output function @p
+ *     out with each call
+ * @param format A string specifying the format of the output, with %-marked
+ *     specifiers of how to interpret additional arguments.
+ * @param arg Additional arguments to the function, one for each specifier in
+ *     @p format
+ * @return The number of characters for which the output f unction was invoked,
+ *     not counting the terminating null character
+ *
+ */
+PRINTF_VISIBILITY
+int fctprintf(void (*out)(char c, void* extra_arg), void* extra_arg, const char* format, ...) ATTR_PRINTF(3, 4);
+PRINTF_VISIBILITY
+int vfctprintf(void (*out)(char c, void* extra_arg), void* extra_arg, const char* format, va_list arg) ATTR_VPRINTF(3);
+PRINTF_VISIBILITY
+int vofctprintf(void (*out)(char c, void* extra_arg), void* extra_arg, const char* format, va_list arg) ATTR_VPRINTF(3);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD
+# undef printf_
+# undef sprintf_
+# undef vsprintf_
+# undef snprintf_
+# undef vsnprintf_
+# undef vprintf_
+#else
+#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT
+# define printf     printf_
+# define sprintf    sprintf_
+# define vsprintf   vsprintf_
+# define snprintf   snprintf_
+# define vsnprintf  vsnprintf_
+# define vprintf    vprintf_
+#endif
+#endif
+
+#endif  // PRINTF_H_
diff --git a/common/treeitem.cpp b/common/treeitem.cpp
index 3939c0b..5e5ee36 100644
--- a/common/treeitem.cpp
+++ b/common/treeitem.cpp
@@ -16,7 +16,7 @@
 
 TreeItem::TreeItem(const UINT32 offset, const UINT8 type, const UINT8 subtype,
                    const UString & name, const UString & text, const UString & info,
-                   const UByteArray & header, const UByteArray & body, const UByteArray & tail,
+                   const UINT32 headerSize, const UINT32 bodySize, const UINT32 tailSize,
                    const bool fixed, const bool compressed,
                    TreeItem *parent) :
 itemOffset(offset),
@@ -27,9 +27,9 @@ itemMarking(0),
 itemName(name),
 itemText(text),
 itemInfo(info),
-itemHeader(header),
-itemBody(body),
-itemTail(tail),
+itemHeaderSize(headerSize),
+itemBodySize(bodySize),
+itemTailSize(tailSize),
 itemFixed(fixed),
 itemCompressed(compressed),
 parentItem(parent)
@@ -37,16 +37,39 @@ parentItem(parent)
 }
 
 TreeItem::~TreeItem() {
-    std::list<TreeItem*>::iterator begin = childItems.begin();
+    auto begin = childItems.begin();
     while (begin != childItems.end()) {
         delete *begin;
         ++begin;
     }
 }
 
+const char * TreeItem::content(UINT32 dataOffset) const
+{
+    if (!itemContent.isEmpty()) {
+        return itemContent.constData() + dataOffset;
+    }
+    auto o = itemOffset;
+    auto p = parentItem;
+    while (p && ((!p->itemCompressed && p->itemContent.isEmpty()) || (p->itemCompressed && p->itemUncompressedData.isEmpty()))) {
+        o += p->itemOffset;
+        p = p->parentItem;
+    }
+    if (!p)
+        return nullptr;
+    return !p->itemCompressed ? p->content(o + dataOffset) : p->itemUncompressedData.constData() + o + dataOffset - p->itemHeaderSize;
+}
+
+bool TreeItem::compressedInherited() const {
+    auto p = this;
+    while (p && p->itemType != Types::Root && !p->itemCompressed)
+        p = p->parentItem;
+    return p ? p->itemCompressed : false;
+}
+
 UINT8 TreeItem::insertChildBefore(TreeItem *item, TreeItem *newItem)
 {
-    std::list<TreeItem*>::iterator found = std::find(childItems.begin(), childItems.end(), item);
+    auto found = std::find(childItems.begin(), childItems.end(), item);
     if (found == childItems.end())
         return U_ITEM_NOT_FOUND;
     childItems.insert(found, newItem);
@@ -55,7 +78,7 @@ UINT8 TreeItem::insertChildBefore(TreeItem *item, TreeItem *newItem)
 
 UINT8 TreeItem::insertChildAfter(TreeItem *item, TreeItem *newItem)
 {
-    std::list<TreeItem*>::iterator found = std::find(childItems.begin(), childItems.end(), item);
+    auto found = std::find(childItems.begin(), childItems.end(), item);
     if (found == childItems.end())
         return U_ITEM_NOT_FOUND;
     childItems.insert(++found, newItem);
@@ -84,7 +107,7 @@ UString TreeItem::data(int column) const
 int TreeItem::row() const
 {
     if (parentItem) {
-        std::list<TreeItem*>::const_iterator iter = parentItem->childItems.begin();
+        auto iter = parentItem->childItems.begin();
         for (int i = 0; i < (int)parentItem->childItems.size(); ++i, ++iter) {
             if (const_cast<TreeItem*>(this) == *iter)
                 return i;
@@ -95,7 +118,7 @@ int TreeItem::row() const
 
 TreeItem* TreeItem::child(int row)
 {
-    std::list<TreeItem*>::iterator child = childItems.begin();
+    auto child = childItems.begin();
     std::advance(child, row);
     return *child;
 }
diff --git a/common/treeitem.h b/common/treeitem.h
index 0baf3e1..49effc2 100644
--- a/common/treeitem.h
+++ b/common/treeitem.h
@@ -14,7 +14,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #ifndef TREEITEM_H
 #define TREEITEM_H
 
-#include <list>
+#include <vector>
 #include <iterator>
 
 #include "basetypes.h"
@@ -25,20 +25,20 @@ class TreeItem
 {
 public:
     TreeItem(const UINT32 offset, const UINT8 type, const UINT8 subtype, const UString &name, const UString &text, const UString &info,
-        const UByteArray & header, const UByteArray & body, const UByteArray & tail,
+        const UINT32 headerSize, const UINT32 bodySize, const UINT32 tailSize,
         const bool fixed, const bool compressed,
         TreeItem *parent = 0);
     ~TreeItem();                                                               // Non-trivial implementation in CPP file
 
     // Operations with items
     void appendChild(TreeItem *item) { childItems.push_back(item); }
-    void prependChild(TreeItem *item) { childItems.push_front(item); };
+    void prependChild(TreeItem *item) { childItems.insert(childItems.begin(), item); };
     UINT8 insertChildBefore(TreeItem *item, TreeItem *newItem);                // Non-trivial implementation in CPP file
     UINT8 insertChildAfter(TreeItem *item, TreeItem *newItem);                 // Non-trivial implementation in CPP file
 
     // Model support operations
     TreeItem *child(int row);                                                  // Non-trivial implementation in CPP file
-    int childCount() const {return (int)childItems.size(); }
+    int childCount() const { return (int)childItems.size(); }
     int columnCount() const { return 5; }
     UString data(int column) const;                                            // Non-trivial implementation in CPP file
     int row() const;                                                           // Non-trivial implementation in CPP file
@@ -60,14 +60,17 @@ public:
     UString text() const { return itemText; }
     void setText(const UString &text) { itemText = text; }
 
-    UByteArray header() const { return itemHeader; }
-    bool hasEmptyHeader() const { return itemHeader.isEmpty(); }
+    UByteArray header() const { return UByteArray(content(0), itemHeaderSize); }
+    UINT32 headerSize() const { return itemHeaderSize; }
+    bool hasEmptyHeader() const { return itemHeaderSize == 0; }
 
-    UByteArray body() const { return itemBody; };
-    bool hasEmptyBody() const { return itemBody.isEmpty(); }
+    UByteArray body() const { return UByteArray(content(itemHeaderSize), itemBodySize); }
+    UINT32 bodySize() const { return itemBodySize; }
+    bool hasEmptyBody() const { return itemBodySize == 0; }
 
-    UByteArray tail() const { return itemTail; };
-    bool hasEmptyTail() const { return itemTail.isEmpty(); }
+    UByteArray tail() const { return UByteArray(content(itemHeaderSize + itemBodySize), itemTailSize); }
+    UINT32 tailSize() const { return itemTailSize; }
+    bool hasEmptyTail() const { return itemTailSize == 0; }
 
     UString info() const { return itemInfo; }
     void addInfo(const UString &info, const bool append) { if (append) itemInfo += info; else itemInfo = info + itemInfo; }
@@ -79,6 +82,10 @@ public:
     bool fixed() const { return itemFixed; }
     void setFixed(const bool fixed) { itemFixed = fixed; }
 
+    bool hasContent() const { return !itemContent.isEmpty(); }
+    void setContent(const UByteArray& c) { itemContent = c; }
+
+    bool compressedInherited() const;
     bool compressed() const { return itemCompressed; }
     void setCompressed(const bool compressed) { itemCompressed = compressed; }
 
@@ -94,8 +101,13 @@ public:
     void setMarking(const UINT8 marking) { itemMarking = marking; }
 
 private:
-    std::list<TreeItem*> childItems;
+    const char* content(UINT32 dataOffset) const;
+
+    std::vector<TreeItem*> childItems;
     UINT32     itemOffset;
+    UINT32     itemHeaderSize;
+    UINT32     itemBodySize;
+    UINT32     itemTailSize;
     UINT8      itemAction;
     UINT8      itemType;
     UINT8      itemSubtype;
@@ -103,9 +115,7 @@ private:
     UString    itemName;
     UString    itemText;
     UString    itemInfo;
-    UByteArray itemHeader;
-    UByteArray itemBody;
-    UByteArray itemTail;
+    UByteArray itemContent;
     bool       itemFixed;
     bool       itemCompressed;
     UByteArray itemParsingData;
diff --git a/common/treemodel.cpp b/common/treemodel.cpp
index 8fcc0bd..6349793 100644
--- a/common/treemodel.cpp
+++ b/common/treemodel.cpp
@@ -11,6 +11,12 @@
  
  */
 
+#if defined (QT_GUI_LIB)
+#include <QtWidgets/QApplication>
+#include <QIcon>
+#include <QtWidgets/QStyle>
+#endif
+
 #include "treemodel.h"
 
 #include "stack"
@@ -36,6 +42,16 @@ QVariant TreeModel::data(const UModelIndex &index, int role) const
             }
         }
     }
+    else if (role == Qt::DecorationRole) {
+        if ((item->hasContent() || (item->parent()->hasContent() && item->parent()->type() == Types::Root)) && index.column() == 0) {
+            if (item->compressed())
+                return QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning);
+            else
+                return QApplication::style()->standardIcon(QStyle::SP_FileDialogContentsView);
+        }
+        else if (item->compressed() && index.column() == 0)
+            return QApplication::style()->standardIcon(QStyle::SP_FileDialogStart);
+    }
 #endif
     else if (role == Qt::UserRole) {
         return item->info().toLocal8Bit();
@@ -214,6 +230,14 @@ UByteArray TreeModel::header(const UModelIndex &index) const
     return item->header();
 }
 
+UINT32 TreeModel::headerSize(const UModelIndex& index) const
+{
+    if (!index.isValid())
+        return 0;
+    TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
+    return item->headerSize();
+}
+
 bool TreeModel::hasEmptyHeader(const UModelIndex &index) const
 {
     if (!index.isValid())
@@ -230,6 +254,14 @@ UByteArray TreeModel::body(const UModelIndex &index) const
     return item->body();
 }
 
+UINT32 TreeModel::bodySize(const UModelIndex& index) const
+{
+    if (!index.isValid())
+        return 0;
+    TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
+    return item->bodySize();
+}
+
 bool TreeModel::hasEmptyBody(const UModelIndex &index) const
 {
     if (!index.isValid())
@@ -246,6 +278,14 @@ UByteArray TreeModel::tail(const UModelIndex &index) const
     return item->tail();
 }
 
+UINT32 TreeModel::tailSize(const UModelIndex& index) const
+{
+    if (!index.isValid())
+        return 0;
+    TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
+    return item->tailSize();
+}
+
 bool TreeModel::hasEmptyTail(const UModelIndex &index) const
 {
     if (!index.isValid())
@@ -299,7 +339,7 @@ bool TreeModel::compressed(const UModelIndex &index) const
     if (!index.isValid())
         return false;
     TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
-    return item->compressed();
+    return item->compressedInherited();
 }
 
 void TreeModel::setFixed(const UModelIndex &index, const bool fixed)
@@ -315,7 +355,7 @@ void TreeModel::setFixed(const UModelIndex &index, const bool fixed)
     
     if (fixed) {
         // Special handling for uncompressed to compressed boundary
-        if (item->compressed() && item->parent()->compressed() == FALSE) {
+        if (item->compressedInherited() && item->parent()->compressedInherited() == FALSE) {
             item->setFixed(item->parent()->fixed());
             return;
         }
@@ -352,6 +392,14 @@ void TreeModel::TreeModel::setMarkingDarkMode(const bool enabled)
     emit dataChanged(UModelIndex(), UModelIndex());
 }
 
+void TreeModel::TreeModel::setCStyleHexEnabled(const bool enabled)
+{
+    cStyleHexEnabledFlag = enabled;
+    setCStyleHexView(enabled);
+    
+    emit dataChanged(UModelIndex(), UModelIndex());
+}
+
 void TreeModel::setMarking(const UModelIndex &index, const UINT8 marking)
 {
     if (!index.isValid())
@@ -501,7 +549,7 @@ void TreeModel::setUncompressedData(const UModelIndex &index, const UByteArray &
 
 UModelIndex TreeModel::addItem(const UINT32 offset, const UINT8 type, const UINT8 subtype,
                                const UString & name, const UString & text, const UString & info,
-                               const UByteArray & header, const UByteArray & body, const UByteArray & tail,
+                               const UINT32 headerSize, const UINT32 bodySize, const UINT32 tailSize,
                                const ItemFixedState fixed,
                                const UModelIndex & parent, const UINT8 mode)
 {
@@ -524,8 +572,8 @@ UModelIndex TreeModel::addItem(const UINT32 offset, const UINT8 type, const UINT
         }
     }
     
-    TreeItem *newItem = new TreeItem(offset, type, subtype, name, text, info, header, body, tail, Movable, this->compressed(parent), parentItem);
-    
+    TreeItem* newItem = new TreeItem(offset, type, subtype, name, text, info, headerSize, bodySize, tailSize, Movable, false, parentItem);
+
     if (mode == CREATE_MODE_APPEND) {
         emit layoutAboutToBeChanged();
         parentItem->appendChild(newItem);
@@ -551,6 +599,7 @@ UModelIndex TreeModel::addItem(const UINT32 offset, const UINT8 type, const UINT
     
     UModelIndex created = createIndex(newItem->row(), parentColumn, newItem);
     setFixed(created, (bool)fixed); // Non-trivial logic requires additional call
+
     return created;
 }
 
@@ -601,7 +650,7 @@ goDeeper:
         UModelIndex currentIndex = parentIndex.model()->index(i, 0, parentIndex);
         
         UINT32 currentBase = this->base(currentIndex);
-        UINT32 fullSize = (UINT32)(header(currentIndex).size() + body(currentIndex).size() + tail(currentIndex).size());
+        UINT32 fullSize = (UINT32)(headerSize(currentIndex) + bodySize(currentIndex) + tailSize(currentIndex));
         if ((compressed(currentIndex) == false || (compressed(currentIndex) == true && compressed(currentIndex.parent()) == false)) // Base is meaningful only for true uncompressed items
             && currentBase <= base && base < currentBase + fullSize) { // Base must be in range [currentBase, currentBase + fullSize)
             // Found a better candidate
diff --git a/common/treemodel.h b/common/treemodel.h
index 0d6b5ac..fe08969 100644
--- a/common/treemodel.h
+++ b/common/treemodel.h
@@ -97,14 +97,15 @@ private:
     TreeItem *rootItem;
     bool markingEnabledFlag;
     bool markingDarkModeFlag;
+    bool cStyleHexEnabledFlag;
 
 public:
     QVariant data(const UModelIndex &index, int role) const;
     Qt::ItemFlags flags(const UModelIndex &index) const;
     QVariant headerData(int section, Qt::Orientation orientation,
         int role = Qt::DisplayRole) const;
-    TreeModel(QObject *parent = 0) : QAbstractItemModel(parent), markingEnabledFlag(true), markingDarkModeFlag(false) {
-        rootItem = new TreeItem(0, Types::Root, 0, UString(), UString(), UString(), UByteArray(), UByteArray(), UByteArray(), true, false);
+    TreeModel(QObject *parent = 0) : QAbstractItemModel(parent), markingEnabledFlag(true), markingDarkModeFlag(false), cStyleHexEnabledFlag (true) {
+        rootItem = new TreeItem(0, Types::Root, 0, UString(), UString(), UString(), 0, 0, 0, true, false);
     }
 
 #else
@@ -116,6 +117,7 @@ private:
     TreeItem *rootItem;
     bool markingEnabledFlag;
     bool markingDarkModeFlag;
+    bool cStyleHexEnabledFlag;
 
     void dataChanged(const UModelIndex &, const UModelIndex &) {}
     void layoutAboutToBeChanged() {}
@@ -126,7 +128,7 @@ public:
     UString headerData(int section, int orientation, int role = 0) const;
 
     TreeModel() : markingEnabledFlag(false), markingDarkModeFlag(false) {
-        rootItem = new TreeItem(0, Types::Root, 0, UString(), UString(), UString(), UByteArray(), UByteArray(), UByteArray(), true, false);
+        rootItem = new TreeItem(0, Types::Root, 0, UString(), UString(), UString(), 0, 0, 0, true, false);
     }
 
     bool hasIndex(int row, int column, const UModelIndex &parent = UModelIndex()) const {
@@ -142,12 +144,17 @@ public:
         delete rootItem;
     }
 
+    void setImage(const UByteArray& image) { rootItem->setContent(image); }
+
     bool markingEnabled() { return markingEnabledFlag; }
     void setMarkingEnabled(const bool enabled);
 
     bool markingDarkMode() { return markingDarkModeFlag; }
     void setMarkingDarkMode(const bool enabled);
 
+    bool cStyleHexEnabled() { return cStyleHexEnabledFlag; }
+    void setCStyleHexEnabled(const bool enabled);
+
     UModelIndex index(int row, int column, const UModelIndex &parent = UModelIndex()) const;
     UModelIndex parent(const UModelIndex &index) const;
     int rowCount(const UModelIndex &parent = UModelIndex()) const;
@@ -190,12 +197,15 @@ public:
     void setMarking(const UModelIndex &index, const UINT8 marking);
 
     UByteArray header(const UModelIndex &index) const;
+    UINT32 headerSize(const UModelIndex& index) const;
     bool hasEmptyHeader(const UModelIndex &index) const;
 
     UByteArray body(const UModelIndex &index) const;
+    UINT32 bodySize(const UModelIndex& index) const;
     bool hasEmptyBody(const UModelIndex &index) const;
 
     UByteArray tail(const UModelIndex &index) const;
+    UINT32 tailSize(const UModelIndex& index) const;
     bool hasEmptyTail(const UModelIndex &index) const;
 
     UByteArray parsingData(const UModelIndex &index) const;
@@ -204,7 +214,7 @@ public:
 
     UModelIndex addItem(const UINT32 offset, const UINT8 type, const UINT8 subtype,
         const UString & name, const UString & text, const UString & info,
-        const UByteArray & header, const UByteArray & body, const UByteArray & tail,
+        const UINT32 headerSize, const UINT32 bodySize, const UINT32 tailSize,
         const ItemFixedState fixed,
         const UModelIndex & parent = UModelIndex(), const UINT8 mode = CREATE_MODE_APPEND);
 
diff --git a/common/types.h b/common/types.h
index 0ee8247..ac82105 100755
--- a/common/types.h
+++ b/common/types.h
@@ -116,6 +116,7 @@ namespace Subtypes {
         Reserved1Region,
         Reserved2Region,
         PttRegion,
+        InvalidRegion,
     };
 
     enum PaddingSubtypes {
diff --git a/common/ubytearray.h b/common/ubytearray.h
index 1623403..00dd20e 100644
--- a/common/ubytearray.h
+++ b/common/ubytearray.h
@@ -46,7 +46,6 @@ public:
     uint32_t toUInt(bool* ok = NULL, const uint8_t base = 10) { return (uint32_t)strtoul(d.c_str(), NULL, base); }
 
     int32_t size() const { return (int32_t)d.size();  }
-    int32_t count(char ch) const { return (int32_t)std::count(d.begin(), d.end(), ch); }
     char at(uint32_t i) const { return d.at(i); }
     char operator[](uint32_t i) const { return d[i]; }
     char& operator[](uint32_t i) { return d[i]; }
diff --git a/common/ustring.cpp b/common/ustring.cpp
index 2493a41..4f0a45c 100644
--- a/common/ustring.cpp
+++ b/common/ustring.cpp
@@ -14,19 +14,42 @@
 #include <cstddef>
 #include <cstdint>
 #include <stdarg.h>
+#include "printf/printf.c"
+
+static bool cStyleHexEnabled = false;
+
+void putchar_(char c) {}
+
+void setCStyleHexView(const bool enable)
+{
+    cStyleHexEnabled = enable;
+}
 
 #if defined(QT_CORE_LIB)
+
+typedef struct {
+    char flag_cstyle_Xh;
+    UString* string;
+} qstring_opt_t;
+
+void qstring_out(char c, void* extra_arg)
+{
+    ((qstring_opt_t*)extra_arg)->string->append(c);
+}
+
 UString usprintf(const char* fmt, ...)
 {
     UString msg;
+    qstring_opt_t opt = { cStyleHexEnabled ? '\1' : '\0', &msg };
+
     va_list vl;
     va_start(vl, fmt);
-    
-    msg = msg.vasprintf(fmt, vl);
-    
+
+    int n = vofctprintf(qstring_out, &opt, fmt, vl);
+
     va_end(vl);
     return msg;
-};
+}
 
 UString urepeated(char c, int len)
 {
@@ -84,7 +107,8 @@ UString usprintf(const char* fmt, ...)
                 }
                 
                 va_start(arglist, fmt);
-                exvsnprintf(r, (char *)b->data, n + 1, fmt, arglist);
+                *(char*)b->data = cStyleHexEnabled ? '\1' : '\0';
+                r = vosnprintf_((char*)b->data, n + 1, fmt, arglist);
                 va_end(arglist);
                 
                 b->data[n] = '\0';
diff --git a/common/ustring.h b/common/ustring.h
index c143df4..529d5fb 100644
--- a/common/ustring.h
+++ b/common/ustring.h
@@ -31,6 +31,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #define ATTRIBUTE_FORMAT_(t,f,a)
 #endif
 
+void setCStyleHexView(const bool enable);
 UString usprintf(const char* fmt, ...) ATTRIBUTE_FORMAT_(printf, 1, 2);
 UString urepeated(char c, int len);
 UString uFromUcs2(const char* str, size_t max_len = 0);
diff --git a/common/utility.cpp b/common/utility.cpp
index 612f3da..339f119 100755
--- a/common/utility.cpp
+++ b/common/utility.cpp
@@ -429,16 +429,6 @@ UINT32 calculateChecksum32(const UINT32* buffer, UINT32 bufferSize)
     return (UINT32)(0x100000000ULL - counter);
 }
 
-// Get padding type for a given padding
-UINT8 getPaddingType(const UByteArray & padding)
-{
-    if (padding.count('\x00') == padding.size())
-        return Subtypes::ZeroPadding;
-    if (padding.count('\xFF') == padding.size())
-        return Subtypes::OnePadding;
-    return Subtypes::DataPadding;
-}
-
 static inline int char2hex(char c)
 {
     if (c >= '0' && c <= '9')
diff --git a/common/utility.h b/common/utility.h
index 505d217..5203893 100755
--- a/common/utility.h
+++ b/common/utility.h
@@ -59,8 +59,33 @@ UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize);
 // 32bit checksum calculation routine
 UINT32 calculateChecksum32(const UINT32* buffer, UINT32 bufferSize);
 
-// Return padding type from it's contents
-UINT8 getPaddingType(const UByteArray & padding);
+// Check if an array is filled in by a single repeated char
+inline signed long checkSingle(const UByteArray& a, signed long defaultRc = -1)
+{
+    size_t s = a.size();
+    if (!s)
+        return defaultRc;
+    if (s == 1 || memcmp(a.constData(), a.constData() + 1, s - 1) == 0)
+        return (unsigned char)a.at(0);
+    return -1;
+}
+
+// Get padding type for a given padding
+inline UINT8 getPaddingType(const UByteArray& a)
+{
+    size_t s = a.size();
+    if (s) {
+        if (s == 1 || memcmp(a.constData(), a.constData() + 1, s - 1) == 0) {
+            switch (a.at(0)) {
+            case 0:
+                return Subtypes::ZeroPadding;
+            case 0xFF:
+                return Subtypes::OnePadding;
+            }
+        }
+    }
+    return Subtypes::DataPadding;
+}
 
 // Make pattern from a hexstring with an assumption of . being any char
 bool makePattern(const CHAR8 *textPattern, std::vector<UINT8> &pattern, std::vector<UINT8> &patternMask);