From a400c2ef8fd74045f2969d2eee5217b8a3f34dd8 Mon Sep 17 00:00:00 2001
From: Nikolaj Schlej <schlej@live.de>
Date: Sat, 8 Nov 2014 22:24:53 +0100
Subject: [PATCH] Version 0.19.1

- hex numbers are printed uppercase
- empty paddings are shown as Empty(0x00) or Empty(0xFF)
- volume size is determined by FvLength header field only
- spaces are now allowed for hex pattern search
- another messages clean-up
---
 basetypes.h      |   3 +
 ffsengine.cpp    | 236 +++++++++++++++++++++++------------------------
 ffsengine.h      |   2 +-
 searchdialog.cpp |   2 +-
 types.cpp        |   4 +-
 uefitool.cpp     |   4 +-
 6 files changed, 125 insertions(+), 126 deletions(-)

diff --git a/basetypes.h b/basetypes.h
index ddc33d0..f9efdc3 100644
--- a/basetypes.h
+++ b/basetypes.h
@@ -148,4 +148,7 @@ typedef struct {
 #include <assert.h>
 #define ASSERT(x) assert(x)
 
+//Hexarg macro
+#define hexarg(X, Y) arg(QString("%1").arg((X),(Y),16,QChar('0')).toUpper())
+
 #endif
diff --git a/ffsengine.cpp b/ffsengine.cpp
index d3901f6..7139b9a 100644
--- a/ffsengine.cpp
+++ b/ffsengine.cpp
@@ -252,9 +252,9 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer)
         QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize);
         QString name = tr("UEFI capsule");
         QString info = tr("Header size: 0x%1\nFlags: 0x%2\nImage size: 0x%3")
-            .arg(capsuleHeader->HeaderSize, 8, 16, QChar('0'))
-            .arg(capsuleHeader->Flags, 8, 16, QChar('0'))
-            .arg(capsuleHeader->CapsuleImageSize, 8, 16, QChar('0'));
+            .hexarg(capsuleHeader->HeaderSize, 8)
+            .hexarg(capsuleHeader->Flags, 8)
+            .hexarg(capsuleHeader->CapsuleImageSize, 8);
         // Add tree item
         index = model->addItem(Types::Capsule, Subtypes::UefiCapsule, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body);
     }
@@ -268,9 +268,9 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer)
         QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize);
         QString name = tr("AMI Aptio capsule");
         QString info = tr("Header size: 0x%1\nFlags: 0x%2\nImage size: 0x%3")
-            .arg(aptioCapsuleHeader->RomImageOffset, 4, 16, QChar('0'))
-            .arg(aptioCapsuleHeader->CapsuleHeader.Flags, 8, 16, QChar('0'))
-            .arg(aptioCapsuleHeader->CapsuleHeader.CapsuleImageSize - aptioCapsuleHeader->RomImageOffset, 8, 16, QChar('0'));
+            .hexarg(aptioCapsuleHeader->RomImageOffset, 4)
+            .hexarg(aptioCapsuleHeader->CapsuleHeader.Flags, 8)
+            .hexarg(aptioCapsuleHeader->CapsuleHeader.CapsuleImageSize - aptioCapsuleHeader->RomImageOffset, 8);
         //!TODO: more info about Aptio capsule
         // Add tree item
         index = model->addItem(Types::Capsule, Subtypes::AptioCapsule, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body);
@@ -295,7 +295,7 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer)
     // Get info
     QString name = tr("BIOS image");
     QString info = tr("Size: 0x%1")
-        .arg(flashImage.size(), 8, 16, QChar('0'));
+        .hexarg(flashImage.size(), 8);
 
     // Add tree item
     index = model->addItem(Types::Image, Subtypes::BiosImage, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), flashImage, QByteArray(), index);
@@ -431,7 +431,7 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
     // Intel image
     name = tr("Intel image");
     info = tr("Size: 0x%1\nFlash chips: %2\nRegions: %3\nMasters: %4\nPCH straps: %5\nPROC straps: %6\nICC table entries: %7")
-        .arg(intelImage.size(), 8, 16, QChar('0'))
+        .hexarg(intelImage.size(), 8)
         .arg(descriptorMap->NumberOfFlashChips + 1) //
         .arg(descriptorMap->NumberOfRegions + 1)    // Zero-based numbers in storage
         .arg(descriptorMap->NumberOfMasters + 1)    //
@@ -446,36 +446,36 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
     // Get descriptor info
     body = intelImage.left(FLASH_DESCRIPTOR_SIZE);
     name = tr("Descriptor region");
-    info = tr("Size: 0x%1").arg(FLASH_DESCRIPTOR_SIZE, 4, 16, QChar('0'));
+    info = tr("Size: 0x%1").hexarg(FLASH_DESCRIPTOR_SIZE, 8);
 
     // Check regions presence once again
     QVector<UINT32> offsets;
     if (regionSection->GbeLimit) {
         offsets.append(gbeBegin);
-        info += tr("\nGbE region offset:  0x%1").arg(gbeBegin, 8, 16, QChar('0'));
+        info += tr("\nGbE region offset:  0x%1").hexarg(gbeBegin, 8);
     }
     if (regionSection->MeLimit) {
         offsets.append(meBegin);
-        info += tr("\nME region offset:   0x%1").arg(meBegin, 8, 16, QChar('0'));
+        info += tr("\nME region offset:   0x%1").hexarg(meBegin, 8);
     }
     if (regionSection->BiosLimit) {
         offsets.append(biosBegin);
-        info += tr("\nBIOS region offset: 0x%1").arg(biosBegin, 8, 16, QChar('0'));
+        info += tr("\nBIOS region offset: 0x%1").hexarg(biosBegin, 8);
     }
     if (regionSection->PdrLimit) {
         offsets.append(pdrBegin);
-        info += tr("\nPDR region offset:  0x%1").arg(pdrBegin, 8, 16, QChar('0'));
+        info += tr("\nPDR region offset:  0x%1").hexarg(pdrBegin, 8);
     }
 
     // Region access settings
     info += tr("\nRegion access settings:");
-    info += tr("\nBIOS:0x%1%2  ME:0x%3%4  GbE:0x%5%6")
-		.arg(masterSection->BiosRead, 2, 16, QChar('0'))
-		.arg(masterSection->BiosWrite, 2, 16, QChar('0'))
-		.arg(masterSection->MeRead, 2, 16, QChar('0'))
-		.arg(masterSection->MeWrite, 2, 16, QChar('0'))
-		.arg(masterSection->GbeRead, 2, 16, QChar('0'))
-		.arg(masterSection->GbeWrite, 2, 16, QChar('0'));
+    info += tr("\nBIOS:0x%1%2 ME:0x%3%4 GbE:0x%5%6")
+        .hexarg(masterSection->BiosRead, 2)
+        .hexarg(masterSection->BiosWrite, 2)
+        .hexarg(masterSection->MeRead, 2)
+        .hexarg(masterSection->MeWrite, 2)
+        .hexarg(masterSection->GbeRead, 2)
+        .hexarg(masterSection->GbeWrite, 2);
 
     // BIOS access table
     info += tr("\nBIOS access table:");
@@ -500,9 +500,9 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
 	UINT8 vsscTableSize = upperMap->VsccTableSize * sizeof(UINT32) / sizeof(VSCC_TABLE_ENTRY);
 	for (int i = 0; i < vsscTableSize; i++) {
 		info += tr("\n0x%1%2%3")
-			.arg(vsccTableEntry->VendorId, 2, 16, QChar('0'))
-			.arg(vsccTableEntry->DeviceId0, 2, 16, QChar('0'))
-			.arg(vsccTableEntry->DeviceId1, 2, 16, QChar('0'));
+            .hexarg(vsccTableEntry->VendorId, 2)
+            .hexarg(vsccTableEntry->DeviceId0, 2)
+            .hexarg(vsccTableEntry->DeviceId1, 2);
 		vsccTableEntry++;
 	}
 
@@ -552,13 +552,13 @@ UINT8 FfsEngine::parseGbeRegion(const QByteArray & gbe, QModelIndex & index, con
     GBE_MAC*     mac = (GBE_MAC*)gbe.constData();
     GBE_VERSION* version = (GBE_VERSION*)(gbe.constData() + GBE_VERSION_OFFSET);
     QString      info = tr("Size: 0x%1\nMAC: %2:%3:%4:%5:%6:%7\nVersion: %8.%9")
-        .arg(gbe.size(), 8, 16, QChar('0'))
-        .arg(mac->vendor[0], 2, 16, QChar('0'))
-        .arg(mac->vendor[1], 2, 16, QChar('0'))
-        .arg(mac->vendor[2], 2, 16, QChar('0'))
-        .arg(mac->device[0], 2, 16, QChar('0'))
-        .arg(mac->device[1], 2, 16, QChar('0'))
-        .arg(mac->device[2], 2, 16, QChar('0'))
+        .hexarg(gbe.size(), 8)
+        .hexarg(mac->vendor[0], 2)
+        .hexarg(mac->vendor[1], 2)
+        .hexarg(mac->vendor[2], 2)
+        .hexarg(mac->device[0], 2)
+        .hexarg(mac->device[1], 2)
+        .hexarg(mac->device[2], 2)
         .arg(version->major)
         .arg(version->minor);
 
@@ -576,7 +576,7 @@ UINT8 FfsEngine::parseMeRegion(const QByteArray & me, QModelIndex & index, const
     // Get info
     QString name = tr("ME region");
     QString info = tr("Size: 0x%1").
-        arg(me.size(), 8, 16, QChar('0'));
+        hexarg(me.size(), 8);
 
     // Search for new signature
     INT32 versionOffset = me.indexOf(ME_VERSION_SIGNATURE2);
@@ -617,7 +617,7 @@ UINT8 FfsEngine::parsePdrRegion(const QByteArray & pdr, QModelIndex & index, con
     // Get info
     QString name = tr("PDR region");
     QString info = tr("Size: 0x%1").
-        arg(pdr.size(), 8, 16, QChar('0'));
+        hexarg(pdr.size(), 8);
 
     // Add tree item
     index = model->addItem(Types::Region, Subtypes::PdrRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), pdr, QByteArray(), parent, mode);
@@ -638,7 +638,7 @@ UINT8 FfsEngine::parseBiosRegion(const QByteArray & bios, QModelIndex & index, c
     // Get info
     QString name = tr("BIOS region");
     QString info = tr("Size: 0x%1").
-        arg(bios.size(), 8, 16, QChar('0'));
+        hexarg(bios.size(), 8);
 
     // Add tree item
     index = model->addItem(Types::Region, Subtypes::BiosRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), bios, QByteArray(), parent, mode);
@@ -673,7 +673,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
         QByteArray padding = bios.left(prevVolumeOffset);
         name = tr("Padding");
         info = tr("Size: 0x%1")
-            .arg(padding.size(), 8, 16, QChar('0'));
+            .hexarg(padding.size(), 8);
 		
         // Add tree item
 		model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent);
@@ -683,12 +683,14 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
     UINT32 volumeOffset = prevVolumeOffset;
     UINT32 prevVolumeSize = 0;
     UINT32 volumeSize = 0;
+    UINT32 bmVolumeSize = 0;
 
     while (true)
     {
         bool msgAlignmentBitsSet = false;
         bool msgUnaligned = false;
         bool msgUnknownRevision = false;
+        bool msgSizeMismach = false;
 
         // Padding between volumes
         if (volumeOffset > prevVolumeOffset + prevVolumeSize) {
@@ -697,16 +699,21 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
             // Get info
             name = tr("Padding");
             info = tr("Size: 0x%1")
-                .arg(padding.size(), 8, 16, QChar('0'));
+                .hexarg(padding.size(), 8);
             // Add tree item
 			model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent);
         }
 
         // Get volume size
-        result = getVolumeSize(bios, volumeOffset, volumeSize);
+        result = getVolumeSize(bios, volumeOffset, volumeSize, bmVolumeSize);
         if (result)
             return result;
 
+        // Check reported size
+        if (volumeSize != bmVolumeSize)
+            msgSizeMismach = true;
+        //!TODO: now we trust header size, sometimes it's the bmVolumeSize that is OK, need to implement some settings for it
+
         //Check that volume is fully present in input
         if (volumeOffset + volumeSize > (UINT32)bios.size()) {
             msg(tr("parseBios: One of volumes inside overlaps the end of data"), parent);
@@ -748,6 +755,10 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
             msg(tr("parseBios: Unaligned revision 2 volume"), index);
         if (msgUnknownRevision)
             msg(tr("parseBios: Unknown volume revision %1").arg(volumeHeader->Revision), index);
+        if (msgSizeMismach)
+            msg(tr("parseBios: Volume size stored in header 0x%1 differs from calculated using block map 0x%2")
+            .hexarg(volumeSize, 8)
+            .hexarg(bmVolumeSize, 8), index);
 
         // Go to next volume
         prevVolumeOffset = volumeOffset;
@@ -762,7 +773,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
                 // Get info
                 name = tr("Padding");
                 info = tr("Size: 0x%1")
-                    .arg(padding.size(), 8, 16, QChar('0'));
+                    .hexarg(padding.size(), 8);
                 // Add tree item
 				model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent);
             }
@@ -784,7 +795,7 @@ UINT8 FfsEngine::findNextVolume(const QByteArray & bios, UINT32 volumeOffset, UI
     return ERR_SUCCESS;
 }
 
-UINT8 FfsEngine::getVolumeSize(const QByteArray & bios, UINT32 volumeOffset, UINT32 & volumeSize)
+UINT8 FfsEngine::getVolumeSize(const QByteArray & bios, UINT32 volumeOffset, UINT32 & volumeSize, UINT32 & bmVolumeSize)
 {
     // Populate volume header
     EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)(bios.constData() + volumeOffset);
@@ -795,30 +806,23 @@ UINT8 FfsEngine::getVolumeSize(const QByteArray & bios, UINT32 volumeOffset, UIN
 
     // Calculate volume size using BlockMap
     EFI_FV_BLOCK_MAP_ENTRY* entry = (EFI_FV_BLOCK_MAP_ENTRY*)(bios.constData() + volumeOffset + sizeof(EFI_FIRMWARE_VOLUME_HEADER));
-    UINT32 bmVolumeSize = 0;
+    UINT32 calcVolumeSize = 0;
     while (entry->NumBlocks != 0 && entry->Length != 0) {
         if ((void*)entry > bios.constData() + bios.size())
             return ERR_INVALID_VOLUME;
 
-        bmVolumeSize += entry->NumBlocks * entry->Length;
+        calcVolumeSize += entry->NumBlocks * entry->Length;
         entry += 1;
     }
 
-    // Check calculated and stored volume sizes to be the same
-    if (volumeHeader->FvLength != bmVolumeSize) {
-        // Use smaller value as volume size
-        volumeSize = volumeHeader->FvLength < bmVolumeSize ? volumeHeader->FvLength : bmVolumeSize;
-    }
-    else
-        volumeSize = bmVolumeSize;
-
+    volumeSize = volumeHeader->FvLength;
+    bmVolumeSize = calcVolumeSize;
     return ERR_SUCCESS;
 }
 
 UINT8  FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, const QModelIndex & parent, const UINT8 mode)
 {
     bool msgUnknownFS = false;
-    bool msgSizeMismach = false;
     bool msgInvalidChecksum = false;
 
     // Populate volume header
@@ -872,18 +876,12 @@ UINT8  FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
     // Get volume size
     UINT8 result;
     UINT32 volumeSize;
+    UINT32 bmVolumeSize;
 
-    result = getVolumeSize(volume, 0, volumeSize);
+    result = getVolumeSize(volume, 0, volumeSize, bmVolumeSize);
     if (result)
         return result;
 
-    // Check reported size
-    if (volumeSize != volumeHeader->FvLength)
-        msgSizeMismach = true;
-    // Trust header size
-    else
-        volumeSize = volumeHeader->FvLength;
-
     // Check header checksum by recalculating it
     if (subtype == Subtypes::NormalVolume && calculateChecksum16((UINT16*)volumeHeader, volumeHeader->HeaderLength))
         msgInvalidChecksum = true;
@@ -892,16 +890,16 @@ UINT8  FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
     QString name = guidToQString(volumeHeader->FileSystemGuid);
     QString info = tr("FileSystem GUID: %1\nSize: 0x%2\nRevision: %3\nAttributes: 0x%4\nErase polarity: %5\nHeader size: 0x%6")
         .arg(guidToQString(volumeHeader->FileSystemGuid))
-        .arg(volumeSize, 8, 16, QChar('0'))
+        .hexarg(volumeSize, 8)
         .arg(volumeHeader->Revision)
-        .arg(volumeHeader->Attributes, 8, 16, QChar('0'))
+        .hexarg(volumeHeader->Attributes, 8)
         .arg(empty ? "1" : "0")
-        .arg(headerSize, 4, 16, QChar('0'));
+        .hexarg(headerSize, 4);
     // Extended header present
     if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) {
         EFI_FIRMWARE_VOLUME_EXT_HEADER* extendedHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(volume.constData() + volumeHeader->ExtHeaderOffset);
         info += tr("\nExtended header size: 0x%1\nVolume name: %2")
-            .arg(extendedHeader->ExtHeaderSize, 8, 16, QChar('0'))
+            .arg(extendedHeader->ExtHeaderSize, 8)
             .arg(guidToQString(extendedHeader->FvName));
     }
 
@@ -913,10 +911,6 @@ UINT8  FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
     // Show messages
     if (msgUnknownFS)
         msg(tr("parseVolume: Unknown file system %1").arg(guidToQString(volumeHeader->FileSystemGuid)), index);
-    if (msgSizeMismach)
-        msg(tr("parseVolume: Volume size stored in header 0x%1 differs from calculated using block map 0x%2")
-        .arg(volumeHeader->FvLength, 8, 16, QChar('0'))
-        .arg(volumeSize, 8, 16, QChar('0')), index);
     if (msgInvalidChecksum)
         msg(tr("parseVolume: Volume header checksum is invalid"), index);
 
@@ -1120,10 +1114,10 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U
         name = tr("Padding");
     info = tr("Name: %1\nType: 0x%2\nAttributes: 0x%3\nSize: 0x%4\nState: 0x%5")
         .arg(guidToQString(fileHeader->Name))
-        .arg(fileHeader->Type, 2, 16, QChar('0'))
-        .arg(fileHeader->Attributes, 2, 16, QChar('0'))
-        .arg(uint24ToUint32(fileHeader->Size), 6, 16, QChar('0'))
-        .arg(fileHeader->State, 2, 16, QChar('0'));
+        .hexarg(fileHeader->Type, 2)
+        .hexarg(fileHeader->Attributes, 2)
+        .hexarg(uint24ToUint32(fileHeader->Size), 6)
+        .hexarg(fileHeader->State, 2);
 
     // Add tree item
     index = model->addItem(Types::File, fileHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, tail, parent, mode);
@@ -1136,7 +1130,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U
     if (msgInvalidTailValue)
         msg(tr("parseFile: Invalid tail value"), index);
     if (msgInvalidType)
-        msg(tr("parseFile: Unknown file type 0x%1").arg(fileHeader->Type, 2, 16, QChar('0')), index);
+        msg(tr("parseFile: Unknown file type 0x%1").arg(fileHeader->Type, 2), index);
 	if (msgNonEmptyPadFile)
 		msg(tr("parseFile: Non-empty pad file contents will be destroyed after volume modification"), index);
 
@@ -1334,10 +1328,10 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
 
         // Get info
         info = tr("Type: 0x%1\nSize: 0x%2\nCompression type: %3\nDecompressed size: 0x%4")
-            .arg(sectionHeader->Type, 2, 16, QChar('0'))
-            .arg(body.size(), 6, 16, QChar('0'))
+            .hexarg(sectionHeader->Type, 2)
+            .hexarg(body.size(), 6)
             .arg(compressionTypeToQString(algorithm))
-            .arg(compressedSectionHeader->UncompressedLength, 8, 16, QChar('0'));
+            .hexarg(compressedSectionHeader->UncompressedLength, 8);
 
         // Add tree item
         index = model->addItem(Types::Section, sectionHeader->Type, algorithm, name, "", info, header, body, QByteArray(), parent, mode);
@@ -1372,10 +1366,10 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
         name = guidToQString(guidDefinedSectionHeader->SectionDefinitionGuid);
         info = tr("GUID: %1\nType: 0x%2\nSize: 0x%3\nData offset: 0x%4\nAttributes: 0x%5")
             .arg(name)
-            .arg(sectionHeader->Type, 2, 16, QChar('0'))
-            .arg(body.size(), 6, 16, QChar('0'))
-            .arg(guidDefinedSectionHeader->DataOffset, 4, 16, QChar('0'))
-            .arg(guidDefinedSectionHeader->Attributes, 4, 16, QChar('0'));
+            .hexarg(sectionHeader->Type, 2)
+            .hexarg(body.size(), 6)
+            .hexarg(guidDefinedSectionHeader->DataOffset, 4)
+            .hexarg(guidDefinedSectionHeader->Attributes, 4);
 
         UINT8 algorithm = COMPRESSION_ALGORITHM_NONE;
         // Check if section requires processing
@@ -1390,11 +1384,11 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
 				
 				if (algorithm == COMPRESSION_ALGORITHM_TIANO) {
 					info += tr("\nCompression type: Tiano");
-					info += tr("\nDecompressed size: 0x%1").arg(decompressed.length(), 8, 16, QChar('0'));
+                    info += tr("\nDecompressed size: 0x%1").hexarg(decompressed.length(), 8);
 				}
 				else if (algorithm == COMPRESSION_ALGORITHM_EFI11) {
 					info += tr("\nCompression type: EFI 1.1");
-					info += tr("\nDecompressed size: 0x%1").arg(decompressed.length(), 8, 16, QChar('0'));
+                    info += tr("\nDecompressed size: 0x%1").hexarg(decompressed.length(), 8);
 				}
 				else 
 					info += tr("\nCompression type: unknown");
@@ -1409,7 +1403,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
 				
 				if (algorithm == COMPRESSION_ALGORITHM_LZMA) {
 					info += tr("\nCompression type: LZMA");
-					info += tr("\nDecompressed size: 0x%1").arg(decompressed.length(), 8, 16, QChar('0'));
+                    info += tr("\nDecompressed size: 0x%1").hexarg(decompressed.length(), 8);
 				}
 				else
 					info += tr("\nCompression type: unknown");
@@ -1465,7 +1459,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
             // Get signature
             QByteArray signature = body.left(*(UINT32*)body.constData());
             // Get info for it
-            QString signatureInfo = tr("Size: 0x%1").arg(signature.size(), 8, 16, QChar('0'));
+            QString signatureInfo = tr("Size: 0x%1").hexarg(signature.size(), 8);
             // Add it to the tree
             QModelIndex signatureIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Padding"), tr("Intel signature"), signatureInfo, QByteArray(), signature, QByteArray(), index, mode);
 
@@ -1491,8 +1485,8 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
 
         // Get info
         info = tr("parseSection: 0x%1\nSize: 0x%2")
-            .arg(sectionHeader->Type, 2, 16, QChar('0'))
-            .arg(body.size(), 6, 16, QChar('0'));
+            .hexarg(sectionHeader->Type, 2)
+            .hexarg(body.size(), 6);
 
         // Add tree item
         index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
@@ -1515,8 +1509,8 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
 
         // Get info
         info = tr("Type: 0x%1\nSize: 0x%2")
-            .arg(sectionHeader->Type, 2, 16, QChar('0'))
-            .arg(body.size(), 6, 16, QChar('0'));
+            .hexarg(sectionHeader->Type, 2)
+            .hexarg(body.size(), 6);
 
         // Parse dependency expression
         QString str;
@@ -1544,8 +1538,8 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
 
         // Get info
         info = tr("Type: 0x%1\nSize: 0x%2")
-            .arg(sectionHeader->Type, 2, 16, QChar('0'))
-            .arg(body.size(), 6, 16, QChar('0'));
+            .hexarg(sectionHeader->Type, 2)
+            .hexarg(body.size(), 6);
 
         // Add tree item
         index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
@@ -1567,8 +1561,8 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
         EFI_FREEFORM_SUBTYPE_GUID_SECTION* fsgHeader = (EFI_FREEFORM_SUBTYPE_GUID_SECTION*)sectionHeader;
         // Get info
         info = tr("Type: 0x%1\nSize: 0x%2\nSubtype GUID: %3")
-            .arg(fsgHeader->Type, 2, 16, QChar('0'))
-            .arg(body.size(), 6, 16, QChar('0'))
+            .hexarg(fsgHeader->Type, 2)
+            .hexarg(body.size(), 6)
             .arg(guidToQString(fsgHeader->SubTypeGuid));
 
         // Add tree item
@@ -1583,8 +1577,8 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
 
         // Get info
         info = tr("Type: 0x%1\nSize: 0x%2\nBuild number: %3\nVersion string: %4")
-            .arg(versionHeader->Type, 2, 16, QChar('0'))
-            .arg(body.size(), 6, 16, QChar('0'))
+            .hexarg(versionHeader->Type, 2)
+            .hexarg(body.size(), 6)
             .arg(versionHeader->BuildNumber)
             .arg(QString::fromUtf16((const ushort*)body.constData()));
 
@@ -1599,8 +1593,8 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
 
         // Get info
         info = tr("Type: 0x%1\nSize: 0x%2\nText: %3")
-            .arg(sectionHeader->Type, 2, 16, QChar('0'))
-            .arg(body.size(), 6, 16, QChar('0'))
+            .hexarg(sectionHeader->Type, 2)
+            .hexarg(body.size(), 6)
             .arg(text);
 
         // Add tree item
@@ -1616,8 +1610,8 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
 
         // Get info
         info = tr("Type: 0x%1\nSize: 0x%2")
-            .arg(sectionHeader->Type, 2, 16, QChar('0'))
-            .arg(body.size(), 6, 16, QChar('0'));
+            .hexarg(sectionHeader->Type, 2)
+            .hexarg(body.size(), 6);
 
         // Add tree item
         index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
@@ -1637,8 +1631,8 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
 
         // Get info
         info = tr("Type: 0x%1\nSize: 0x%2")
-            .arg(sectionHeader->Type, 2, 16, QChar('0'))
-            .arg(body.size(), 6, 16, QChar('0'));
+            .hexarg(sectionHeader->Type, 2)
+            .hexarg(body.size(), 6);
 
         // Check for apriori file
         QModelIndex parentFile = model->findParentOfType(parent, Types::File);
@@ -1688,12 +1682,12 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
         body = section.mid(sizeof(EFI_COMMON_SECTION_HEADER), sectionSize - sizeof(EFI_COMMON_SECTION_HEADER));
         // Get info
         info = tr("Type: 0x%1\nSize: 0x%2")
-            .arg(sectionHeader->Type, 2, 16, QChar('0'))
-            .arg(body.size(), 6, 16, QChar('0'));
+            .hexarg(sectionHeader->Type, 2)
+            .hexarg(body.size(), 6);
 
         // Add tree item
         index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
-        msg(tr("parseSection: Section with unknown type 0x%1").arg(sectionHeader->Type, 2, 16, QChar('0')), index);
+        msg(tr("parseSection: Section with unknown type 0x%1").hexarg(sectionHeader->Type, 2), index);
     }
     return ERR_SUCCESS;
 }
@@ -2227,7 +2221,7 @@ UINT8 FfsEngine::decompress(const QByteArray & compressedData, const UINT8 compr
         delete[] decompressed;
         return ERR_SUCCESS;
     default:
-        msg(tr("decompress: Unknown compression type (%1)").arg(compressionType));
+        msg(tr("decompress: Unknown compression type %1").arg(compressionType));
         if (algorithm)
             *algorithm = COMPRESSION_ALGORITHM_UNKNOWN;
         return ERR_UNKNOWN_COMPRESSION_ALGORITHM;
@@ -2311,7 +2305,7 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA
     }
         break;
     default:
-        msg(tr("compress: Unknown compression algorithm (%1)").arg(algorithm));
+        msg(tr("compress: Unknown compression algorithm %1").arg(algorithm));
         return ERR_UNKNOWN_COMPRESSION_ALGORITHM;
     }
 }
@@ -2435,14 +2429,14 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec
         // Check size of reconstructed image, it must be same
         if (reconstructed.size() > model->body(index).size()) {
             msg(tr("reconstructIntelImage: reconstructed body size 0x%1 is bigger then original 0x%2")
-                .arg(reconstructed.size(), 8, 16, QChar('0'))
-                .arg(model->body(index).size(), 8, 16, QChar('0')), index);
+                .hexarg(reconstructed.size(), 8)
+                .hexarg(model->body(index).size(), 8), index);
             return ERR_INVALID_PARAMETER;
         }
         else if (reconstructed.size() < model->body(index).size()) {
             msg(tr("reconstructIntelImage: reconstructed body size 0x%1 is smaller then original 0x%2")
-                .arg(reconstructed.size(), 8, 16, QChar('0'))
-                .arg(model->body(index).size(), 8, 16, QChar('0')), index);
+                .hexarg(reconstructed.size(), 8)
+                .hexarg(model->body(index).size(), 8), index);
             return ERR_INVALID_PARAMETER;
         }
 
@@ -2490,14 +2484,14 @@ UINT8 FfsEngine::reconstructRegion(const QModelIndex& index, QByteArray& reconst
         // Check size of reconstructed region, it must be same
         if (reconstructed.size() > model->body(index).size()) {
             msg(tr("reconstructRegion: reconstructed region size 0x%1 is bigger then original 0x%2")
-                .arg(reconstructed.size(), 8, 16, QChar('0'))
-                .arg(model->body(index).size(), 8, 16, QChar('0')), index);
+                .hexarg(reconstructed.size(), 8)
+                .hexarg(model->body(index).size(), 8), index);
             return ERR_INVALID_PARAMETER;
         }
         else if (reconstructed.size() < model->body(index).size()) {
             msg(tr("reconstructRegion: reconstructed region size 0x%1 is smaller then original 0x%2")
-                .arg(reconstructed.size(), 8, 16, QChar('0'))
-                .arg(model->body(index).size(), 8, 16, QChar('0')), index);
+                .hexarg(reconstructed.size(), 8)
+                .hexarg(model->body(index).size(), 8), index);
             return ERR_INVALID_PARAMETER;
         }
 
@@ -2540,9 +2534,11 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
 
         // Get volume size
         UINT32 volumeSize;
-        result = getVolumeSize(header, 0, volumeSize);
+        UINT32 bmVolumeSize;
+        result = getVolumeSize(header, 0, volumeSize, bmVolumeSize);
         if (result)
             return result;
+        //!TODO: now we trust header size, sometimes it's the bmVolumeSize that is OK, need to implement some settings for it
 
         // Reconstruct volume body
         if (model->rowCount(index)) {
@@ -3246,10 +3242,10 @@ UINT8 FfsEngine::findHexPattern(const QModelIndex & index, const QByteArray & he
         if (offset % 2 == 0) {
             msg(tr("Hex pattern \"%1\" found as \"%2\" in %3 at %4-offset 0x%5")
                 .arg(QString(hexPattern))
-                .arg(hexBody.mid(offset, hexPattern.length()))
+                .arg(hexBody.mid(offset, hexPattern.length()).toUpper())
                 .arg(model->nameString(index))
                 .arg(mode == SEARCH_MODE_BODY ? tr("body") : tr("header"))
-                .arg(offset / 2, 8, 16, QChar('0')),
+                .hexarg(offset / 2, 8),
                 index);
         }
         offset = regexp.indexIn(hexBody, offset + 1);
@@ -3315,10 +3311,10 @@ UINT8 FfsEngine::findGuidPattern(const QModelIndex & index, const QByteArray & g
         if (offset % 2 == 0) {
             msg(tr("GUID pattern \"%1\" found as \"%2\" in %3 at %4-offset 0x%5")
                 .arg(QString(guidPattern))
-                .arg(hexBody.mid(offset, hexPattern.length()))
+                .arg(hexBody.mid(offset, hexPattern.length()).toUpper())
                 .arg(model->nameString(index))
                 .arg(mode == SEARCH_MODE_BODY ? tr("body") : tr("header"))
-                .arg(offset / 2, 8, 16, QChar('0')),
+                .hexarg(offset / 2, 8),
                 index);
         }
         offset = regexp.indexIn(hexBody, offset + 1);
@@ -3355,7 +3351,7 @@ UINT8 FfsEngine::findTextPattern(const QModelIndex & index, const QString & patt
             .arg(unicode ? "Unicode" : "ASCII")
             .arg(pattern)
             .arg(model->nameString(index))
-            .arg(unicode ? offset * 2 : offset, 8, 16, QChar('0')),
+            .hexarg(unicode ? offset * 2 : offset, 8),
             index);
     }
 
@@ -3716,7 +3712,7 @@ UINT8 FfsEngine::recursiveDump(const QModelIndex & index, const QString & path,
     UINT8 result;
     for (int i = 0; i < model->rowCount(index); i++) {
         QModelIndex childIndex = index.child(i, 0);
-        QString childPath = tr("%1/%2 %3").arg(path).arg(i).arg(model->textString(childIndex).isEmpty() ? model->nameString(childIndex) : model->textString(childIndex));
+        QString childPath = QString("%1/%2 %3").arg(path).arg(i).arg(model->textString(childIndex).isEmpty() ? model->nameString(childIndex) : model->textString(childIndex));
         result = recursiveDump(childIndex, childPath, guid);
         if (result)
             return result;
@@ -3817,9 +3813,9 @@ UINT8 FfsEngine::patchViaOffset(QByteArray & data, const UINT32 offset, const QB
     body.replace(offset, replacePattern.length(), replacePattern);
     msg(tr("patch: replaced %1 bytes at offset 0x%2 %3 -> %4")
         .arg(replacePattern.length())
-        .arg(offset, 8, 16, QChar('0'))
-        .arg(QString(data.mid(offset, replacePattern.length()).toHex()))
-        .arg(QString(replacePattern.toHex())));
+        .hexarg(offset, 8)
+        .arg(QString(data.mid(offset, replacePattern.length()).toHex()).toUpper())
+        .arg(QString(replacePattern.toHex())).toUpper());
     data = body;
     return ERR_SUCCESS;
 }
diff --git a/ffsengine.h b/ffsengine.h
index 24ea2fe..df444a0 100644
--- a/ffsengine.h
+++ b/ffsengine.h
@@ -114,7 +114,7 @@ private:
     void  parseAprioriRawSection(const QByteArray & body, QString & parsed);
     UINT8 parseDepexSection(const QByteArray & body, QString & parsed);
 	UINT8 findNextVolume(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & nextVolumeOffset);
-    UINT8 getVolumeSize(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & volumeSize);
+    UINT8 getVolumeSize(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & volumeSize, UINT32 & bmVolumeSize);
     UINT8 getFileSize(const QByteArray & volume, const UINT32 fileOffset, UINT32 & fileSize);
     UINT8 getSectionSize(const QByteArray & file, const UINT32 sectionOffset, UINT32 & sectionSize);
 
diff --git a/searchdialog.cpp b/searchdialog.cpp
index 6fe041b..c9b716d 100644
--- a/searchdialog.cpp
+++ b/searchdialog.cpp
@@ -16,7 +16,7 @@
 SearchDialog::SearchDialog(QWidget *parent) :
 QDialog(parent),
 ui(new Ui::SearchDialog),
-hexValidator(QRegExp("([0-9a-fA-F\\.])*")),
+hexValidator(QRegExp("([0-9a-fA-F\\. ])*")),
 guidValidator(QRegExp("[0-9a-fA-F\\.]{8}-[0-9a-fA-F\\.]{4}-[0-9a-fA-F\\.]{4}-[0-9a-fA-F\\.]{4}-[0-9a-fA-F\\.]{12}"))
 {
     // Create UI
diff --git a/types.cpp b/types.cpp
index 52a700d..c537a69 100644
--- a/types.cpp
+++ b/types.cpp
@@ -71,9 +71,9 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype)
             return QObject::tr("Unknown");
     case Types::Padding:
 		if (subtype == Subtypes::ZeroPadding)
-			return QObject::tr("Empty(0)");
+			return QObject::tr("Empty(0x00)");
 		else if (subtype == Subtypes::OnePadding)
-			return QObject::tr("Empty(1)");
+			return QObject::tr("Empty(0xFF)");
 		else if (subtype == Subtypes::DataPadding)
 			return QObject::tr("Nonempty");
 		else
diff --git a/uefitool.cpp b/uefitool.cpp
index cc229e1..a79d587 100644
--- a/uefitool.cpp
+++ b/uefitool.cpp
@@ -17,7 +17,7 @@
 UEFITool::UEFITool(QWidget *parent) :
 QMainWindow(parent),
 ui(new Ui::UEFITool), 
-version(tr("0.19.0"))
+version(tr("0.19.1"))
 {
     clipboard = QApplication::clipboard();
 
@@ -149,7 +149,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();
+        QByteArray pattern = searchDialog->ui->hexEdit->text().toLatin1().replace(" ", "");
         if (pattern.isEmpty())
             return;
         UINT8 mode;