From 3d7dad6bb6eff44c175f55768a24f8d97488140d Mon Sep 17 00:00:00 2001
From: Nikolaj Schlej <schlej@live.de>
Date: Sun, 17 Nov 2013 10:01:11 +0100
Subject: [PATCH] Version 0.8.0

- code slightly refactored
- solved bug on working with file tail
---
 basetypes.h                              |   7 +
 descriptor.cpp                           |   2 +-
 ffsengine.cpp                            | 519 ++++++++---------------
 ffsengine.h                              |  39 +-
 debuglistitem.cpp => messagelistitem.cpp |  16 +-
 debuglistitem.h => messagelistitem.h     |  16 +-
 treeitem.cpp                             |  23 +-
 treeitem.h                               |  39 +-
 treemodel.cpp                            |   6 +-
 treemodel.h                              |   4 +-
 uefitool.cpp                             | 181 ++++----
 uefitool.h                               |   6 +-
 uefitool.pro                             |   4 +-
 uefitool.ui                              |  20 +-
 14 files changed, 379 insertions(+), 503 deletions(-)
 rename debuglistitem.cpp => messagelistitem.cpp (58%)
 rename debuglistitem.h => messagelistitem.h (56%)

diff --git a/basetypes.h b/basetypes.h
index f261a57..6063bd9 100644
--- a/basetypes.h
+++ b/basetypes.h
@@ -83,6 +83,8 @@ typedef uint16_t  CHAR16;
 #define ERR_STANDARD_DECOMPRESSION_FAILED   24
 #define ERR_CUSTOMIZED_DECOMPRESSION_FAILED 25
 #define ERR_UNKNOWN_COMPRESSION_ALGORITHM   26
+#define ERR_UNKNOWN_EXTRACT_MODE            27
+#define ERR_UNKNOWN_INSERT_MODE             28
 #define ERR_NOT_IMPLEMENTED                 0xFF
 
 // Compression algorithms
@@ -93,6 +95,11 @@ typedef uint16_t  CHAR16;
 #define COMPRESSION_ALGORITHM_LZMA    4
 #define COMPRESSION_ALGORITHM_IMLZMA  5
 
+// Item extract modes
+#define EXTRACT_MODE_AS_IS        0
+#define EXTRACT_MODE_BODY_ONLY    1
+#define EXTRACT_MODE_UNCOMPRESSED 2
+
 // Item insert modes
 #define INSERT_MODE_APPEND  0
 #define INSERT_MODE_PREPEND 1
diff --git a/descriptor.cpp b/descriptor.cpp
index 3453d69..7a94d0b 100644
--- a/descriptor.cpp
+++ b/descriptor.cpp
@@ -25,7 +25,7 @@ QString regionTypeToQString(const UINT8 type)
     case TreeItem::MeRegion:
         return QObject::tr("ME");
     case TreeItem::BiosRegion:
-        return QObject::tr("Bios");
+        return QObject::tr("BIOS");
     case TreeItem::PdrRegion:
         return QObject::tr("PDR");
     default:
diff --git a/ffsengine.cpp b/ffsengine.cpp
index 1a94c62..d39bce0 100644
--- a/ffsengine.cpp
+++ b/ffsengine.cpp
@@ -48,66 +48,12 @@ TreeModel* FfsEngine::model() const
 
 void FfsEngine::msg(const QString & message, const QModelIndex index)
 {
-    debugItems.enqueue(new DebugListItem(message, NULL, 0, index));
+    messageItems.enqueue(new MessageListItem(message, NULL, 0, index));
 }
 
-QQueue<DebugListItem*> FfsEngine::debugMessage()
+QQueue<MessageListItem*> FfsEngine::message()
 {
-    return debugItems;
-}
-
-QByteArray FfsEngine::header(const QModelIndex& index) const
-{
-    if (!index.isValid())
-        return QByteArray();
-
-    TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
-    return item->header();
-}
-
-QByteArray FfsEngine::body(const QModelIndex& index) const
-{
-    if (!index.isValid())
-        return QByteArray();
-
-    TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
-    return item->body();
-}
-
-bool FfsEngine::hasEmptyHeader(const QModelIndex& index) const
-{
-    if (!index.isValid())
-        return true;
-
-    TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
-
-    return item->hasEmptyHeader();
-}
-
-bool FfsEngine::hasEmptyBody(const QModelIndex& index) const
-{
-    if (!index.isValid())
-        return true;
-
-    TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
-
-    return item->hasEmptyBody();
-}
-
-bool FfsEngine::setTreeItemName(const QString &data, const QModelIndex &index)
-{
-    if(!index.isValid())
-        return false;
-
-    return treeModel->setItemName(data, index);
-}
-
-bool FfsEngine::setTreeItemText(const QString &data, const QModelIndex &index)
-{
-    if(!index.isValid())
-        return false;
-
-    return treeModel->setItemText(data, index);
+    return messageItems;
 }
 
 QModelIndex FfsEngine::findParentOfType(UINT8 type, const QModelIndex& index) const
@@ -128,32 +74,17 @@ QModelIndex FfsEngine::findParentOfType(UINT8 type, const QModelIndex& index) co
     return QModelIndex();
 }
 
-bool FfsEngine::isOfType(UINT8 type, const QModelIndex & index) const
-{
-    if (!index.isValid())
-        return false;
-
-    TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
-    return (item->type() == type);
-}
-
-bool FfsEngine::isOfSubtype(UINT8 subtype, const QModelIndex & index) const
-{
-    TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
-    return (item->subtype() == subtype);
-}
-
-UINT8 FfsEngine::hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2)
+bool FfsEngine::hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2)
 {
     if (begin1 < begin2 && begin2 < end1)
-        return 1;
+        return true;
     if (begin1 < end2 && end2 < end1)
-        return 1;
+        return true;
     if (begin2 < begin1 && begin1 < end2)
-        return 1;
+        return true;
     if (begin2 < end1 && end1 < end2)
-        return 1;
-    return 0;
+        return true;
+    return false;
 }
 
 // Firmware image parsing
@@ -222,10 +153,10 @@ UINT8  FfsEngine::parseInputFile(const QByteArray & buffer)
     // Get info
     QString name = tr("BIOS image");
     QString info = tr("Size: %1")
-        .arg(buffer.size(), 8, 16, QChar('0'));
+        .arg(flashImage.size(), 8, 16, QChar('0'));
     
     // Add tree item
-    index = treeModel->addItem(TreeItem::Image, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), buffer, index);
+    index = treeModel->addItem(TreeItem::Image, TreeItem::BiosImage, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), flashImage, QByteArray(), index);
     return parseBios(flashImage, index);
 }
 
@@ -342,34 +273,54 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & flashImage, const QModelInde
     QByteArray body;
     QString    name;
     QString    info;
+    
+    //!TODO: reorganize info
     // Intel image
     name = tr("Intel image");
-    info = tr("Size: %1").arg(flashImage.size(), 4, 16, QChar('0'));
-    // Add tree item
-    QModelIndex index = treeModel->addItem(TreeItem::IntelImage, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), flashImage, parent);
-
-    // Descriptor
-    // Get descriptor info
-    body = flashImage.left(FLASH_DESCRIPTOR_SIZE);
-    name = tr("Descriptor region");
     info = tr("Size: %1\nFlash chips: %2\nRegions: %3\nMasters: %4\nPCH straps: %5\nPROC straps: %6\nICC table entries: %7")
-        .arg(FLASH_DESCRIPTOR_SIZE, 8, 16, QChar('0'))
+        .arg(flashImage.size(), 8, 16, QChar('0'))
         .arg(descriptorMap->NumberOfFlashChips + 1) //
         .arg(descriptorMap->NumberOfRegions + 1)    // Zero-based numbers in storage
         .arg(descriptorMap->NumberOfMasters + 1)    //
         .arg(descriptorMap->NumberOfPchStraps)
         .arg(descriptorMap->NumberOfProcStraps)
         .arg(descriptorMap->NumberOfIccTableEntries);
-    // Add tree item
-    treeModel->addItem(TreeItem::Region, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), body, index);
-    
-    // Sort rest of regions in ascending order
+
+    // Add Intel image tree item
+    QModelIndex index = treeModel->addItem(TreeItem::Image, TreeItem::IntelImage, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), flashImage, QByteArray(), parent);
+
+    // Descriptor
+    // Get descriptor info
+    body = flashImage.left(FLASH_DESCRIPTOR_SIZE);
+    name = tr("Descriptor region");
+    info = tr("Size: %1").arg(FLASH_DESCRIPTOR_SIZE, 4, 16, QChar('0'));
+
+    // Check regions presence once again
     QVector<UINT32> offsets;
-    if (regionSection->GbeLimit)  offsets.append(gbeBegin);
-    if (regionSection->MeLimit)   offsets.append(meBegin);
-    if (regionSection->BiosLimit) offsets.append(biosBegin);
-    if (regionSection->PdrLimit)  offsets.append(pdrBegin);
+    if (regionSection->GbeLimit) { 
+        offsets.append(gbeBegin);
+        info += tr("\nGbE region offset: %1").arg(gbeBegin, 8, 16, QChar('0'));
+    }
+    if (regionSection->MeLimit) {  
+        offsets.append(meBegin);
+        info += tr("\nME region offset: %1").arg(meBegin, 8, 16, QChar('0'));
+    }
+    if (regionSection->BiosLimit) {
+        offsets.append(biosBegin);
+        info += tr("\nBIOS region offset: %1").arg(biosBegin, 8, 16, QChar('0'));
+    }
+    if (regionSection->PdrLimit) { 
+        offsets.append(pdrBegin);
+        info += tr("\nPDR region offset: %1").arg(pdrBegin, 8, 16, QChar('0'));
+    }
+    
+    // Add descriptor tree item
+    treeModel->addItem(TreeItem::Region, TreeItem::DescriptorRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), body, QByteArray(), index);
+
+    // Sort regions in ascending order
     qSort(offsets);
+    
+    // Parse regions
     UINT8 result;
     for (int i = 0; i < offsets.count(); i++) {
         // Parse GbE region
@@ -391,6 +342,7 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & flashImage, const QModelInde
         if (result)
             return result;
     }
+
     return ERR_SUCCESS;
 }
 
@@ -415,7 +367,7 @@ UINT8 FfsEngine::parseGbeRegion(const QByteArray & gbe, const QModelIndex & pare
         .arg(version->minor);
     
     // Add tree item
-    treeModel->addItem(TreeItem::Region, TreeItem::GbeRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), gbe, parent);
+    treeModel->addItem(TreeItem::Region, TreeItem::GbeRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), gbe, QByteArray(), parent);
 
     return ERR_SUCCESS;
 }
@@ -446,7 +398,7 @@ UINT8 FfsEngine::parseMeRegion(const QByteArray & me, const QModelIndex & parent
     }
 
     // Add tree item
-    treeModel->addItem(TreeItem::Region, TreeItem::MeRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), me, parent);
+    treeModel->addItem(TreeItem::Region, TreeItem::MeRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), me, QByteArray(), parent);
 
     return ERR_SUCCESS;
 }
@@ -462,7 +414,7 @@ UINT8 FfsEngine::parsePdrRegion(const QByteArray & pdr, const QModelIndex & pare
         arg(pdr.size(), 8, 16, QChar('0'));
     
     // Add tree item
-    treeModel->addItem(TreeItem::Region, TreeItem::PdrRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), pdr, parent);
+    treeModel->addItem(TreeItem::Region, TreeItem::PdrRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), pdr, QByteArray(), parent);
 
     return ERR_SUCCESS;
 }
@@ -478,133 +430,11 @@ UINT8 FfsEngine::parseBiosRegion(const QByteArray & bios, const QModelIndex & pa
         arg(bios.size(), 8, 16, QChar('0'));
     
     // Add tree item
-    QModelIndex index = treeModel->addItem(TreeItem::Region, TreeItem::BiosRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), bios, parent);
+    QModelIndex index = treeModel->addItem(TreeItem::Region, TreeItem::BiosRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), bios, QByteArray(), parent);
 
     return parseBios(bios, index);
 }
 
-/*UINT8 FfsEngine::parseRegion(const QByteArray & flashImage, const UINT16 regionBase, const UINT16 regionLimit, const QModelIndex & parent, QModelIndex & regionIndex)
-{
-    // Check for empty region or flash image
-    if (!regionLimit || flashImage.size() <= 0)
-        return ERR_EMPTY_REGION;
-
-    // Storing flash image size to unsigned variable, because it can't be negative now and all other values are unsigned  
-    UINT32 flashImageSize = (UINT32) flashImage.size(); 
-
-    // Calculate region offset and size
-    UINT32 regionOffset = calculateRegionOffset(regionBase);
-    UINT32 regionSize   = calculateRegionSize(regionBase, regionLimit);
-
-    // Populate descriptor map 
-    FLASH_DESCRIPTOR_MAP* descriptorMap = (FLASH_DESCRIPTOR_MAP*) (flashImage.constData() + sizeof(FLASH_DESCRIPTOR_HEADER));
-
-    // Determine presence of 2 flash chips
-    bool twoChips = descriptorMap->NumberOfFlashChips;
-
-    // Determine region subtype
-    UINT8 regionSubtype;
-    FLASH_DESCRIPTOR_REGION_SECTION* regionSection = (FLASH_DESCRIPTOR_REGION_SECTION*) calculateAddress8((UINT8*)flashImage.constData(), descriptorMap->RegionBase);
-    if (regionBase == regionSection->GbeBase)
-        regionSubtype = TreeItem::GbeRegion;
-    else if (regionBase == regionSection->MeBase)
-        regionSubtype = TreeItem::MeRegion;
-    else if (regionBase == regionSection->BiosBase)
-        regionSubtype = TreeItem::BiosRegion;
-    else if (regionBase == regionSection->PdrBase)
-        regionSubtype = TreeItem::PdrRegion;
-    else 
-        return ERR_UNKNOWN_ITEM_TYPE;
-    
-    // Construct region name
-    QString regionName = regionTypeToQString(regionSubtype);
-
-    // Check region base to be in buffer
-    if (regionOffset >= flashImageSize)
-    {
-        msg(tr("parseRegion: %1 region stored in descriptor not found").arg(regionName), parent);
-        if (twoChips) 
-            msg(tr("Two flash chips installed, so it could be in another flash chip\n"
-            "Make a dump from another flash chip and open it to view information about %1 region").arg(regionName), parent);
-        else
-            msg(tr("One flash chip installed, so it is an error caused by damaged or incomplete dump"), parent);
-        msg(tr("Absence of %1 region assumed").arg(regionName), parent);
-        return ERR_INVALID_REGION;
-    }
-
-    // Check region to be fully present in buffer
-    else if (regionOffset + regionSize > flashImageSize)
-    {
-        msg(tr("parseRegion: %1 region stored in descriptor overlaps the end of opened file").arg(regionName), parent);
-        if (twoChips) 
-            msg(tr("Two flash chips installed, so it could be in another flash chip\n"
-            "Make a dump from another flash chip and open it to view information about %1 region").arg(regionName), parent);
-        else
-            msg(tr("One flash chip installed, so it is an error caused by damaged or incomplete dump"), parent);
-        msg(tr("Absence of %1 region assumed\n").arg(regionName), parent);
-        return ERR_INVALID_REGION;
-    }
-
-    // Get info
-    QByteArray body = flashImage.mid(regionOffset, regionSize);
-    QString    name;
-    QString    info;
-    GBE_MAC* gbeMac;   
-    GBE_VERSION* gbeVersion;
-    ME_VERSION* meVersion;
-    INT32 meVersionOffset;
-    info = tr("Size: %1")
-        .arg(body.size(), 8, 16, QChar('0'));
-    switch (regionSubtype) 
-    {
-    case TreeItem::GbeRegion:
-        name = tr("GbE region");
-        gbeMac = (GBE_MAC*) body.constData();
-        gbeVersion = (GBE_VERSION*) (body.constData() + GBE_VERSION_OFFSET);
-        info += tr("\nMAC: %1:%2:%3:%4:%5:%6\nVersion: %7.%8")
-            .arg(gbeMac->vendor[0], 2, 16, QChar('0'))
-            .arg(gbeMac->vendor[1], 2, 16, QChar('0'))
-            .arg(gbeMac->vendor[2], 2, 16, QChar('0'))
-            .arg(gbeMac->device[0], 2, 16, QChar('0'))
-            .arg(gbeMac->device[1], 2, 16, QChar('0'))
-            .arg(gbeMac->device[2], 2, 16, QChar('0'))
-            .arg(gbeVersion->major)
-            .arg(gbeVersion->minor);
-        break;
-    case TreeItem::MeRegion:
-        name = tr("ME region");
-        meVersionOffset = body.indexOf(ME_VERSION_SIGNATURE);
-        if (meVersionOffset < 0){
-            info += tr("\nVersion: unknown");
-            msg(tr("parseRegion: ME region version is unknown, it can be damaged"), parent);
-        }
-        else {
-            meVersion = (ME_VERSION*) (body.constData() + meVersionOffset);
-            info += tr("\nVersion: %1.%2.%3.%4")
-                .arg(meVersion->major)
-                .arg(meVersion->minor)
-                .arg(meVersion->bugfix)
-                .arg(meVersion->build);
-        }
-        break;
-    case TreeItem::BiosRegion:
-        name = tr("BIOS region");
-        break;
-    case TreeItem::PdrRegion:
-        name = tr("PDR region");
-        break;
-    default:
-        name = tr("Unknown region");
-        msg(tr("parseRegion: Unknown region"), parent);
-        break;
-    }
-
-    // Add tree item
-    regionIndex = treeModel->addItem(TreeItem::Region, regionSubtype, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), body, parent);
-
-    return ERR_SUCCESS;
-}*/
-
 UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
 {
     // Search for first volume
@@ -625,7 +455,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
         info = tr("Size: %1")
             .arg(padding.size(), 8, 16, QChar('0'));
         // Add tree item
-        treeModel->addItem(TreeItem::Padding, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, parent);
+        treeModel->addItem(TreeItem::Padding, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent);
     }
 
     // Search for and parse all volumes
@@ -644,7 +474,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
             info = tr("Size: %1")
                 .arg(padding.size(), 8, 16, QChar('0'));
             // Add tree item
-            treeModel->addItem(TreeItem::Padding, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, parent);
+            treeModel->addItem(TreeItem::Padding, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent);
         } 
 
         // Get volume size
@@ -762,7 +592,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
                 info = tr("Size: %2")
                     .arg(padding.size(), 8, 16, QChar('0'));
                 // Add tree item
-                treeModel->addItem(TreeItem::Padding, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, parent);
+                treeModel->addItem(TreeItem::Padding, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent);
             }
             break;
         }
@@ -873,7 +703,7 @@ UINT8  FfsEngine::parseVolume(const QByteArray & volume, const QModelIndex & par
     // Add tree item
     QByteArray  header = volume.left(headerSize);
     QByteArray  body   = volume.mid(headerSize, volumeSize - headerSize);
-    QModelIndex index  = treeModel->addItem(TreeItem::Volume, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
+    QModelIndex index  = treeModel->addItem(TreeItem::Volume, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
 
     // Do not parse volumes with unknown FS
     if (!parseCurrentVolume)
@@ -986,13 +816,13 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, UINT8 revision, const char e
 
     // Get file body
     QByteArray body = file.right(file.size() - sizeof(EFI_FFS_FILE_HEADER));
-    UINT32 fileSize = (UINT32) file.size(); 
     // For files in Revision 1 volumes, check for file tail presence
+    QByteArray tail;
     if (revision == 1 && fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT)
     {
         //Check file tail;
-        UINT16* tail = (UINT16*) body.right(sizeof(UINT16)).constData();
-        if (!fileHeader->IntegrityCheck.TailReference == *tail)
+        tail = body.right(sizeof(UINT16));
+        if (!fileHeader->IntegrityCheck.TailReference == *(UINT16*)tail.constData())
             msg(tr("parseVolume: %1, file tail value %2 is not a bitwise not of %3 stored in file header")
             .arg(guidToQString(fileHeader->Name))
             .arg(*tail, 4, 16, QChar('0'))
@@ -1000,7 +830,6 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, UINT8 revision, const char e
 
         // Remove tail from file body
         body = body.left(body.size() - sizeof(UINT16));
-        fileSize -= sizeof(UINT16);
     }
 
     // Parse current file by default
@@ -1069,7 +898,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, UINT8 revision, const char e
         .arg(fileHeader->State, 2, 16, QChar('0'));
 
     // Add tree item
-    QModelIndex index = treeModel->addItem(TreeItem::File, fileHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
+    QModelIndex index = treeModel->addItem(TreeItem::File, fileHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, tail, parent, mode);
 
     if (!parseCurrentFile)
         return ERR_SUCCESS;
@@ -1167,7 +996,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
                 .arg(compressedSectionHeader->UncompressedLength, 8, 16, QChar('0'));
 
             // Add tree item
-            index  = treeModel->addItem(TreeItem::Section, sectionHeader->Type, algorithm, name, "", info, header, body, parent, mode);
+            index  = treeModel->addItem(TreeItem::Section, sectionHeader->Type, algorithm, name, "", info, header, body, QByteArray(), parent, mode);
             
             // Parse decompressed data
             if (parseCurrentSection) {
@@ -1214,7 +1043,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
                 .arg(compressionTypeToQString(algorithm));
 
             // Add tree item
-            index  = treeModel->addItem(TreeItem::Section, sectionHeader->Type, algorithm, name, "", info, header, body, parent, mode);
+            index  = treeModel->addItem(TreeItem::Section, sectionHeader->Type, algorithm, name, "", info, header, body, QByteArray(), parent, mode);
 
             // Parse decompressed data
             if (parseCurrentSection) {
@@ -1235,7 +1064,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
                 .arg(body.size(), 8, 16, QChar('0'));
 
             // Add tree item
-            index  = treeModel->addItem(TreeItem::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
+            index  = treeModel->addItem(TreeItem::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
 
             // Parse section body
             result = parseSections(body, revision, empty, index);
@@ -1264,9 +1093,10 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
             .arg(body.size(), 8, 16, QChar('0'));
 
         // Add tree item
-        index = treeModel->addItem(TreeItem::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
+        index = treeModel->addItem(TreeItem::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
         break;
     case EFI_SECTION_USER_INTERFACE:
+        {
         header = section.left(sizeof(EFI_USER_INTERFACE_SECTION));
         body   = section.mid(sizeof(EFI_USER_INTERFACE_SECTION), sectionSize - sizeof(EFI_USER_INTERFACE_SECTION));
 
@@ -1276,12 +1106,11 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
             .arg(body.size(), 8, 16, QChar('0'));
 
         // Add tree item
-        index = treeModel->addItem(TreeItem::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
+        index = treeModel->addItem(TreeItem::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
 
         // Rename parent file
-        {
-            QString text = QString::fromUtf16((const ushort*)body.constData());
-            setTreeItemText(text, findParentOfType(TreeItem::File, parent));
+        QString text = QString::fromUtf16((const ushort*)body.constData());
+        treeModel->setItemText(text, findParentOfType(TreeItem::File, parent));
         }
         break;
     case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
@@ -1294,7 +1123,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
             .arg(body.size(), 8, 16, QChar('0'));
 
         // Add tree item
-        index = treeModel->addItem(TreeItem::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
+        index = treeModel->addItem(TreeItem::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
 
         // Parse section body as BIOS space
         result = parseBios(body, index);
@@ -1313,7 +1142,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
             .arg(body.size(), 8, 16, QChar('0'));
 
         // Add tree item
-        index  = treeModel->addItem(TreeItem::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
+        index  = treeModel->addItem(TreeItem::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
 
         // Parse section body as BIOS space
         result = parseBios(body, index);
@@ -1331,13 +1160,42 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
             .arg(body.size(), 8, 16, QChar('0'));
 
         // Add tree item
-        index  = treeModel->addItem(TreeItem::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
+        index  = treeModel->addItem(TreeItem::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
         msg(tr("parseFile: Section with unknown type (%1)").arg(sectionHeader->Type, 2, 16, QChar('0')), index);
     }
     return ERR_SUCCESS;
 }
 
 // Operations on tree items
+UINT8 FfsEngine::extract(const QModelIndex & index, QByteArray & extracted, const UINT8 mode)
+{
+    if (!index.isValid())
+        return ERR_INVALID_PARAMETER;
+    
+    TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
+
+    if (mode == EXTRACT_MODE_AS_IS) {
+        // Extract as is, with header, body and tail
+        extracted.clear();
+        extracted.append(item->header());
+        extracted.append(item->body());
+        extracted.append(item->tail());
+    }
+    else if (mode == EXTRACT_MODE_BODY_ONLY) {
+        // Extract without header and tail
+        extracted.clear();
+        extracted.append(item->body());
+    }
+    else if (mode == EXTRACT_MODE_UNCOMPRESSED) {
+        // Only possible for files with compressed sections
+        return ERR_NOT_IMPLEMENTED;
+    }
+    else
+        return ERR_UNKNOWN_EXTRACT_MODE;
+
+    return ERR_SUCCESS;
+}
+
 UINT8 FfsEngine::insert(const QModelIndex & index, const QByteArray & object, const UINT8 type, const UINT8 mode)
 {
     if (!index.isValid())
@@ -1464,6 +1322,7 @@ UINT8 FfsEngine::decompress(const QByteArray & compressedData, const UINT8 compr
         scratch = new UINT8[scratchSize];
 
         // Decompress section data
+        //!TODO: better check needed
         // Try EFI1.1 decompression first
         if (ERR_SUCCESS != EfiDecompress(data, dataSize, decompressed, decompressedSize, scratch, scratchSize)) {
             // Not EFI 1.1, try Tiano
@@ -1498,7 +1357,6 @@ UINT8 FfsEngine::decompress(const QByteArray & compressedData, const UINT8 compr
                 }
                 else {
                     // Data are same - it's EFI 1.1
-                    msg(tr("EFI1.1"));
                     if (algorithm)
                         *algorithm = COMPRESSION_ALGORITHM_EFI11;
                 }
@@ -1645,15 +1503,12 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA
 UINT8 FfsEngine::reconstructImage(QByteArray & reconstructed)
 {
     QQueue<QByteArray> queue;
-    reconstructed = QByteArray();
-    rootItem->setAction(TreeItem::Reconstruct);
-    UINT8 result = reconstruct(rootItem, queue);
+    UINT8 result = reconstruct(treeModel->index(0,0), queue);
     if (result)
         return result;
-
+    reconstructed.clear();
     while (!queue.isEmpty())
         reconstructed.append(queue.dequeue());
-    rootItem->setAction(TreeItem::NoAction);
     return ERR_SUCCESS;
 }
 
@@ -1681,26 +1536,18 @@ UINT8 FfsEngine::constructPadFile(const UINT32 size, const UINT8 revision, const
     return ERR_SUCCESS;
 }
 
-UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const UINT8 revision, char empty)
+UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & queue, const UINT8 revision, char empty)
 {
-    if (!item)
+    if (!index.isValid())
         return ERR_SUCCESS;
 
     QByteArray reconstructed;
     UINT8 result;
+    TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
 
     // No action is needed, just return header + body
     if (item->action() == TreeItem::NoAction) {
-        reconstructed = item->header().append(item->body());
-        // One special case: file with tail
-        if (revision == 1 && item->type() == TreeItem::File) {
-            EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*) item->header().constData();
-            if (fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
-                // Append file tail
-                reconstructed.append(!fileHeader->IntegrityCheck.TailReference);
-            }
-        }
-
+        reconstructed = item->header().append(item->body()).append(item->tail());
         queue.enqueue(reconstructed);
         return ERR_SUCCESS;
     }
@@ -1713,7 +1560,7 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
         if (item->type() == TreeItem::Volume) {
             EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*) item->header().constData();
             empty = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00';
-            reconstructed.fill(empty, item->header().size() + item->body().size());
+            reconstructed.fill(empty, item->header().size() + item->body().size() + item->tail().size());
             queue.enqueue(reconstructed);
             return ERR_SUCCESS;
         }
@@ -1734,13 +1581,13 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
         QQueue<QByteArray> childrenQueue;
 
         switch (item->type()) {
-        case TreeItem::IntelImage:
-            {
+        case TreeItem::Image:
+            if (item->subtype() == TreeItem::IntelImage) {
                 // Reconstruct Intel image
                 // First child will always be descriptor for this type of image
-                result = reconstruct(item->child(0), childrenQueue);
-                    if (result)
-                        return result;
+                result = reconstruct(index.child(0, index.column()), childrenQueue);
+                if (result)
+                    return result;
                 QByteArray descriptor = childrenQueue.dequeue();
                 reconstructed.append(descriptor);
 
@@ -1762,7 +1609,7 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
                 UINT32 offset = descriptor.size();
                 // Reconstruct other regions
                 for (int i = 1; i < item->childCount(); i++) {
-                    result = reconstruct(item->child(i), childrenQueue);
+                    result = reconstruct(index.child(i, index.column()), childrenQueue);
                     if (result)
                         return result;
                     switch(item->child(i)->subtype()) 
@@ -1796,7 +1643,7 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
                         offset = pdrEnd;
                         break;
                     default:
-                        msg(tr("reconstruct: unknown region type found while reconstructing Intel image"));
+                        msg(tr("reconstruct: unknown region type found while reconstructing Intel image"), index);
                         return ERR_INVALID_REGION;
                     }
                 }
@@ -1804,73 +1651,64 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
                     reconstructed.append(QByteArray((UINT32)item->body().size() - offset, empty));
                 
                 if (reconstructed.size() > item->body().size()) {
-                    msg(tr("reconstructed: reconstructed body %1 is bigger then original %2 (Type: %3)")
+                    msg(tr("reconstruct: reconstructed body %1 is bigger then original %2")
                         .arg(reconstructed.size(), 8, 16, QChar('0'))
-                        .arg(item->body().size(), 8, 16, QChar('0'))
-                        .arg(itemTypeToQString(item->type())));
+                        .arg(item->body().size(), 8, 16, QChar('0')), index);
                     return ERR_INVALID_PARAMETER;
                 }
                 else if (reconstructed.size() < item->body().size()) {
-                    msg(tr("reconstructed: reconstructed body %1 is smaller then original %2 (Type: %3)")
+                    msg(tr("reconstruct: reconstructed body %1 is smaller then original %2")
                         .arg(reconstructed.size(), 8, 16, QChar('0'))
-                        .arg(item->body().size(), 8, 16, QChar('0'))
-                        .arg(itemTypeToQString(item->type())));
+                        .arg(item->body().size(), 8, 16, QChar('0')), index);
                     return ERR_INVALID_PARAMETER;
                 }
                 
                 // Enqueue reconstructed item
                 queue.enqueue(item->header().append(reconstructed));
+                return ERR_SUCCESS;
             }
-            break;
-
-        case TreeItem::Padding:
-            // Padding can't be changed
-            queue.enqueue(item->body()); 
-            break;
-
+            // BIOS Image must be treated like region
         case TreeItem::Capsule:
             if (item->subtype() == TreeItem::AptioCapsule)
-                msg(tr("reconstruct: Aptio extended header checksum and signature are now invalid"));
-        case TreeItem::Root:
-        case TreeItem::Image:
+                msg(tr("reconstruct: Aptio capsule checksum and signature can now become invalid"), index);
         case TreeItem::Region:
-            // Reconstruct item body
-            if (item->childCount()) {
-                // Reconstruct item children
-                for (int i = 0; i < item->childCount(); i++) {
-                    result = reconstruct(item->child(i), childrenQueue);
-                    if (result)
-                        return result;
-                }
+            {
+                // Reconstruct item body
+                if (item->childCount()) {
+                    // Reconstruct item children
+                    for (int i = 0; i < item->childCount(); i++) {
+                        result = reconstruct(index.child(i, index.column()), childrenQueue);
+                        if (result)
+                            return result;
+                    }
 
-                // No additional checks needed
-                while (!childrenQueue.isEmpty())
-                    reconstructed.append(childrenQueue.dequeue());
-            }
-            // Use stored item body
-            else
-                reconstructed = item->body();
-
-            // Check size of reconstructed image, it must be the same
-            if (item->type() != TreeItem::Root) {
-                if (reconstructed.size() > item->body().size()) {
-                    msg(tr("reconstructed: reconstructed body %1 is bigger then original %2 (Type: %3)")
-                        .arg(reconstructed.size(), 8, 16, QChar('0'))
-                        .arg(item->body().size(), 8, 16, QChar('0'))
-                        .arg(itemTypeToQString(item->type())));
-                    return ERR_INVALID_PARAMETER;
-                } 
-                else if (reconstructed.size() < item->body().size()) {
-                    msg(tr("reconstructed: reconstructed body %1 is smaller then original %2 (Type: %3)")
-                        .arg(reconstructed.size(), 8, 16, QChar('0'))
-                        .arg(item->body().size(), 8, 16, QChar('0'))
-                        .arg(itemTypeToQString(item->type())));
-                    return ERR_INVALID_PARAMETER;
+                    // No additional checks needed
+                    while (!childrenQueue.isEmpty())
+                        reconstructed.append(childrenQueue.dequeue());
+                }
+                // Use stored item body
+                else
+                    reconstructed = item->body();
+
+                // Check size of reconstructed image, it must be the same
+                if (item->type() != TreeItem::Root) {
+                    if (reconstructed.size() > item->body().size()) {
+                        msg(tr("reconstructed: reconstructed body %1 is bigger then original %2")
+                            .arg(reconstructed.size(), 8, 16, QChar('0'))
+                            .arg(item->body().size(), 8, 16, QChar('0')), index);
+                        return ERR_INVALID_PARAMETER;
+                    } 
+                    else if (reconstructed.size() < item->body().size()) {
+                        msg(tr("reconstructed: reconstructed body %1 is smaller then original %2")
+                            .arg(reconstructed.size(), 8, 16, QChar('0'))
+                            .arg(item->body().size(), 8, 16, QChar('0')), index);
+                        return ERR_INVALID_PARAMETER;
+                    }
                 }
-            }
             
-            // Enqueue reconstructed item
-            queue.enqueue(item->header().append(reconstructed));  
+                // Enqueue reconstructed item
+                queue.enqueue(item->header().append(reconstructed));
+            }
             break;
 
         case TreeItem::Volume: 
@@ -1884,7 +1722,7 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
                     // Reconstruct files in volume
                     for (int i = 0; i < item->childCount(); i++) {
                         // Reconstruct files
-                        result = reconstruct(item->child(i), childrenQueue, volumeHeader->Revision, empty);
+                        result = reconstruct(index.child(i, index.column()), childrenQueue, volumeHeader->Revision, empty);
                         if (result)
                             return result;
                     }
@@ -1952,7 +1790,7 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
                                 UINT32 vtfOffset = volumeSize - header.size() - file.size();
                                 if (vtfOffset % 8) {
                                     msg(tr("reconstruct: %1: Wrong size of Volume Top File")
-                                        .arg(guidToQString(volumeHeader->FileSystemGuid)));
+                                        .arg(guidToQString(volumeHeader->FileSystemGuid)), index);
                                     return ERR_INVALID_FILE;
                                 }
                                 // Insert pad file to fill the gap
@@ -1973,7 +1811,7 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
                                     // Check if volume can be grown
                                     UINT8 parentType = item->parent()->type();
                                     if(parentType != TreeItem::File && parentType != TreeItem::Section) {
-                                        msg(tr("%1: can't grow root volume").arg(guidToQString(volumeHeader->FileSystemGuid)));
+                                        msg(tr("%1: can't grow root volume").arg(guidToQString(volumeHeader->FileSystemGuid)), index);
                                         return ERR_INVALID_VOLUME;
                                     }
                                     // Grow volume to fit VTF
@@ -1985,7 +1823,7 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
                                     vtfOffset = newSize - header.size() - file.size();
                                     if (vtfOffset % 8) {
                                         msg(tr("reconstruct: %1: Wrong size of Volume Top File")
-                                            .arg(guidToQString(volumeHeader->FileSystemGuid)));
+                                            .arg(guidToQString(volumeHeader->FileSystemGuid)), index);
                                         return ERR_INVALID_FILE;
                                     }
                                     // Construct pad file
@@ -2012,7 +1850,7 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
                                     // Check if volume can be grown
                                     UINT8 parentType = item->parent()->type();
                                     if(parentType != TreeItem::File && parentType != TreeItem::Section) {
-                                        msg(tr("%1: can't grow root volume").arg(guidToQString(volumeHeader->FileSystemGuid)));
+                                        msg(tr("%1: can't grow root volume").arg(guidToQString(volumeHeader->FileSystemGuid)), index);
                                         return ERR_INVALID_VOLUME;
                                     }
                                     // Grow volume to fit new body
@@ -2057,7 +1895,7 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
                 if (item->childCount()) {
                     for (int i = 0; i < item->childCount(); i++) {
                         // Reconstruct sections
-                        result = reconstruct(item->child(i), childrenQueue, revision, empty);
+                        result = reconstruct(index.child(i, index.column()), childrenQueue, revision, empty);
                         if (result)
                             return result;
                     }
@@ -2084,9 +1922,7 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
                     }
 
                     // Correct file size
-                    UINT8 tailSize = 0;
-                    if(revision == 1 && (fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT))
-                        tailSize = sizeof(UINT16);
+                    UINT8 tailSize = item->hasEmptyTail() ? 0 : sizeof(UINT16);
 
                     uint32ToUint24(sizeof(EFI_FFS_FILE_HEADER) + reconstructed.size() + tailSize, fileHeader->Size);
 
@@ -2108,9 +1944,9 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
                     if (tailSize)
                         reconstructed.append(!fileHeader->IntegrityCheck.TailReference);
                 }
-                // Use current file body
+                // Use current file body and tail
                 else
-                    reconstructed = item->body();
+                    reconstructed = item->body().append(item->tail());
 
                 // Enqueue reconstructed item
                 queue.enqueue(header.append(reconstructed));  
@@ -2127,7 +1963,7 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
                     // Reconstruct section body
                     for (int i = 0; i < item->childCount(); i++) {
                         // Reconstruct subsections
-                        result = reconstruct(item->child(i), childrenQueue, revision, empty);
+                        result = reconstruct(index.child(i, index.column()), childrenQueue, revision, empty);
                         if (result)
                             return result;
                     }
@@ -2181,9 +2017,8 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
                         if (result)
                             return result;
                         // Check for auth status valid attribute
-                        if (guidDefinedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID)
-                        {
-                            msg(tr("reconstruct: %1: GUID defined section signature can now become invalid")
+                        if (guidDefinedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
+                            msg(tr("reconstruct: %1: GUID defined section signature can become invalid invalid")
                                 .arg(guidToQString(guidDefinedHeader->SectionDefinitionGuid)));
                         }
                         // Replace new section body
@@ -2215,7 +2050,6 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
         return ERR_SUCCESS;
     }
 
-    //!TODO: implement other actions
     return ERR_NOT_IMPLEMENTED;
 }
 
@@ -2224,7 +2058,12 @@ UINT8 FfsEngine::growVolume(QByteArray & header, const UINT32 size, UINT32 & new
     // Adjust new size to be representable by current FvBlockMap
     EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*) header.data();
     EFI_FV_BLOCK_MAP_ENTRY* blockMap = (EFI_FV_BLOCK_MAP_ENTRY*) (header.data() + sizeof(EFI_FIRMWARE_VOLUME_HEADER));
-    UINT32 blockMapSize = header.size() - sizeof(EFI_FIRMWARE_VOLUME_HEADER);
+    
+    // Get block map size
+    UINT32 extHeaderOffset = volumeHeader->Revision == 2 ? volumeHeader->ExtHeaderOffset : 0;
+    UINT32 blockMapSize = header.size() - extHeaderOffset - sizeof(EFI_FIRMWARE_VOLUME_HEADER);
+    if (blockMapSize % sizeof(EFI_FV_BLOCK_MAP_ENTRY))
+        return ERR_INVALID_VOLUME;
     UINT32 blockMapCount = blockMapSize / sizeof(EFI_FV_BLOCK_MAP_ENTRY);
     
     // Check blockMap validity
@@ -2252,7 +2091,7 @@ UINT8 FfsEngine::growVolume(QByteArray & header, const UINT32 size, UINT32 & new
 }
 
 // Will be refactored later
-QByteArray FfsEngine::decompressFile(const QModelIndex& index) const
+/*QByteArray FfsEngine::decompressFile(const QModelIndex& index) const
 {
     if (!index.isValid())
         return QByteArray();
@@ -2315,9 +2154,9 @@ QByteArray FfsEngine::decompressFile(const QModelIndex& index) const
         file.append(!fileHeader->IntegrityCheck.TailReference);
 
     return header.append(file);
-}
+}*/
 
-bool FfsEngine::isCompressedFile(const QModelIndex& index) const
+/*bool FfsEngine::isCompressedFile(const QModelIndex& index) const
 {
     if (!index.isValid())
         return false;
@@ -2332,4 +2171,4 @@ bool FfsEngine::isCompressedFile(const QModelIndex& index) const
     }
 
     return false;
-}
\ No newline at end of file
+}*/
\ No newline at end of file
diff --git a/ffsengine.h b/ffsengine.h
index dfaec81..c0ebe90 100644
--- a/ffsengine.h
+++ b/ffsengine.h
@@ -21,7 +21,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include "basetypes.h"
 #include "treeitem.h"
 #include "treemodel.h"
-#include "debuglistitem.h"
+#include "messagelistitem.h"
 
 class TreeModel;
 
@@ -37,8 +37,8 @@ public:
     // Returns model for Qt view classes
     TreeModel* model() const;
 
-    // Returns debug items queue
-    QQueue<DebugListItem*> debugMessage();
+    // Returns message items queue
+    QQueue<MessageListItem*> message();
 
     // Firmware image parsing
     UINT8 parseInputFile(const QByteArray & buffer);
@@ -64,38 +64,25 @@ public:
     // Construction routines
     UINT8 reconstructImage(QByteArray & reconstructed);
     UINT8 constructPadFile(const UINT32 size, const UINT8 revision, const char empty, QByteArray & pad);
-    UINT8 reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const UINT8 revision = 2, char empty = '\xFF');
+    UINT8 reconstruct(const QModelIndex & index, QQueue<QByteArray> & queue, const UINT8 revision = 2, char empty = '\xFF');
     UINT8 growVolume(QByteArray & header, const UINT32 size, UINT32 & newSize);
 
     // Operations on tree items
-    UINT8 insert(const QModelIndex & index, const QByteArray & object, const UINT8 type, const UINT8 mode);
+    UINT8 extract(const QModelIndex & index, QByteArray & extracted, const UINT8 mode);
+    UINT8 insert(const QModelIndex & index, const QByteArray & object, const UINT8 objectType, const UINT8 mode);
     UINT8 remove(const QModelIndex & index);
     
-    // Proxies to model operations
-    QByteArray header(const QModelIndex & index) const;
-    bool       hasEmptyHeader(const QModelIndex & index) const;
-    QByteArray body(const QModelIndex & index) const;
-    bool       hasEmptyBody(const QModelIndex & index) const;
-    
-    // Item-related operations
-    bool        isOfType(UINT8 type, const QModelIndex & index) const;
-    bool        isOfSubtype(UINT8 subtype, const QModelIndex & index) const;
-    QModelIndex findParentOfType(UINT8 type, const QModelIndex& index) const;
-    
-    // Will be refactored later
-    bool isCompressedFile(const QModelIndex & index) const;
-    QByteArray decompressFile(const QModelIndex & index) const;
-
 private:
     TreeItem  *rootItem;
     TreeModel *treeModel;
-    // Debug window helper
-    QQueue<DebugListItem*> debugItems;
+    
+    // Message helper
+    QQueue<MessageListItem*> messageItems;
     void msg(const QString & message, const QModelIndex index = QModelIndex());
-    // Internal operations used in insertInTree
-    bool setTreeItemName(const QString & data, const QModelIndex & index);
-    bool setTreeItemText(const QString & data, const QModelIndex & index);
-    UINT8 hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2);
+    
+    // Internal operations
+    QModelIndex findParentOfType(UINT8 type, const QModelIndex & index) const;
+    bool hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2);
 };
 
 #endif
diff --git a/debuglistitem.cpp b/messagelistitem.cpp
similarity index 58%
rename from debuglistitem.cpp
rename to messagelistitem.cpp
index 207c209..f8198a7 100644
--- a/debuglistitem.cpp
+++ b/messagelistitem.cpp
@@ -1,4 +1,4 @@
-/* debuglistitem.cpp
+/* messagelistitem.cpp
 
   Copyright (c) 2013, Nikolaj Schlej. All rights reserved.
   This program and the accompanying materials
@@ -11,37 +11,37 @@
 
 */
 
-#include "debuglistitem.h"
+#include "messagelistitem.h"
 
-DebugListItem::DebugListItem(QListWidget * parent, int type, const QModelIndex & index)
+MessageListItem::MessageListItem(QListWidget * parent, int type, const QModelIndex & index)
     : QListWidgetItem(parent, type)
 {
     itemIndex = index;
 }
 
-DebugListItem::DebugListItem(const QString & text, QListWidget * parent, int type, const QModelIndex & index)
+MessageListItem::MessageListItem(const QString & text, QListWidget * parent, int type, const QModelIndex & index)
     : QListWidgetItem(text, parent, type)
 {
     itemIndex = index;
 }
 
-DebugListItem::DebugListItem(const QIcon & icon, const QString & text, QListWidget * parent, int type, const QModelIndex & index)
+MessageListItem::MessageListItem(const QIcon & icon, const QString & text, QListWidget * parent, int type, const QModelIndex & index)
     : QListWidgetItem(icon, text, parent, type)
 {
     itemIndex = index;
 }
 
-DebugListItem::~DebugListItem()
+MessageListItem::~MessageListItem()
 {
 
 }
 
-QModelIndex DebugListItem::index() const
+QModelIndex MessageListItem::index() const
 {
     return itemIndex;
 }
 
-void DebugListItem::setIndex(QModelIndex & index)
+void MessageListItem::setIndex(QModelIndex & index)
 {
     itemIndex = index;
 }
\ No newline at end of file
diff --git a/debuglistitem.h b/messagelistitem.h
similarity index 56%
rename from debuglistitem.h
rename to messagelistitem.h
index af443ae..e1460ef 100644
--- a/debuglistitem.h
+++ b/messagelistitem.h
@@ -1,4 +1,4 @@
-/* debuglistitem.h
+/* messagelistitem.h
 
   Copyright (c) 2013, Nikolaj Schlej. All rights reserved.
   This program and the accompanying materials
@@ -11,21 +11,21 @@
 
 */
 
-#ifndef __DEBUGLISTITEM_H__
-#define __DEBUGLISTITEM_H__
+#ifndef __MESSAGELISTITEM_H__
+#define __MESSAGELISTITEM_H__
 
 #include <QModelIndex>
 #include <QListWidgetItem>
 
 #include "basetypes.h"
 
-class DebugListItem : public QListWidgetItem
+class MessageListItem : public QListWidgetItem
 {
 public:
-    DebugListItem(QListWidget * parent = 0, int type = Type, const QModelIndex & index = QModelIndex());
-    DebugListItem(const QString & text, QListWidget * parent = 0, int type = Type, const QModelIndex & index = QModelIndex());
-    DebugListItem(const QIcon & icon, const QString & text, QListWidget * parent = 0, int type = Type, const QModelIndex & index = QModelIndex());
-    ~DebugListItem();
+    MessageListItem(QListWidget * parent = 0, int type = Type, const QModelIndex & index = QModelIndex());
+    MessageListItem(const QString & text, QListWidget * parent = 0, int type = Type, const QModelIndex & index = QModelIndex());
+    MessageListItem(const QIcon & icon, const QString & text, QListWidget * parent = 0, int type = Type, const QModelIndex & index = QModelIndex());
+    ~MessageListItem();
     
     QModelIndex index() const;
     void setIndex(QModelIndex & index);
diff --git a/treeitem.cpp b/treeitem.cpp
index 088a120..4345319 100644
--- a/treeitem.cpp
+++ b/treeitem.cpp
@@ -21,8 +21,6 @@ QString itemTypeToQString(const UINT8 type)
     switch (type) {
     case TreeItem::Root:
         return QObject::tr("Root");
-    case TreeItem::IntelImage:
-        return QObject::tr("Intel image");
     case TreeItem::Image:
         return QObject::tr("Image");
     case TreeItem::Capsule:
@@ -46,8 +44,13 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype)
 {
     switch (type) {
     case TreeItem::Root:
-    case TreeItem::IntelImage:
     case TreeItem::Image:
+        if (subtype == TreeItem::IntelImage)
+            return QObject::tr("Intel");
+        else if (subtype == TreeItem::BiosImage)
+            return QObject::tr("BIOS");
+        else
+            return QObject::tr("Unknown");
     case TreeItem::Padding:
     case TreeItem::Volume:
         return "";
@@ -89,7 +92,7 @@ QString compressionTypeToQString(UINT8 algorithm)
 
 TreeItem::TreeItem(const UINT8 type, const UINT8 subtype, const UINT8 compression,
                    const QString & name, const QString & text, const QString & info, 
-                   const QByteArray & header, const QByteArray & body, 
+                   const QByteArray & header, const QByteArray & body, const QByteArray & tail, 
                    TreeItem *parent)
 {
     itemAction = NoAction;
@@ -101,6 +104,7 @@ TreeItem::TreeItem(const UINT8 type, const UINT8 subtype, const UINT8 compressio
     itemInfo = info;
     itemHeader = header;
     itemBody = body;
+    itemTail = tail;
     parentItem = parent;
     
     // Set default names
@@ -252,6 +256,12 @@ QByteArray TreeItem::body() const
     return itemBody;
 }
 
+QByteArray TreeItem::tail() const
+{
+    return itemTail;
+}
+
+
 bool TreeItem::hasEmptyHeader() const
 {
     return itemHeader.isEmpty();
@@ -262,6 +272,11 @@ bool TreeItem::hasEmptyBody() const
     return itemBody.isEmpty();
 }
 
+bool TreeItem::hasEmptyTail() const
+{
+    return itemTail.isEmpty();
+}
+
 UINT8 TreeItem::action() const
 {
     return itemAction;
diff --git a/treeitem.h b/treeitem.h
index 46891fc..61a3541 100644
--- a/treeitem.h
+++ b/treeitem.h
@@ -30,33 +30,38 @@ class TreeItem
 public:
     // Action types
     enum ActionTypes {
-        NoAction,
-        Remove,
-        Reconstruct
+        NoAction = 50,
+        Remove,      
+        Reconstruct 
     };
     
     // Item types
     enum ItemTypes {
-        Root,
-        Capsule,
-        IntelImage,
-        Image,
-        Region,
-        Padding,
-        Volume,
-        File,
-        Section
+        Root = 60,
+        Capsule,    
+        Image,      
+        Region,     
+        Padding,    
+        Volume,     
+        File,       
+        Section    
+    };
+
+    // Image subtypes 
+    enum ImageSubtypes{
+        IntelImage = 70,
+        BiosImage
     };
 
     // Capsule subtypes
     enum CapsuleSubtypes {
-        AptioCapsule,
+        AptioCapsule = 80,
         UefiCapsule
     };
 
     // Region subtypes
     enum RegionSubtypes {
-        DescriptorRegion,
+        DescriptorRegion = 90,
         GbeRegion,
         MeRegion,
         BiosRegion,
@@ -66,7 +71,8 @@ public:
     // Constructor
     TreeItem(const UINT8 type, const UINT8 subtype = 0, const UINT8 compression = COMPRESSION_ALGORITHM_NONE, 
         const QString &name = QString(), const QString &text = QString(), const QString &info = QString(), 
-        const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(), TreeItem *parent = 0);
+        const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(), const QByteArray & tail = QByteArray(),
+        TreeItem *parent = 0);
     // Destructor
     ~TreeItem();
 
@@ -91,6 +97,8 @@ public:
     bool hasEmptyHeader() const;
     QByteArray body() const;
     bool hasEmptyBody() const;
+    QByteArray tail() const;
+    bool hasEmptyTail() const;
     QString info() const;
     UINT8 compression() const;
 
@@ -117,6 +125,7 @@ private:
     UINT8 itemCompression;
     QByteArray itemHeader;
     QByteArray itemBody;
+    QByteArray itemTail;
     QString itemTypeName;
     QString itemSubtypeName;
     QString itemName;
diff --git a/treemodel.cpp b/treemodel.cpp
index 9311161..c7d3675 100644
--- a/treemodel.cpp
+++ b/treemodel.cpp
@@ -154,8 +154,8 @@ UINT8 TreeModel::setItemAction(const UINT8 action, const QModelIndex &index)
 
 QModelIndex TreeModel::addItem(const UINT8 type, const UINT8 subtype, const UINT8 compression, 
                                const QString & name, const QString & text, const QString & info, 
-                               const QByteArray & header, const QByteArray & body, const QModelIndex & index,
-                               const UINT8 mode)
+                               const QByteArray & header, const QByteArray & body, const QByteArray & tail,
+                               const QModelIndex & index, const UINT8 mode)
 {
     TreeItem *item;
     TreeItem *parentItem;
@@ -176,7 +176,7 @@ QModelIndex TreeModel::addItem(const UINT8 type, const UINT8 subtype, const UINT
         }
     }
     
-    TreeItem *newItem = new TreeItem(type, subtype, compression, name, text, info, header, body, parentItem);
+    TreeItem *newItem = new TreeItem(type, subtype, compression, name, text, info, header, body, tail, parentItem);
     if (mode == INSERT_MODE_APPEND) {
         emit layoutAboutToBeChanged();
         parentItem->appendChild(newItem);
diff --git a/treemodel.h b/treemodel.h
index c2c67d9..3793199 100644
--- a/treemodel.h
+++ b/treemodel.h
@@ -47,8 +47,8 @@ public:
     
     QModelIndex addItem(const UINT8 type, const UINT8 subtype = 0, const UINT8 compression = COMPRESSION_ALGORITHM_NONE,
         const QString & name = QString(), const QString & text = QString(), const QString & info = QString(), 
-        const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(), const QModelIndex & index = QModelIndex(),
-        const UINT8 mode = INSERT_MODE_APPEND);
+        const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(), const QByteArray & tail = QByteArray(),
+        const QModelIndex & index = QModelIndex(), const UINT8 mode = INSERT_MODE_APPEND);
 
 private:
     TreeItem *rootItem;
diff --git a/uefitool.cpp b/uefitool.cpp
index e881090..104617f 100644
--- a/uefitool.cpp
+++ b/uefitool.cpp
@@ -23,7 +23,7 @@ UEFITool::UEFITool(QWidget *parent) :
 
     //Connect
     connect(ui->actionOpenImageFile, SIGNAL(triggered()), this, SLOT(openImageFile()));
-    connect(ui->actionExtract, SIGNAL(triggered()), this, SLOT(extract()));
+    connect(ui->actionExtract, SIGNAL(triggered()), this, SLOT(extractAsIs()));
     connect(ui->actionExtractBody, SIGNAL(triggered()), this, SLOT(extractBody()));
     connect(ui->actionExtractUncompressed, SIGNAL(triggered()), this, SLOT(extractUncompressed()));
     connect(ui->actionInsertInto, SIGNAL(triggered()), this, SLOT(insertInto()));
@@ -49,7 +49,7 @@ UEFITool::~UEFITool()
 void UEFITool::init()
 {
     // Clear components
-    ui->debugListWidget->clear();
+    ui->messageListWidget->clear();
     ui->infoEdit->clear();
     
     // Disable all actions except openImageFile
@@ -72,58 +72,60 @@ void UEFITool::init()
     connect(ui->structureTreeView, SIGNAL(expanded(const QModelIndex &)), this, SLOT(resizeTreeViewColums(void)));
     connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
         this, SLOT(populateUi(const QModelIndex &)));
-    connect(ui->debugListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(scrollTreeView(QListWidgetItem*)));
+    connect(ui->messageListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(scrollTreeView(QListWidgetItem*)));
 
     resizeTreeViewColums();
 }
 
 void UEFITool::populateUi(const QModelIndex &current)
 {
-    currentIndex = current;
-    ui->infoEdit->setPlainText(current.data(Qt::UserRole).toString());
-    ui->actionExtract->setDisabled(ffsEngine->hasEmptyBody(current) && ffsEngine->hasEmptyHeader(current));
-    ui->actionExtractBody->setDisabled(ffsEngine->hasEmptyHeader(current));
-    ui->actionExtractUncompressed->setEnabled(ffsEngine->isCompressedFile(current));
-    ui->actionRemove->setEnabled(ffsEngine->isOfType(TreeItem::Volume, current) 
-        || ffsEngine->isOfType(TreeItem::File, current) 
-        || ffsEngine->isOfType(TreeItem::Section, current));
-    ui->actionInsertInto->setEnabled(ffsEngine->isOfType(TreeItem::Volume, current) 
-        || ffsEngine->isOfType(TreeItem::File, current)
-        || (ffsEngine->isOfType(TreeItem::Section, current) 
-           && (ffsEngine->isOfSubtype(EFI_SECTION_COMPRESSION, current) 
-           || ffsEngine->isOfSubtype(EFI_SECTION_GUID_DEFINED, current) 
-           || ffsEngine->isOfSubtype(EFI_SECTION_DISPOSABLE, current))));
-    ui->actionInsertBefore->setEnabled(ffsEngine->isOfType(TreeItem::File, current) 
-        || ffsEngine->isOfType(TreeItem::Section, current));
-    ui->actionInsertAfter->setEnabled(ffsEngine->isOfType(TreeItem::File, current)
-        || ffsEngine->isOfType(TreeItem::Section, current));
+    if (!current.isValid())
+        return;
+
+    TreeItem* item = static_cast<TreeItem*>(current.internalPointer());
+    UINT8 type = item->type();
+    UINT8 subtype = item->subtype();
+
+    ui->infoEdit->setPlainText(item->info());
+    ui->actionExtract->setDisabled(item->hasEmptyHeader() && item->hasEmptyBody() && item->hasEmptyTail());
+    ui->actionExtractBody->setDisabled(item->hasEmptyHeader());
+    //ui->actionExtractUncompressed->setEnabled(ffsEngine->isCompressedFile(current));
+    ui->actionRemove->setEnabled(type == TreeItem::Volume || type == TreeItem::File || type == TreeItem::Section);
+    ui->actionInsertInto->setEnabled(type == TreeItem::Volume || type == TreeItem::File 
+        || (type == TreeItem::Section && (subtype == EFI_SECTION_COMPRESSION || subtype == EFI_SECTION_GUID_DEFINED || subtype == EFI_SECTION_DISPOSABLE)));
+    ui->actionInsertBefore->setEnabled(type == TreeItem::File || type == TreeItem::Section);
+    ui->actionInsertAfter->setEnabled(type == TreeItem::File || type == TreeItem::Section); 
     //ui->actionReplace->setEnabled(ffsEngine->isOfType(TreeItem::File, current));
 }
 
 void UEFITool::remove()
 {
-    UINT8 result = ffsEngine->remove(currentIndex);
-    if (result) {
-        
-    }
-    else
+    QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex();
+    if (!index.isValid())
+        return;
+
+    UINT8 result = ffsEngine->remove(index);
+
+    if (result == ERR_SUCCESS)
         ui->actionSaveImageFile->setEnabled(true);
-    
-    resizeTreeViewColums();
 }
 
 void UEFITool::insert(const UINT8 mode)
 {
-    QString path;
-    TreeItem* item = static_cast<TreeItem*>(currentIndex.internalPointer());
+    QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex();
+    if (!index.isValid())
+        return;
     
+    TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
     UINT8 type;
 	UINT8 objectType;
+
     if (mode == INSERT_MODE_BEFORE || mode == INSERT_MODE_AFTER)
         type = item->parent()->type();
     else
         type = item->type();
 
+    QString path;
     switch (type) {
     case TreeItem::Volume:
         path = QFileDialog::getOpenFileName(this, tr("Select FFS file to insert"),".","FFS file (*.ffs *.bin);;All files (*.*)");
@@ -131,7 +133,7 @@ void UEFITool::insert(const UINT8 mode)
     break;
     case TreeItem::File:
     case TreeItem::Section:
-        path = QFileDialog::getOpenFileName(this, tr("Select section file to insert"),".","Section file (*.sec *.bin);;All files (*.*)");
+        path = QFileDialog::getOpenFileName(this, tr("Select section file to insert"),".","Section file (*.sct *.bin);;All files (*.*)");
 		objectType = TreeItem::Section;
     break;
     default:
@@ -157,13 +159,11 @@ void UEFITool::insert(const UINT8 mode)
     QByteArray buffer = inputFile.readAll();
     inputFile.close();
 
-    UINT8 result = ffsEngine->insert(currentIndex, buffer, objectType, mode);
+    UINT8 result = ffsEngine->insert(index, buffer, objectType, mode);
     if (result)
         ui->statusBar->showMessage(tr("File can't be inserted (%1)").arg(result));
     else
         ui->actionSaveImageFile->setEnabled(true);
-    
-    resizeTreeViewColums();
 }
 
 void UEFITool::insertInto()
@@ -203,7 +203,7 @@ void UEFITool::saveImageFile()
     if (result)
     {
         ui->statusBar->showMessage(tr("Reconstruction failed (%1)").arg(result));
-        showDebugMessage();
+        showMessage();
         return;
     }
 
@@ -211,7 +211,7 @@ void UEFITool::saveImageFile()
     outputFile.write(reconstructed);
     outputFile.close();
     ui->statusBar->showMessage(tr("Reconstructed image written"));
-    showDebugMessage();
+    showMessage();
 }
 
 void UEFITool::resizeTreeViewColums()
@@ -255,47 +255,45 @@ void UEFITool::openImageFile(QString path)
     else
         ui->statusBar->showMessage(tr("Opened: %1").arg(fileInfo.fileName()));
     
-    showDebugMessage();
+    showMessage();
     resizeTreeViewColums();
 }
 
-void UEFITool::extract()
+void UEFITool::extract(const UINT8 mode)
 {
-    QString path = QFileDialog::getSaveFileName(this, tr("Save selected item to binary file"),".","Binary files (*.bin);;All files (*.*)");
+    QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex();
+    if (!index.isValid())
+        return;
+    
+    TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
+    UINT8 type = item->type();
 
-    QFile outputFile;
-    outputFile.setFileName(path);
-    if (!outputFile.open(QFile::WriteOnly))
-    {
-        ui->statusBar->showMessage(tr("Can't open file for rewriting"));
+    QString path;
+    switch (type) {
+    case TreeItem::Capsule:
+        path = QFileDialog::getSaveFileName(this, tr("Save capsule to binary file"),".","Capsule file (*.cap *.bin);;All files (*.*)");
+        break;
+    case TreeItem::Image:
+        path = QFileDialog::getSaveFileName(this, tr("Save image to binary file"),".","Image file (*.rom *.bin);;All files (*.*)");
+        break;
+    case TreeItem::Region:
+        path = QFileDialog::getSaveFileName(this, tr("Save region to binary file"),".","Region file (*.rgn *.bin);;All files (*.*)");
+        break;
+    case TreeItem::Padding:
+        path = QFileDialog::getSaveFileName(this, tr("Save padding to binary file"),".","Padding file (*.pad *.bin);;All files (*.*)");
+        break;
+    case TreeItem::Volume:
+        path = QFileDialog::getSaveFileName(this, tr("Save volume to binary file"),".","Volume file (*.vol *.bin);;All files (*.*)");
+        break;
+    case TreeItem::File:
+        path = QFileDialog::getSaveFileName(this, tr("Save FFS file to binary file"),".","FFS file (*.ffs *.bin);;All files (*.*)");
+        break;
+    case TreeItem::Section:
+        path = QFileDialog::getSaveFileName(this, tr("Select section file to insert"),".","Section file (*.sct *.bin);;All files (*.*)");
+    break;
+    default:
         return;
     }
-
-    outputFile.resize(0);
-    outputFile.write(ffsEngine->header(currentIndex) + ffsEngine->body(currentIndex));
-    outputFile.close();
-}
-
-void UEFITool::extractBody()
-{
-    QString path = QFileDialog::getSaveFileName(this, tr("Save selected item without header to file"),".","Binary files (*.bin);;All files (*.*)");
-
-    QFile outputFile;
-    outputFile.setFileName(path);
-    if (!outputFile.open(QFile::WriteOnly))
-    {
-        ui->statusBar->showMessage(tr("Can't open file for rewriting"));
-        return;
-    }
-
-    outputFile.resize(0);
-    outputFile.write(ffsEngine->body(currentIndex));
-    outputFile.close();
-}
-
-void UEFITool::extractUncompressed()
-{
-    QString path = QFileDialog::getSaveFileName(this, tr("Save selected FFS file as uncompressed to file"),".","FFS files (*.ffs);;All files (*.*)");
     
     QFile outputFile;
     outputFile.setFileName(path);
@@ -305,9 +303,30 @@ void UEFITool::extractUncompressed()
         return;
     }
 
-    outputFile.resize(0);
-    outputFile.write(ffsEngine->decompressFile(currentIndex));
-    outputFile.close();
+    QByteArray extracted;
+    UINT8 result = ffsEngine->extract(index, extracted, mode);
+    if (result) 
+        ui->statusBar->showMessage(tr("File can't be extracted (%1)").arg(result));
+    else {
+        outputFile.resize(0);
+        outputFile.write(extracted);
+        outputFile.close();
+    }
+}
+
+void UEFITool::extractAsIs()
+{
+    extract(EXTRACT_MODE_AS_IS);
+}
+
+void UEFITool::extractBody()
+{
+    extract(EXTRACT_MODE_BODY_ONLY);
+}
+
+void UEFITool::extractUncompressed()
+{
+    extract(EXTRACT_MODE_UNCOMPRESSED);
 }
 
 void UEFITool::dragEnterEvent(QDragEnterEvent* event)
@@ -322,22 +341,22 @@ void UEFITool::dropEvent(QDropEvent* event)
     openImageFile(path);
 }
 
-void UEFITool::showDebugMessage()
+void UEFITool::showMessage()
 {
-    ui->debugListWidget->clear();
-    QQueue<DebugListItem*> debugItems = ffsEngine->debugMessage();
-    for (int i = 0; i < debugItems.count(); i++) {
-        ui->debugListWidget->addItem((QListWidgetItem*) debugItems.at(i));
+    ui->messageListWidget->clear();
+    QQueue<MessageListItem*> messageItems = ffsEngine->message();
+    for (int i = 0; i < messageItems.count(); i++) {
+        ui->messageListWidget->addItem(messageItems.at(i));
     }
 }
 
 void UEFITool::scrollTreeView(QListWidgetItem* item)
 {
-    DebugListItem* debugItem = (DebugListItem*) item;
-    QModelIndex index = debugItem->index();
+    MessageListItem* messageItem = (MessageListItem*) item;
+    QModelIndex index = messageItem->index();
     if (index.isValid()) {
         ui->structureTreeView->scrollTo(index);
-        ui->structureTreeView->selectionModel()->select(currentIndex, QItemSelectionModel::Clear);
+        ui->structureTreeView->selectionModel()->clearSelection();
         ui->structureTreeView->selectionModel()->select(index, QItemSelectionModel::Select);
     }
 }
\ No newline at end of file
diff --git a/uefitool.h b/uefitool.h
index e683aba..143a105 100644
--- a/uefitool.h
+++ b/uefitool.h
@@ -50,7 +50,8 @@ private slots:
     void saveImageFile();
     void populateUi(const QModelIndex &current);
     void resizeTreeViewColums();
-    void extract();
+    void extract(const UINT8 mode);
+    void extractAsIs();
     void extractBody();
     void extractUncompressed();
     void insert(const UINT8 mode);
@@ -64,11 +65,10 @@ private slots:
 private:
     Ui::UEFITool * ui;
     FfsEngine* ffsEngine;
-    QModelIndex currentIndex;
     
     void dragEnterEvent(QDragEnterEvent* event);
     void dropEvent(QDropEvent* event);
-    void showDebugMessage();
+    void showMessage();
 };
 
 #endif
diff --git a/uefitool.pro b/uefitool.pro
index c8a0727..c0061d4 100644
--- a/uefitool.pro
+++ b/uefitool.pro
@@ -11,7 +11,7 @@ SOURCES  += main.cpp \
 			ffsengine.cpp \
             treeitem.cpp \ 
             treemodel.cpp \
-			debuglistitem.cpp \
+			messagelistitem.cpp \
             LZMA/LzmaCompress.c \
             LZMA/LzmaDecompress.c \
             LZMA/SDK/C/LzFind.c \
@@ -29,7 +29,7 @@ HEADERS  += uefitool.h \
 			ffsengine.h \
             treeitem.h \
             treemodel.h \
-			debuglistitem.h \
+			messagelistitem.h \
             LZMA/LzmaCompress.h \
             LZMA/LzmaDecompress.h \
             Tiano/EfiTianoDecompress.h \
diff --git a/uefitool.ui b/uefitool.ui
index c9c7b7c..0d45587 100644
--- a/uefitool.ui
+++ b/uefitool.ui
@@ -20,7 +20,7 @@
    <bool>true</bool>
   </property>
   <property name="windowTitle">
-   <string>UEFITool 0.7.0</string>
+   <string>UEFITool 0.8.0</string>
   </property>
   <widget class="QWidget" name="centralWidget">
    <property name="sizePolicy">
@@ -135,7 +135,7 @@
      </widget>
     </item>
     <item row="1" column="0" colspan="2">
-     <widget class="QGroupBox" name="debugGroupBox">
+     <widget class="QGroupBox" name="messageGroupBox">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
         <horstretch>0</horstretch>
@@ -149,7 +149,7 @@
        </size>
       </property>
       <property name="title">
-       <string>Debug</string>
+       <string>Message</string>
       </property>
       <layout class="QHBoxLayout" name="horizontalLayout">
        <property name="spacing">
@@ -159,7 +159,7 @@
         <number>5</number>
        </property>
        <item>
-        <widget class="QListWidget" name="debugListWidget"/>
+        <widget class="QListWidget" name="messageListWidget"/>
        </item>
       </layout>
      </widget>
@@ -201,7 +201,7 @@
     <bool>false</bool>
    </property>
    <property name="text">
-    <string>Insert after...</string>
+    <string>Insert object after...</string>
    </property>
    <property name="toolTip">
     <string>Insert an object from file after selected object</string>
@@ -215,7 +215,7 @@
     <bool>false</bool>
    </property>
    <property name="text">
-    <string>Insert before...</string>
+    <string>Insert object before...</string>
    </property>
    <property name="toolTip">
     <string>Insert object from file before selected object</string>
@@ -243,10 +243,10 @@
     <bool>false</bool>
    </property>
    <property name="text">
-    <string>Extract...</string>
+    <string>Extract as is...</string>
    </property>
    <property name="toolTip">
-    <string>Extract selected object to file</string>
+    <string>Extract selected object as is to file</string>
    </property>
    <property name="shortcut">
     <string>Ctrl+E</string>
@@ -257,7 +257,7 @@
     <bool>false</bool>
    </property>
    <property name="text">
-    <string>Extract body...</string>
+    <string>Extract without header...</string>
    </property>
    <property name="toolTip">
     <string>Extract selected object without header to file</string>
@@ -310,7 +310,7 @@
     <bool>false</bool>
    </property>
    <property name="text">
-    <string>Insert into...</string>
+    <string>Insert object into...</string>
    </property>
    <property name="toolTip">
     <string>Insert object from file into selected object</string>