Hello community,

here is the log from the commit of package UEFITool for openSUSE:Factory 
checked in at 2018-03-09 10:46:25
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/UEFITool (Old)
 and      /work/SRC/openSUSE:Factory/.UEFITool.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "UEFITool"

Fri Mar  9 10:46:25 2018 rev:3 rq:584443 version:20180225

Changes:
--------
--- /work/SRC/openSUSE:Factory/UEFITool/UEFITool.changes        2017-07-25 
11:41:16.188942464 +0200
+++ /work/SRC/openSUSE:Factory/.UEFITool.new/UEFITool.changes   2018-03-09 
10:46:27.502975575 +0100
@@ -1,0 +2,11 @@
+Thu Mar  8 14:01:24 UTC 2018 - [email protected]
+
+- Update to version 20180225:
+  * fixed rebase PEI files with nonstandard alignment
+  * Fixed patches for Skylake-X
+  * multiple fixes
+  * fix for #99
+  * 0.22.1 multiple FFSv3 support fixes, thanks to @osresearch
+  * add FFSv3 support with large files and large sections
+
+-------------------------------------------------------------------

Old:
----
  UEFITool-20170506.tar.xz

New:
----
  UEFITool-20180225.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ UEFITool.spec ++++++
--- /var/tmp/diff_new_pack.hOQ5u9/_old  2018-03-09 10:46:28.282947481 +0100
+++ /var/tmp/diff_new_pack.hOQ5u9/_new  2018-03-09 10:46:28.282947481 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package UEFITool
 #
-# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,12 +17,12 @@
 
 
 Name:           UEFITool
-Version:        20170506
+Version:        20180225
 Release:        0
 Summary:        Tools to inspect and work on UEFI BIOSes
 License:        BSD-2-Clause
 Group:          Development/Tools/Other
-Url:            https://github.com/LongSoft/UEFITool
+URL:            https://github.com/LongSoft/UEFITool
 Source0:        %{name}-%{version}.tar.xz
 BuildRequires:  pkgconfig
 BuildRequires:  pkgconfig(Qt5Core)
@@ -49,17 +49,17 @@
 done
 
 %install
-install -D -p -m 0755 UEFITool \
+install -Dpm 0755 UEFITool \
   %{buildroot}/%{_bindir}/UEFITool
 for i in UEFIExtract UEFIFind UEFIPatch UEFIReplace; do
   pushd $i
-    install -D -p -m 0755 $i %{buildroot}/%{_bindir}/$i
+    install -Dpm 0755 $i %{buildroot}/%{_bindir}/$i
   popd
 done
 
 %files
-%defattr(-,root,root)
-%doc LICENSE.md README.rst
+%license LICENSE.md
+%doc README.rst
 %{_bindir}/UEFITool
 %{_bindir}/UEFIExtract
 %{_bindir}/UEFIFind

++++++ UEFITool-20170506.tar.xz -> UEFITool-20180225.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/UEFITool-20170506/UEFIExtract/uefiextract_main.cpp 
new/UEFITool-20180225/UEFIExtract/uefiextract_main.cpp
--- old/UEFITool-20170506/UEFIExtract/uefiextract_main.cpp      2017-05-07 
02:24:47.000000000 +0200
+++ new/UEFITool-20180225/UEFIExtract/uefiextract_main.cpp      2018-02-26 
00:40:14.000000000 +0100
@@ -1,6 +1,6 @@
 /* uefiextract_main.cpp
 
-Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
+Copyright (c) 2018, LongSoft. All rights reserved.
 This program and the accompanying materials
 are licensed and made available under the terms and conditions of the BSD 
License
 which accompanies this distribution.  The full text of the license may be 
found at
@@ -19,8 +19,8 @@
 int main(int argc, char *argv[])
 {
   QCoreApplication a(argc, argv);
-  a.setOrganizationName("CodeRush");
-  a.setOrganizationDomain("coderush.me");
+  a.setOrganizationName("LongSoft");
+  a.setOrganizationDomain("longsoft.me");
   a.setApplicationName("UEFIExtract");
 
   UEFIExtract w;
@@ -52,7 +52,7 @@
     
   }
   else {
-    std::cout << "UEFIExtract 0.4.4" << std::endl << std::endl <<
+    std::cout << "UEFIExtract 0.4.5" << std::endl << std::endl <<
     "Usage: uefiextract imagefile [FileGUID_1 FileGUID_2 ... FileGUID_31]" << 
std::endl <<
     "Returned value is a bit mask where 0 on position N meant File with GUID_N 
was found and unpacked, 1 otherwise" << std::endl;
     return 1;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/UEFITool-20170506/UEFIPatch/patches.txt 
new/UEFITool-20180225/UEFIPatch/patches.txt
--- old/UEFITool-20170506/UEFIPatch/patches.txt 2017-05-07 02:24:47.000000000 
+0200
+++ new/UEFITool-20180225/UEFIPatch/patches.txt 2018-02-26 00:40:14.000000000 
+0100
@@ -34,6 +34,7 @@
 
 # PowerManagement | Sandy Bridge with ME 8.xx, Ivy Bridge 
 8C783970-F02A-4A4D-AF09-8797A51EEC8D 10 
P:75080FBAE80F89442430:EB080FBAE80F89442430 
+
 # PowerManagement | New SB-E/IB-E 
 8C783970-F02A-4A4D-AF09-8797A51EEC8D 10 P:0FBA6C24380F:0FBA7424380F 
 
@@ -48,5 +49,11 @@
 299D6F8B-2EC9-4E40-9EC6-DDAA7EBF5FD9 12 P:75080D00800000:EB080D00800000 
 
 # SiInit | Kaby Lake
-299D6F8B-2EC9-4E40-9EC6-DDAA7EBF5FD9 10 P:81E10080000033C1:9090909090909090
+299D6F8B-2EC9-4E40-9EC6-DDAA7EBF5FD9 10 P:81E10080000033C1:9090909090909090 
 299D6F8B-2EC9-4E40-9EC6-DDAA7EBF5FD9 12 P:81E10080000033C1:9090909090909090 
+
+# PpmInitialize | Skylake-X
+3FFCAE95-23CF-4967-94F5-16352F68E43B 10 P:742CB9E2000000:752CB9E2000000 
+
+# CpuInitPei | Skylake-X
+01359D99-9446-456D-ADA4-50A711C03ADA 12 P:BE0080000023CE0B:BE0000000023CE0B 
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/UEFITool-20170506/UEFIPatch/uefipatch_main.cpp 
new/UEFITool-20180225/UEFIPatch/uefipatch_main.cpp
--- old/UEFITool-20170506/UEFIPatch/uefipatch_main.cpp  2017-05-07 
02:24:47.000000000 +0200
+++ new/UEFITool-20180225/UEFIPatch/uefipatch_main.cpp  2018-02-26 
00:40:14.000000000 +0100
@@ -1,6 +1,6 @@
 /* uefipatch_main.cpp
 
-Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
+Copyright (c) 2018, LongSoft. All rights reserved.
 This program and the accompanying materials
 are licensed and made available under the terms and conditions of the BSD 
License
 which accompanies this distribution.  The full text of the license may be 
found at
@@ -19,8 +19,8 @@
 int main(int argc, char *argv[])
 {
     QCoreApplication a(argc, argv);
-    a.setOrganizationName("CodeRush");
-    a.setOrganizationDomain("coderush.me");
+    a.setOrganizationName("LongSoft");
+    a.setOrganizationDomain("longsoft.me");
     a.setApplicationName("UEFIPatch");
 
     UEFIPatch w;
@@ -31,7 +31,7 @@
         result = w.patchFromFile(a.arguments().at(1));
     }
     else {
-        std::cout << "UEFIPatch 0.3.9 - UEFI image file patching utility" << 
std::endl << std::endl <<
+        std::cout << "UEFIPatch 0.3.13 - UEFI image file patching utility" << 
std::endl << std::endl <<
             "Usage: UEFIPatch image_file" << std::endl << std::endl <<
             "Patches will be read from patches.txt file\n";
         return ERR_SUCCESS;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/UEFITool-20170506/UEFIReplace/uefireplace_main.cpp 
new/UEFITool-20180225/UEFIReplace/uefireplace_main.cpp
--- old/UEFITool-20170506/UEFIReplace/uefireplace_main.cpp      2017-05-07 
02:24:47.000000000 +0200
+++ new/UEFITool-20180225/UEFIReplace/uefireplace_main.cpp      2018-02-26 
00:40:14.000000000 +0100
@@ -19,8 +19,8 @@
 int main(int argc, char *argv[])
 {
     QCoreApplication a(argc, argv);
-    a.setOrganizationName("CodeRush");
-    a.setOrganizationDomain("coderush.me");
+    a.setOrganizationName("LongSoft");
+    a.setOrganizationDomain("longsoft.me");
     a.setApplicationName("UEFIReplace");
 
     UEFIReplace r;
@@ -28,7 +28,7 @@
     QStringList args = a.arguments();
 
     if (args.length() < 5) {
-        std::cout << "UEFIReplace 0.3.9 - UEFI image file replacement utility" 
<< std::endl << std::endl <<
+        std::cout << "UEFIReplace 0.1.1 - UEFI image file replacement utility" 
<< std::endl << std::endl <<
             "Usage: UEFIReplace image_file guid section_type contents_file" << 
std::endl;
         return ERR_SUCCESS;
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/UEFITool-20170506/ffs.cpp 
new/UEFITool-20180225/ffs.cpp
--- old/UEFITool-20170506/ffs.cpp       2017-05-07 02:24:47.000000000 +0200
+++ new/UEFITool-20180225/ffs.cpp       2018-02-26 00:40:14.000000000 +0100
@@ -30,7 +30,10 @@
 const UINT8 ffsAlignmentTable[] =
 { 0, 4, 7, 9, 10, 12, 15, 16 };
 
-UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize)
+const UINT8 ffsAlignment2Table[] =
+{ 17, 18, 19, 20, 21, 22, 23, 24 };
+
+UINT8 calculateSum8(const UINT8* buffer, UINT32 bufferSize)
 {
     if (!buffer)
         return 0;
@@ -40,7 +43,15 @@
     while (bufferSize--)
         counter += buffer[bufferSize];
 
-    return (UINT8)0x100 - counter;
+    return counter;
+}
+
+UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize)
+{
+    if (!buffer)
+        return 0;
+
+    return (UINT8)0x100 - calculateSum8(buffer, bufferSize);
 }
 
 UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize)
@@ -120,6 +131,8 @@
     case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE: return QObject::tr("Volume 
image");
     case EFI_FV_FILETYPE_COMBINED_SMM_DXE:      return QObject::tr("Combined 
SMM/DXE");
     case EFI_FV_FILETYPE_SMM_CORE:              return QObject::tr("SMM core");
+       case EFI_FV_FILETYPE_SMM_STANDALONE:        return QObject::tr("SMM 
standalone");
+       case EFI_FV_FILETYPE_SMM_CORE_STANDALONE:   return QObject::tr("SMM 
core standalone");
     case EFI_FV_FILETYPE_PAD:                   return QObject::tr("Pad");
     default:                                    return QObject::tr("Unknown");
     };
@@ -155,10 +168,10 @@
     if (!header)
         return 0;
 
-    const bool extended = false;
-    /*if (uint24ToUint32(header->Size) == EFI_SECTION2_IS_USED) {
+    bool extended = false;
+    if (uint24ToUint32(header->Size) == EFI_SECTION2_IS_USED) {
         extended = true;
-    }*/
+    }
 
     switch (header->Type)
     {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/UEFITool-20170506/ffs.h new/UEFITool-20180225/ffs.h
--- old/UEFITool-20170506/ffs.h 2017-05-07 02:24:47.000000000 +0200
+++ new/UEFITool-20180225/ffs.h 2018-02-26 00:40:14.000000000 +0100
@@ -292,7 +292,7 @@
 UINT8                   Attributes;
 UINT8                   Size[3]; // Set to 0xFFFFFF
 UINT8                   State;
-UINT32                  ExtendedSize;
+UINT64                  ExtendedSize;
 } EFI_FFS_FILE_HEADER2;
 
 // Standard data checksum, used if FFS_ATTRIB_CHECKSUM is clear
@@ -314,6 +314,8 @@
 #define EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE   0x0B
 #define EFI_FV_FILETYPE_COMBINED_SMM_DXE        0x0C
 #define EFI_FV_FILETYPE_SMM_CORE                0x0D
+#define EFI_FV_FILETYPE_SMM_STANDALONE          0x0E
+#define EFI_FV_FILETYPE_SMM_CORE_STANDALONE     0x0F
 #define EFI_FV_FILETYPE_OEM_MIN                 0xC0
 #define EFI_FV_FILETYPE_OEM_MAX                 0xDF
 #define EFI_FV_FILETYPE_DEBUG_MIN               0xE0
@@ -326,6 +328,7 @@
 #define FFS_ATTRIB_TAIL_PRESENT       0x01 // Valid only for revision 1 volumes
 #define FFS_ATTRIB_RECOVERY           0x02 // Valid only for revision 1 volumes
 #define FFS_ATTRIB_LARGE_FILE         0x01 // Valid only for FFSv3 volumes
+#define FFS_ATTRIB_DATA_ALIGNMENT2    0x02 // Valid only for revision 2 volumes
 #define FFS_ATTRIB_FIXED              0x04
 #define FFS_ATTRIB_DATA_ALIGNMENT     0x38
 #define FFS_ATTRIB_CHECKSUM           0x40
@@ -333,6 +336,9 @@
 // FFS alignment table
 extern const UINT8 ffsAlignmentTable[];
 
+// Extended FFS alignment table
+extern const UINT8 ffsAlignment2Table[];
+
 // File states
 #define EFI_FILE_HEADER_CONSTRUCTION    0x01
 #define EFI_FILE_HEADER_VALID           0x02
@@ -340,6 +346,7 @@
 #define EFI_FILE_MARKED_FOR_UPDATE      0x08
 #define EFI_FILE_DELETED                0x10
 #define EFI_FILE_HEADER_INVALID         0x20
+#define EFI_FILE_ERASE_POLARITY         0x80 // Defined as "all other bits 
must be set to ERASE_POLARITY" in UEFI PI
 
 // PEI apriori file
 const QByteArray EFI_PEI_APRIORI_FILE_GUID
@@ -360,7 +367,9 @@
 // FFS size conversion routines
 extern VOID uint32ToUint24(UINT32 size, UINT8* ffsSize);
 extern UINT32 uint24ToUint32(const UINT8* ffsSize);
-// FFS file 8bit checksum calculation routine
+
+// FFS file 8bit checksum calculation routines
+extern UINT8 calculateSum8(const UINT8* buffer, UINT32 bufferSize);
 extern UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize);
 
 //*****************************************************************************
@@ -528,7 +537,7 @@
 typedef EFI_COMMON_SECTION_HEADER  EFI_USER_INTERFACE_SECTION;
 typedef EFI_COMMON_SECTION_HEADER2 EFI_USER_INTERFACE_SECTION2;
 
-//Section routines
+// Section routines
 extern UINT32 sizeOfSectionHeader(const EFI_COMMON_SECTION_HEADER* header);
 
 //*****************************************************************************
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/UEFITool-20170506/ffsengine.cpp 
new/UEFITool-20180225/ffsengine.cpp
--- old/UEFITool-20170506/ffsengine.cpp 2017-05-07 02:24:47.000000000 +0200
+++ new/UEFITool-20180225/ffsengine.cpp 2018-02-26 00:40:14.000000000 +0100
@@ -287,15 +287,9 @@
     const FLASH_DESCRIPTOR_COMPONENT_SECTION* componentSection = (const 
FLASH_DESCRIPTOR_COMPONENT_SECTION*)calculateAddress8(descriptor, 
descriptorMap->ComponentBase);
 
     // Check descriptor version by getting hardcoded value of 
FlashParameters.ReadClockFrequency
-    UINT8 descriptorVersion = 0;
-    if (componentSection->FlashParameters.ReadClockFrequency == 
FLASH_FREQUENCY_20MHZ)      // Old descriptor
+    UINT8 descriptorVersion = 2; // Skylake+ by default
+    if (componentSection->FlashParameters.ReadClockFrequency == 
FLASH_FREQUENCY_20MHZ) // Old descriptor
         descriptorVersion = 1;
-    else if (componentSection->FlashParameters.ReadClockFrequency == 
FLASH_FREQUENCY_17MHZ) // Skylake+ descriptor
-        descriptorVersion = 2;
-    else {
-        msg(tr("parseIntelImage: unknown descriptor version with 
ReadClockFrequency 
%1h").hexarg(componentSection->FlashParameters.ReadClockFrequency));
-        return ERR_INVALID_FLASH_DESCRIPTOR;
-    }
 
     // ME region
     QByteArray me;
@@ -854,7 +848,7 @@
         }
         else if (volumeHeader->Revision == 2) {
             // Acquire alignment
-            alignment = (UINT32)pow(2.0, (int)(volumeHeader->Attributes & 
EFI_FVB2_ALIGNMENT) >> 16);
+            alignment = (UINT32)(1UL << ((volumeHeader->Attributes & 
EFI_FVB2_ALIGNMENT) >> 16));
 
             // Check alignment
             if (volumeOffset % alignment)
@@ -877,9 +871,8 @@
         if (msgUnknownRevision)
             msg(tr("parseBios: unknown volume revision 
%1").arg(volumeHeader->Revision), index);
         if (msgSizeMismach)
-            msg(tr("parseBios: volume size stored in header %1h (%2) differs 
from calculated using block map %3h (%4)")
-            .hexarg(volumeSize).arg(volumeSize)
-            .hexarg(bmVolumeSize).arg(bmVolumeSize),
+            msg(tr("parseBios: volume size stored in header %1h differs from 
calculated using block map %2h")
+            .hexarg(volumeSize).arg(bmVolumeSize),
             index);
 
         // Go to next volume
@@ -983,15 +976,16 @@
     else
         headerSize = volumeHeader->HeaderLength;
 
-    // Sanity check after some new crazy MSI images
+    // Sanity check after some crazy MSI images
     headerSize = ALIGN8(headerSize);
 
-    // Check for volume structure to be known
-    bool volumeIsUnknown = true;
-
-    // Check for FFS v2 volume
-    if (FFSv2Volumes.contains(QByteArray::fromRawData((const 
char*)volumeHeader->FileSystemGuid.Data, sizeof(EFI_GUID)))) {
-        volumeIsUnknown = false;
+    // Check for FFS v2/v3 volume
+       UINT8 subtype = Subtypes::UnknownVolume;
+    if (FFSv2Volumes.contains(QByteArray::fromRawData((const 
char*)volumeHeader->FileSystemGuid.Data, sizeof(EFI_GUID)))){
+               subtype = Subtypes::Ffs2Volume;
+       }
+       else if (FFSv3Volumes.contains(QByteArray::fromRawData((const 
char*)volumeHeader->FileSystemGuid.Data, sizeof(EFI_GUID)))) {
+        subtype = Subtypes::Ffs3Volume;
     }
 
     // Check attributes
@@ -1063,10 +1057,10 @@
     // Add tree item
     QByteArray  header = volume.left(headerSize);
     QByteArray  body = volume.mid(headerSize, volumeSize - headerSize);
-    index = model->addItem(Types::Volume, volumeIsUnknown ? 
Subtypes::UnknownVolume : Subtypes::Ffs2Volume, COMPRESSION_ALGORITHM_NONE, 
name, text, info, header, body, parent, mode);
+    index = model->addItem(Types::Volume, subtype, COMPRESSION_ALGORITHM_NONE, 
name, text, info, header, body, parent, mode);
 
     // Show messages
-    if (volumeIsUnknown) {
+    if (subtype == Subtypes::UnknownVolume) {
         msg(tr("parseVolume: unknown file system 
%1").arg(guidToQString(volumeHeader->FileSystemGuid)), index);
         // Do not parse unknown volumes
         return ERR_SUCCESS;
@@ -1100,19 +1094,42 @@
             break;
         }
 
-        result = getFileSize(volume, fileOffset, fileSize);
-        if (result)
-            return result;
+        QByteArray tempFile = volume.mid(fileOffset, 
sizeof(EFI_FFS_FILE_HEADER));
+        const EFI_FFS_FILE_HEADER* tempFileHeader = (const 
EFI_FFS_FILE_HEADER*)tempFile.constData();
+        UINT32 fileHeaderSize = sizeof(EFI_FFS_FILE_HEADER);
+        fileSize = uint24ToUint32(tempFileHeader->Size);
+        if (volumeHeader->Revision > 1 && (tempFileHeader->Attributes & 
FFS_ATTRIB_LARGE_FILE)) {
+            // Check if it's possibly the latest file in the volume
+            if (volumeSize - fileOffset < sizeof(EFI_FFS_FILE_HEADER2)) {
+                // No files are possible after this point
+                // All the rest is either free space or non-UEFI data
+                QByteArray rest = volume.right(volumeSize - fileOffset);
+                if (rest.count(empty) == rest.size()) { // It's a free space
+                    model->addItem(Types::FreeSpace, 0, 
COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h 
(%2)").hexarg(rest.size()).arg(rest.size()), QByteArray(), rest, index);
+                }
+                else { //It's non-UEFI data
+                    QModelIndex dataIndex = model->addItem(Types::Padding, 
Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", 
tr("Full size: %1h (%2)").hexarg(rest.size()).arg(rest.size()), QByteArray(), 
rest, index);
+                    msg(tr("parseVolume: non-UEFI data found in volume's free 
space"), dataIndex);
+                }
+                // Exit from loop
+                break;
+            }
+
+            fileHeaderSize = sizeof(EFI_FFS_FILE_HEADER2);
+            tempFile = volume.mid(fileOffset, sizeof(EFI_FFS_FILE_HEADER2));
+            const EFI_FFS_FILE_HEADER2* tempFileHeader2 = (const 
EFI_FFS_FILE_HEADER2*)tempFile.constData();
+            fileSize = (UINT32)tempFileHeader2->ExtendedSize;
+        }
 
-        // Check file size to be at least size of EFI_FFS_FILE_HEADER
-        if (fileSize < sizeof(EFI_FFS_FILE_HEADER)) {
+        // Check file size to be at least size of the header
+        if (fileSize < fileHeaderSize) {
             msg(tr("parseVolume: volume has FFS file with invalid size"), 
index);
             return ERR_INVALID_FILE;
         }
-
+       
         QByteArray file = volume.mid(fileOffset, fileSize);
-        QByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER));
-
+        QByteArray header = file.left(fileHeaderSize);
+        
         // If we are at empty space in the end of volume
         if (header.count(empty) == header.size()) {
             // Check free space to be actually free
@@ -1152,8 +1169,11 @@
         // Check file alignment
         const EFI_FFS_FILE_HEADER* fileHeader = (const 
EFI_FFS_FILE_HEADER*)header.constData();
         UINT8 alignmentPower = ffsAlignmentTable[(fileHeader->Attributes & 
FFS_ATTRIB_DATA_ALIGNMENT) >> 3];
-        UINT32 alignment = (UINT32)pow(2.0, alignmentPower);
-        if ((fileOffset + sizeof(EFI_FFS_FILE_HEADER)) % alignment)
+        if (volumeHeader->Revision > 1 && (fileHeader->Attributes & 
FFS_ATTRIB_DATA_ALIGNMENT2))
+            alignmentPower = ffsAlignment2Table[(fileHeader->Attributes & 
FFS_ATTRIB_DATA_ALIGNMENT) >> 3];
+
+        UINT32 alignment = (UINT32)(1UL << alignmentPower);
+        if ((fileOffset + fileHeaderSize) % alignment)
             msgUnalignedFile = true;
 
         // Check file GUID
@@ -1165,7 +1185,7 @@
 
         // Parse file
         QModelIndex fileIndex;
-        result = parseFile(file, fileIndex, empty == '\xFF' ? 
ERASE_POLARITY_TRUE : ERASE_POLARITY_FALSE, index);
+        result = parseFile(file, fileIndex, volumeHeader->Revision, empty == 
'\xFF' ? ERASE_POLARITY_TRUE : ERASE_POLARITY_FALSE, index);
         if (result && result != ERR_VOLUMES_NOT_FOUND && result != 
ERR_INVALID_VOLUME)
             msg(tr("parseVolume: FFS file parsing failed with error 
\"%1\"").arg(errorMessage(result)), index);
 
@@ -1183,16 +1203,7 @@
     return ERR_SUCCESS;
 }
 
-UINT8 FfsEngine::getFileSize(const QByteArray & volume, const UINT32 
fileOffset, UINT32 & fileSize)
-{
-    if ((UINT32)volume.size() < fileOffset + sizeof(EFI_FFS_FILE_HEADER))
-        return ERR_INVALID_VOLUME;
-    const EFI_FFS_FILE_HEADER* fileHeader = (const 
EFI_FFS_FILE_HEADER*)(volume.constData() + fileOffset);
-    fileSize = uint24ToUint32(fileHeader->Size);
-    return ERR_SUCCESS;
-}
-
-UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const 
UINT8 erasePolarity, const QModelIndex & parent, const UINT8 mode)
+UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const 
UINT8 revision, const UINT8 erasePolarity, const QModelIndex & parent, const 
UINT8 mode)
 {
     bool msgInvalidHeaderChecksum = false;
     bool msgInvalidDataChecksum = false;
@@ -1200,43 +1211,32 @@
     bool msgInvalidType = false;
 
     // Populate file header
+    if ((UINT32)file.size() < sizeof(EFI_FFS_FILE_HEADER))
+        return ERR_INVALID_FILE;
     const EFI_FFS_FILE_HEADER* fileHeader = (const 
EFI_FFS_FILE_HEADER*)file.constData();
 
-    // Check file state
     // Construct empty byte for this file
     char empty = erasePolarity ? '\xFF' : '\x00';
 
-    // Check header checksum
+    // Get file header
     QByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER));
-    QByteArray tempHeader = header;
-    EFI_FFS_FILE_HEADER* tempFileHeader = 
(EFI_FFS_FILE_HEADER*)(tempHeader.data());
-    tempFileHeader->IntegrityCheck.Checksum.Header = 0;
-    tempFileHeader->IntegrityCheck.Checksum.File = 0;
-    UINT8 calculated = calculateChecksum8((const UINT8*)tempFileHeader, 
sizeof(EFI_FFS_FILE_HEADER) - 1);
-    if (fileHeader->IntegrityCheck.Checksum.Header != calculated)
-        msgInvalidHeaderChecksum = true;
-
-    // Check data checksum
-    // Data checksum must be calculated
-    if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM) {
-        UINT32 bufferSize = file.size() - sizeof(EFI_FFS_FILE_HEADER);
-        // Exclude file tail from data checksum calculation
-        if (fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT)
-            bufferSize -= sizeof(UINT16);
-        calculated = calculateChecksum8((const UINT8*)(file.constData() + 
sizeof(EFI_FFS_FILE_HEADER)), bufferSize);
-        if (fileHeader->IntegrityCheck.Checksum.File != calculated)
-            msgInvalidDataChecksum = true;
+    if (revision > 1 && (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) {
+        if ((UINT32)file.size() < sizeof(EFI_FFS_FILE_HEADER2))
+            return ERR_INVALID_FILE;
+        header = file.left(sizeof(EFI_FFS_FILE_HEADER2));
     }
-    // Data checksum must be one of predefined values
-    else if (fileHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM && 
fileHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM2)
-        msgInvalidDataChecksum = true;
+
+    // Check header checksum
+    UINT8 calculatedHeader = 0x100 - (calculateSum8((const 
UINT8*)header.constData(), header.size()) - 
fileHeader->IntegrityCheck.Checksum.Header - 
fileHeader->IntegrityCheck.Checksum.File - fileHeader->State);
+    if (fileHeader->IntegrityCheck.Checksum.Header != calculatedHeader)
+        msgInvalidHeaderChecksum = true;
 
     // Get file body
-    QByteArray body = file.right(file.size() - sizeof(EFI_FFS_FILE_HEADER));
+    QByteArray body = file.mid(header.size());
+
     // Check for file tail presence
     QByteArray tail;
-    if (fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT)
-    {
+    if (revision == 1 && fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
         //Check file tail;
         tail = body.right(sizeof(UINT16));
         UINT16 tailValue = *(UINT16*)tail.constData();
@@ -1247,48 +1247,51 @@
         body = body.left(body.size() - sizeof(UINT16));
     }
 
+    // Check data checksum
+    // Data checksum must be calculated
+    UINT8 calculatedData = 0;
+    if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM) {
+        calculatedData = calculateChecksum8((const UINT8*)body.constData(), 
body.size());
+    }
+    // Data checksum must be one of predefined values
+    else if (revision == 1) {
+        calculatedData = FFS_FIXED_CHECKSUM;
+    }
+    else {
+        calculatedData = FFS_FIXED_CHECKSUM2;
+    }
+
+    if (fileHeader->IntegrityCheck.Checksum.File != calculatedData)
+        msgInvalidDataChecksum = true;
+
     // Parse current file by default
-    bool parseCurrentFile = true;
+    bool parseCurrentFile = false;
     bool parseAsBios = false;
 
     // Check file type
-    switch (fileHeader->Type)
-    {
+    switch (fileHeader->Type) {
     case EFI_FV_FILETYPE_ALL:
-        parseAsBios = true;
-        break;
     case EFI_FV_FILETYPE_RAW:
         parseAsBios = true;
-        break;
     case EFI_FV_FILETYPE_FREEFORM:
-        break;
     case EFI_FV_FILETYPE_SECURITY_CORE:
-        break;
     case EFI_FV_FILETYPE_PEI_CORE:
-        break;
     case EFI_FV_FILETYPE_DXE_CORE:
-        break;
     case EFI_FV_FILETYPE_PEIM:
-        break;
     case EFI_FV_FILETYPE_DRIVER:
-        break;
     case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
-        break;
     case EFI_FV_FILETYPE_APPLICATION:
-        break;
     case EFI_FV_FILETYPE_SMM:
-        break;
     case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:
-        break;
     case EFI_FV_FILETYPE_COMBINED_SMM_DXE:
-        break;
     case EFI_FV_FILETYPE_SMM_CORE:
-        break;
+       case EFI_FV_FILETYPE_SMM_STANDALONE:
+    case EFI_FV_FILETYPE_SMM_CORE_STANDALONE:
     case EFI_FV_FILETYPE_PAD:
+        parseCurrentFile = true;
         break;
     default:
         msgInvalidType = true;
-        parseCurrentFile = false;
     };
 
     // Check for empty file
@@ -1310,25 +1313,27 @@
     else
         name = parseAsNonEmptyPadFile ? tr("Non-empty pad-file") : 
tr("Pad-file");
 
-    info = tr("File GUID: %1\nType: %2h\nAttributes: %3h\nFull size: %4h 
(%5)\nHeader size: %6h (%7)\nBody size: %8h (%9)\nState: %10h")
+    info = tr("File GUID: %1\nType: %2h\nAttributes: %3h\nFull size: %4h 
(%5)\nHeader size: %6h (%7)\nBody size: %8h (%9)\nState: %10h\nHeader checksum: 
%11h\nData checksum: %12h")
         .arg(guidToQString(fileHeader->Name))
         .hexarg2(fileHeader->Type, 2)
         .hexarg2(fileHeader->Attributes, 2)
         .hexarg(header.size() + body.size() + tail.size()).arg(header.size() + 
body.size() + tail.size())
         .hexarg(header.size()).arg(header.size())
         .hexarg(body.size()).arg(body.size())
-        .hexarg2(fileHeader->State, 2);
+        .hexarg2(fileHeader->State, 2)
+        .hexarg2(fileHeader->IntegrityCheck.Checksum.Header, 2)
+        .hexarg2(fileHeader->IntegrityCheck.Checksum.File, 2);
 
     // Add tree item
     index = model->addItem(Types::File, fileHeader->Type, 
COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
 
     // Show messages
     if (msgInvalidHeaderChecksum)
-        msg(tr("parseFile: invalid header checksum"), index);
+        msg(tr("parseFile: invalid header checksum %1h, should be 
%2h").hexarg2(fileHeader->IntegrityCheck.Checksum.Header, 
2).hexarg2(calculatedHeader, 2), index);
     if (msgInvalidDataChecksum)
-        msg(tr("parseFile: invalid data checksum"), index);
+        msg(tr("parseFile: invalid data checksum %1h, should be 
%2h").hexarg2(fileHeader->IntegrityCheck.Checksum.File, 
2).hexarg2(calculatedData, 2), index);
     if (msgInvalidTailValue)
-        msg(tr("parseFile: invalid tail value"), index);
+        msg(tr("parseFile: invalid tail value 
%1h").hexarg(*(UINT16*)tail.data()), index);
     if (msgInvalidType)
         msg(tr("parseFile: unknown file type %1h").arg(fileHeader->Type, 2), 
index);
 
@@ -1382,8 +1387,18 @@
 {
     if ((UINT32)file.size() < sectionOffset + 
sizeof(EFI_COMMON_SECTION_HEADER))
         return ERR_INVALID_FILE;
+       
     const EFI_COMMON_SECTION_HEADER* sectionHeader = (const 
EFI_COMMON_SECTION_HEADER*)(file.constData() + sectionOffset);
     sectionSize = uint24ToUint32(sectionHeader->Size);
+    // This may introduce a very rare error with a non-extended section of 
size equal to 0xFFFFFF
+       if (sectionSize != 0xFFFFFF)
+        return ERR_SUCCESS;
+ 
+    if ((UINT32)file.size() < sectionOffset + 
sizeof(EFI_COMMON_SECTION_HEADER2))
+        return ERR_INVALID_FILE;
+
+    const EFI_COMMON_SECTION_HEADER2* sectionHeader2 = (const 
EFI_COMMON_SECTION_HEADER2*)(file.constData() + sectionOffset);
+    sectionSize = sectionHeader2->ExtendedSize;          
     return ERR_SUCCESS;
 }
 
@@ -1536,7 +1551,7 @@
     QString info;
     QByteArray header;
     QByteArray body;
-    UINT32 headerSize;
+    UINT32 headerSize = sizeOfSectionHeader(sectionHeader);
     UINT8 result;
 
     switch (sectionHeader->Type) {
@@ -1547,8 +1562,8 @@
         QByteArray decompressed;
         UINT8 algorithm;
         const EFI_COMPRESSION_SECTION* compressedSectionHeader = (const 
EFI_COMPRESSION_SECTION*)sectionHeader;
-        header = section.left(sizeof(EFI_COMPRESSION_SECTION));
-        body = section.mid(sizeof(EFI_COMPRESSION_SECTION));
+        header = section.left(headerSize);
+        body = section.mid(headerSize);
         algorithm = COMPRESSION_ALGORITHM_UNKNOWN;
         // Decompress section
         result = decompress(body, compressedSectionHeader->CompressionType, 
decompressed, &algorithm);
@@ -1588,12 +1603,10 @@
         bool msgUnknownSignature = false;
         bool msgUnknownUefiGuidSignature = false;
 
-        const EFI_GUID_DEFINED_SECTION* guidDefinedSectionHeader;
-        header = section.left(sizeof(EFI_GUID_DEFINED_SECTION));
-        guidDefinedSectionHeader = (const 
EFI_GUID_DEFINED_SECTION*)(header.constData());
-        header = section.left(guidDefinedSectionHeader->DataOffset);
-        guidDefinedSectionHeader = (const 
EFI_GUID_DEFINED_SECTION*)(header.constData());
-        body = section.mid(guidDefinedSectionHeader->DataOffset);
+        header = section.left(headerSize);
+        body = section.mid(headerSize);
+ 
+        const EFI_GUID_DEFINED_SECTION* guidDefinedSectionHeader = (const 
EFI_GUID_DEFINED_SECTION*)(header.constData());
         QByteArray processed = body;
 
         // Get info
@@ -1670,7 +1683,7 @@
                     }
                 }
                 else if (certificateHeader->CertificateType == 
WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
-                    info += tr("\nSignature type: PCKS7");
+                    info += tr("\nSignature type: PKCS7");
                     // TODO: show signature info in Information panel
                 }
                 else {
@@ -1748,8 +1761,8 @@
 
     case EFI_SECTION_DISPOSABLE:
     {
-        header = section.left(sizeof(EFI_DISPOSABLE_SECTION));
-        body = section.mid(sizeof(EFI_DISPOSABLE_SECTION));
+        header = section.left(headerSize);
+        body = section.mid(headerSize);
 
         // Get info
         info = tr("Type: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody 
size: %6h (%7)")
@@ -1772,7 +1785,6 @@
     case EFI_SECTION_PEI_DEPEX:
     case EFI_SECTION_SMM_DEPEX: {
         bool msgDepexParseFailed = false;
-        headerSize = sizeOfSectionHeader(sectionHeader);
         header = section.left(headerSize);
         body = section.mid(headerSize);
 
@@ -1800,7 +1812,6 @@
     } break;
 
     case EFI_SECTION_TE: {
-        headerSize = sizeOfSectionHeader(sectionHeader);
         header = section.left(headerSize);
         body = section.mid(headerSize);
 
@@ -1814,7 +1825,11 @@
         // Get TE info
         bool msgInvalidSignature = false;
         const EFI_IMAGE_TE_HEADER* teHeader = (const 
EFI_IMAGE_TE_HEADER*)body.constData();
-        UINT32 teFixup = teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER);
+        
+        // Most EFI images today include teFixup in ImageBase value,
+        // which doesn't follow the UEFI spec, but is so popular that
+        // only a few images out of thousands are different
+        UINT32 teFixup = 0; //teHeader->StrippedSize - 
sizeof(EFI_IMAGE_TE_HEADER);
         if (teHeader->Signature != EFI_IMAGE_TE_SIGNATURE) {
             info += tr("\nSignature: %1h, 
invalid").hexarg2(teHeader->Signature, 4);
             msgInvalidSignature = true;
@@ -1851,7 +1866,6 @@
 
     case EFI_SECTION_PE32:
     case EFI_SECTION_PIC: {
-        headerSize = sizeOfSectionHeader(sectionHeader);
         header = section.left(headerSize);
         body = section.mid(headerSize);
 
@@ -1947,7 +1961,6 @@
     } break;
 
     case EFI_SECTION_COMPATIBILITY16: {
-        headerSize = sizeOfSectionHeader(sectionHeader);
         header = section.left(headerSize);
         body = section.mid(headerSize);
 
@@ -1963,8 +1976,8 @@
     } break;
 
     case EFI_SECTION_FREEFORM_SUBTYPE_GUID: {
-        header = section.left(sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION));
-        body = section.mid(sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION));
+        header = section.left(headerSize);
+        body = section.mid(headerSize);
 
         const EFI_FREEFORM_SUBTYPE_GUID_SECTION* fsgHeader = (const 
EFI_FREEFORM_SUBTYPE_GUID_SECTION*)sectionHeader;
         // Get info
@@ -1983,8 +1996,8 @@
     } break;
 
     case EFI_SECTION_VERSION: {
-        header = section.left(sizeof(EFI_VERSION_SECTION));
-        body = section.mid(sizeof(EFI_VERSION_SECTION));
+        header = section.left(headerSize);
+        body = section.mid(headerSize);
 
         const EFI_VERSION_SECTION* versionHeader = (const 
EFI_VERSION_SECTION*)sectionHeader;
 
@@ -2002,8 +2015,8 @@
     } break;
 
     case EFI_SECTION_USER_INTERFACE: {
-        header = section.left(sizeof(EFI_USER_INTERFACE_SECTION));
-        body = section.mid(sizeof(EFI_USER_INTERFACE_SECTION));
+        header = section.left(headerSize);
+        body = section.mid(headerSize);
         QString text = QString::fromUtf16((const ushort*)body.constData());
 
         // Get info
@@ -2022,8 +2035,8 @@
     } break;
 
     case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: {
-        header = section.left(sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION));
-        body = section.mid(sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION));
+        header = section.left(headerSize);
+        body = section.mid(headerSize);
 
         // Get info
         info = tr("Type: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody 
size: %6h (%7)")
@@ -2045,8 +2058,8 @@
 
     case EFI_SECTION_RAW: {
         bool parsed = false;
-        header = section.left(sizeof(EFI_RAW_SECTION));
-        body = section.mid(sizeof(EFI_RAW_SECTION));
+        header = section.left(headerSize);
+        body = section.mid(headerSize);
 
         // Get info
         info = tr("Type: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody 
size: %6h (%7)")
@@ -2100,8 +2113,8 @@
 
     case SCT_SECTION_POSTCODE:
     case INSYDE_SECTION_POSTCODE: {
-        header = section.left(sizeof(POSTCODE_SECTION));
-        body = section.mid(sizeof(POSTCODE_SECTION));
+        header = section.left(headerSize);
+        body = section.mid(headerSize);
 
         const POSTCODE_SECTION* postcodeHeader = (const 
POSTCODE_SECTION*)sectionHeader;
 
@@ -2118,8 +2131,8 @@
     } break;
 
     default:
-        header = section.left(sizeof(EFI_COMMON_SECTION_HEADER));
-        body = section.mid(sizeof(EFI_COMMON_SECTION_HEADER));
+        header = section.left(headerSize);
+        body = section.mid(headerSize);
         // Get info
         info = tr("Type: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody 
size: %6h (%7)")
             .hexarg2(sectionHeader->Type, 2)
@@ -2219,28 +2232,51 @@
         if (header.size() != sizeof(EFI_FFS_FILE_HEADER))
             return ERR_INVALID_FILE;
 
-        QByteArray newHeader = header;
-        QByteArray newBody = body;
-        EFI_FFS_FILE_HEADER* fileHeader = 
(EFI_FFS_FILE_HEADER*)newHeader.data();
+        QByteArray newObject = header + body;
+        EFI_FFS_FILE_HEADER* fileHeader = 
(EFI_FFS_FILE_HEADER*)newObject.data();
+
+        // Determine correct file header size
+        bool largeFile = false;
+        UINT32 headerSize = sizeof(EFI_FFS_FILE_HEADER);
+        if (revision > 1 && (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) {
+            largeFile = true;
+            headerSize = sizeof(EFI_FFS_FILE_HEADER2);
+        }
+
+        QByteArray newHeader = newObject.left(headerSize);
+        QByteArray newBody = newObject.mid(headerSize);
 
         // Check if the file has a tail
-        UINT8 tailSize = fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT ? 
sizeof(UINT16) : 0;
+        UINT8 tailSize = (revision == 1 && (fileHeader->Attributes & 
FFS_ATTRIB_TAIL_PRESENT)) ? sizeof(UINT16) : 0;
         if (tailSize) {
             // Remove the tail, it will then be added back for revision 1 
volumes
             newBody = newBody.left(newBody.size() - tailSize);
-            // Remove the attribute for rev2+ volumes
-            if (revision != 1) {
-                fileHeader->Attributes &= ~(FFS_ATTRIB_TAIL_PRESENT);
-            }
         }
 
         // Correct file size
-        uint32ToUint24(sizeof(EFI_FFS_FILE_HEADER) + newBody.size() + 
tailSize, fileHeader->Size);
+        if (!largeFile) {
+            if (newBody.size() >= 0xFFFFFF) {
+                return ERR_INVALID_FILE;
+            }
+
+            uint32ToUint24(headerSize + newBody.size() + tailSize, 
fileHeader->Size);
+        }
+        else {
+            uint32ToUint24(0xFFFFFF, fileHeader->Size);
+            EFI_FFS_FILE_HEADER2* fileHeader2 = 
(EFI_FFS_FILE_HEADER2*)newHeader.data();
+            fileHeader2->ExtendedSize = headerSize + newBody.size() + tailSize;
+        }
+
+        // Set file state
+        UINT8 state = EFI_FILE_DATA_VALID | EFI_FILE_HEADER_VALID | 
EFI_FILE_HEADER_CONSTRUCTION;
+        if (erasePolarity)
+            state = ~state;
+        fileHeader->State = state;
 
         // Recalculate header checksum
         fileHeader->IntegrityCheck.Checksum.Header = 0;
         fileHeader->IntegrityCheck.Checksum.File = 0;
-        fileHeader->IntegrityCheck.Checksum.Header = calculateChecksum8((const 
UINT8*)fileHeader, sizeof(EFI_FFS_FILE_HEADER) - 1);
+        fileHeader->IntegrityCheck.Checksum.Header = 0x100 - 
(calculateSum8((const UINT8*)newHeader.constData(), headerSize) - 
fileHeader->State);
 
         // Recalculate data checksum, if needed
         if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM)
@@ -2254,23 +2290,17 @@
         created.append(newBody);
 
         // Append tail, if needed
-        if (revision ==1 && tailSize) {
+        if (revision == 1 && tailSize) {
             UINT8 ht = ~fileHeader->IntegrityCheck.Checksum.Header;
             UINT8 ft = ~fileHeader->IntegrityCheck.Checksum.File;
             created.append(ht).append(ft);
         }
 
-        // Set file state
-        UINT8 state = EFI_FILE_DATA_VALID | EFI_FILE_HEADER_VALID | 
EFI_FILE_HEADER_CONSTRUCTION;
-        if (erasePolarity)
-            state = ~state;
-        fileHeader->State = state;
-
         // Prepend header
         created.prepend(newHeader);
 
         // Parse file
-        result = parseFile(created, fileIndex, erasePolarity ? 
ERASE_POLARITY_TRUE : ERASE_POLARITY_FALSE, index, mode);
+        result = parseFile(created, fileIndex, revision, erasePolarity ? 
ERASE_POLARITY_TRUE : ERASE_POLARITY_FALSE, index, mode);
         if (result && result != ERR_VOLUMES_NOT_FOUND  && result != 
ERR_INVALID_VOLUME)
             return result;
 
@@ -2284,12 +2314,17 @@
         if (model->type(parent) != Types::File && model->type(parent) != 
Types::Section)
             return ERR_INVALID_SECTION;
 
-        if (header.size() < (int) sizeof(EFI_COMMON_SECTION_HEADER))
+        if ((UINT32)header.size() < sizeof(EFI_COMMON_SECTION_HEADER))
             return ERR_INVALID_SECTION;
 
         QByteArray newHeader = header;
         EFI_COMMON_SECTION_HEADER* commonHeader = 
(EFI_COMMON_SECTION_HEADER*)newHeader.data();
 
+        if (uint24ToUint32(commonHeader->Size) == EFI_SECTION2_IS_USED) {
+            msg(tr("create: creation of large sections not supported yet"), 
index);
+            return ERR_NOT_IMPLEMENTED;
+        }
+
         switch (commonHeader->Type)
         {
         case EFI_SECTION_COMPRESSION: {
@@ -2428,17 +2463,20 @@
     }
     else if (model->type(parent) == Types::File) {
         type = Types::Section;
-        const EFI_COMMON_SECTION_HEADER* commonHeader = 
(EFI_COMMON_SECTION_HEADER*)object.constData();
+        const EFI_COMMON_SECTION_HEADER* commonHeader = (const 
EFI_COMMON_SECTION_HEADER*)object.constData();
         headerSize = sizeOfSectionHeader(commonHeader);
     }
     else if (model->type(parent) == Types::Section) {
         type = Types::Section;
-        const EFI_COMMON_SECTION_HEADER* commonHeader = 
(EFI_COMMON_SECTION_HEADER*)object.constData();
+        const EFI_COMMON_SECTION_HEADER* commonHeader = (const 
EFI_COMMON_SECTION_HEADER*)object.constData();
         headerSize = sizeOfSectionHeader(commonHeader);
     }
     else
         return ERR_NOT_IMPLEMENTED;
 
+    if ((UINT32)object.size() < headerSize)
+        return ERR_BUFFER_TOO_SMALL;
+
     return create(index, type, object.left(headerSize), 
object.right(object.size() - headerSize), mode, Actions::Insert);
 }
 
@@ -2518,9 +2556,15 @@
         extracted.append(model->header(index));
         extracted.append(model->body(index));
         if (model->type(index) == Types::File) {
-            //!TODO: add volume revision check, maybe?
+            UINT8 revision = 2;
+            QModelIndex parent = model->parent(index);
+            if (parent.isValid() && model->type(parent) == Types::Volume) {
+                const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const 
EFI_FIRMWARE_VOLUME_HEADER*)model->header(parent).constData();
+                revision = volumeHeader->Revision;
+            }
+
             const EFI_FFS_FILE_HEADER* fileHeader = (const 
EFI_FFS_FILE_HEADER*)model->header(index).constData();
-            if (fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
+            if (revision == 1 && fileHeader->Attributes & 
FFS_ATTRIB_TAIL_PRESENT) {
                 UINT8 ht = ~fileHeader->IntegrityCheck.Checksum.Header;
                 UINT8 ft = ~fileHeader->IntegrityCheck.Checksum.File;
                 extracted.append(ht).append(ft);
@@ -2873,6 +2917,9 @@
     if (size < sizeof(EFI_FFS_FILE_HEADER) || erasePolarity == 
ERASE_POLARITY_UNKNOWN)
         return ERR_INVALID_PARAMETER;
 
+    if (size >= 0xFFFFFF) // TODO: large file support
+        return ERR_INVALID_PARAMETER;
+
     pad = QByteArray(size - guid.size(), erasePolarity == ERASE_POLARITY_TRUE 
? '\xFF' : '\x00');
     pad.prepend(guid);
     EFI_FFS_FILE_HEADER* header = (EFI_FFS_FILE_HEADER*)pad.data();
@@ -3265,6 +3312,7 @@
                         model->subtype(index.child(i, 0)) == 
EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER)){
                         QModelIndex peiFile = index.child(i, 0);
                         UINT32 sectionOffset = sizeof(EFI_FFS_FILE_HEADER);
+                        // BUGBUG: this parsing is bad and doesn't support 
large files, but it needs to be performed only for very old images with 
uncompressed DXE volumes, so whatever
                         // Search for PE32 or TE section
                         for (int j = 0; j < model->rowCount(peiFile); j++) {
                             if (model->subtype(peiFile.child(j, 0)) == 
EFI_SECTION_PE32 ||
@@ -3330,6 +3378,9 @@
                         continue;
 
                     EFI_FFS_FILE_HEADER* fileHeader = 
(EFI_FFS_FILE_HEADER*)file.data();
+                    UINT32 fileHeaderSize = sizeof(EFI_FFS_FILE_HEADER);
+                    if (volumeHeader->Revision > 1 && (fileHeader->Attributes 
& FFS_ATTRIB_LARGE_FILE))
+                        fileHeaderSize = sizeof(EFI_FFS_FILE_HEADER2);
 
                     // Pad file
                     if (fileHeader->Type == EFI_FV_FILETYPE_PAD) {
@@ -3354,11 +3405,9 @@
 
                     // Normal file
                     // Ensure correct alignment
-                    UINT8 alignmentPower;
-                    UINT32 alignmentBase;
-                    alignmentPower = ffsAlignmentTable[(fileHeader->Attributes 
& FFS_ATTRIB_DATA_ALIGNMENT) >> 3];
-                    alignment = (UINT32)pow(2.0, alignmentPower);
-                    alignmentBase = header.size() + offset + 
sizeof(EFI_FFS_FILE_HEADER);
+                    UINT8 alignmentPower = 
ffsAlignmentTable[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3];
+                    alignment = (UINT32)(1UL <<alignmentPower);
+                    UINT32 alignmentBase = header.size() + offset + 
fileHeaderSize;
                     if (alignmentBase % alignment) {
                         // File will be unaligned if added as is, so we must 
add pad file before it
                         // Determine pad file size
@@ -3496,18 +3545,21 @@
                     volumeSize = newSize;
                 }
             }
-
-            // Check new volume size
-            if ((UINT32)(header.size() + reconstructed.size()) > volumeSize)
-            {
-                msg(tr("reconstructVolume: volume grow failed"), index);
-                return ERR_INVALID_VOLUME;
-            }
         }
         // Use current volume body
-        else
+        else {
             reconstructed = model->body(index);
 
+            // BUGBUG: volume size may change during this operation for 
volumes withour files in them
+            // but such volumes are fairly rare
+        }
+
+        // Check new volume size
+        if ((UINT32)(header.size() + reconstructed.size()) != volumeSize) {
+            msg(tr("reconstructVolume: volume size can't be changed"), index);
+            return ERR_INVALID_VOLUME;
+        }
+
         // Reconstruction successful
         reconstructed = header.append(reconstructed);
 
@@ -3527,6 +3579,7 @@
                 volumeHeader->Checksum = calculateChecksum16((const 
UINT16*)volumeHeader, volumeHeader->HeaderLength);
             }
         }
+
         // Store new free space offset, if needed
         if (model->text(index).contains("AppleFSO ")) {
             // Get current CRC32 value from volume header
@@ -3577,7 +3630,7 @@
         model->action(index) == Actions::Rebuild) {
         QByteArray header = model->header(index);
         EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*)header.data();
-
+               
         // Check erase polarity
         if (erasePolarity == ERASE_POLARITY_UNKNOWN) {
             msg(tr("reconstructFile: unknown erase polarity"), index);
@@ -3585,9 +3638,9 @@
         }
 
         // Check file state
-        // Invert it first if erase polarity is true
+        // Check top reserved bit of file state to determine it's original 
erase polarity
         UINT8 state = fileHeader->State;
-        if (erasePolarity == ERASE_POLARITY_TRUE)
+        if (state & EFI_FILE_ERASE_POLARITY)
             state = ~state;
 
         // Order of this checks must be preserved
@@ -3635,6 +3688,10 @@
             // File contains sections
             else {
                 UINT32 offset = 0;
+                UINT32 headerSize = sizeof(EFI_FFS_FILE_HEADER);
+                if (revision > 1 && (fileHeader->Attributes & 
FFS_ATTRIB_LARGE_FILE)) {
+                    headerSize = sizeof(EFI_FFS_FILE_HEADER2);
+                }
 
                 for (int i = 0; i < model->rowCount(index); i++) {
                     // Align to 4 byte boundary
@@ -3646,8 +3703,22 @@
                     }
 
                     // Calculate section base
-                    UINT32 sectionBase = base ? base + 
sizeof(EFI_FFS_FILE_HEADER) + offset : 0;
-
+                    UINT32 sectionBase = base ? base + headerSize + offset : 0;
+                    UINT8 alignmentPower = 
ffsAlignmentTable[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3];
+                    UINT32 fileAlignment = (UINT32)(1UL << alignmentPower);
+                    UINT32 alignmentBase = base + headerSize;
+                    if (alignmentBase % fileAlignment) {
+                        // File will be unaligned if added as is, so we must 
add pad file before it
+                        // Determine pad file size
+                        UINT32 size = fileAlignment - (alignmentBase % 
fileAlignment);
+                        // Required padding is smaller then minimal pad file 
size
+                        while (size < sizeof(EFI_FFS_FILE_HEADER)) {
+                            size += fileAlignment;
+                        }
+                        // Adjust file base to incorporate pad file that will 
be added to align it
+                        sectionBase += size;
+                    }
+                    
                     // Reconstruct section
                     QByteArray section;
                     result = reconstructSection(index.child(i, 0), 
sectionBase, section);
@@ -3665,21 +3736,31 @@
                     offset += section.size();
                 }
             }
-
-            // Correct file size
-            UINT8 tailSize = (revision == 1 && (fileHeader->Attributes & 
FFS_ATTRIB_TAIL_PRESENT)) ? sizeof(UINT16) : 0;
-
-            uint32ToUint24(sizeof(EFI_FFS_FILE_HEADER) + reconstructed.size() 
+ tailSize, fileHeader->Size);
-
-            // Recalculate header checksum
-            fileHeader->IntegrityCheck.Checksum.Header = 0;
-            fileHeader->IntegrityCheck.Checksum.File = 0;
-            fileHeader->IntegrityCheck.Checksum.Header = 
calculateChecksum8((const UINT8*)fileHeader, sizeof(EFI_FFS_FILE_HEADER) - 1);
         }
         // Use current file body
         else
             reconstructed = model->body(index);
 
+        // Correct file size
+        UINT8 tailSize = (revision == 1 && (fileHeader->Attributes & 
FFS_ATTRIB_TAIL_PRESENT)) ? sizeof(UINT16) : 0;
+        if (revision > 1 && (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) {
+            uint32ToUint24(EFI_SECTION2_IS_USED, fileHeader->Size);
+            EFI_FFS_FILE_HEADER2* fileHeader2 = 
(EFI_FFS_FILE_HEADER2*)fileHeader;
+            fileHeader2->ExtendedSize = sizeof(EFI_FFS_FILE_HEADER2) + 
reconstructed.size() + tailSize;
+        }
+        else {
+            if (sizeof(EFI_FFS_FILE_HEADER) + reconstructed.size() + tailSize 
> 0xFFFFFF) {
+                msg(tr("reconstructFile: resulting file size is too big"), 
index);
+                return ERR_INVALID_FILE;
+            }
+            uint32ToUint24(sizeof(EFI_FFS_FILE_HEADER) + reconstructed.size() 
+ tailSize, fileHeader->Size);
+        }
+
+        // Recalculate header checksum
+        fileHeader->IntegrityCheck.Checksum.Header = 0;
+        fileHeader->IntegrityCheck.Checksum.File = 0;
+        fileHeader->IntegrityCheck.Checksum.Header = 0x100 - 
(calculateSum8((const UINT8*)header.constData(), header.size()) - 
fileHeader->State);
+
         // Recalculate data checksum, if needed
         if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM) {
             fileHeader->IntegrityCheck.Checksum.File = 
calculateChecksum8((const UINT8*)reconstructed.constData(), 
reconstructed.size());
@@ -3690,11 +3771,12 @@
             fileHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM2;
 
         // Append tail, if needed
-        if (fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
+        if (revision == 1 && fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) 
{
             UINT8 ht = ~fileHeader->IntegrityCheck.Checksum.Header;
             UINT8 ft = ~fileHeader->IntegrityCheck.Checksum.File;
             reconstructed.append(ht).append(ft);
         }
+
         // Set file state
         state = EFI_FILE_DATA_VALID | EFI_FILE_HEADER_VALID | 
EFI_FILE_HEADER_CONSTRUCTION;
         if (erasePolarity == ERASE_POLARITY_TRUE)
@@ -3732,6 +3814,10 @@
         model->action(index) == Actions::Rebase) {
         QByteArray header = model->header(index);
         EFI_COMMON_SECTION_HEADER* commonHeader = 
(EFI_COMMON_SECTION_HEADER*)header.data();
+        bool extended = false;
+        if (uint24ToUint32(commonHeader->Size) == 0xFFFFFF) {
+            extended = true;
+        }
 
         // Reconstruct section with children
         if (model->rowCount(index)) {
@@ -3830,28 +3916,44 @@
                     .arg(model->subtype(index)), index);
                 return ERR_INVALID_SECTION;
             }
-
-            // Correct section size
-            uint32ToUint24(header.size() + reconstructed.size(), 
commonHeader->Size);
         }
         // Leaf section
-        else
+        else {
             reconstructed = model->body(index);
+        }
+
+        // Correct section size
+        if (extended) {
+            EFI_COMMON_SECTION_HEADER2 * extHeader = 
(EFI_COMMON_SECTION_HEADER2*)commonHeader;
+            extHeader->ExtendedSize = header.size() + reconstructed.size();
+            uint32ToUint24(0xFFFFFF, commonHeader->Size);
+        }
+        else {
+            uint32ToUint24(header.size() + reconstructed.size(), 
commonHeader->Size);
+        }
 
         // Rebase PE32 or TE image, if needed
         if ((model->subtype(index) == EFI_SECTION_PE32 || 
model->subtype(index) == EFI_SECTION_TE) &&
             (model->subtype(index.parent()) == EFI_FV_FILETYPE_PEI_CORE ||
-            model->subtype(index.parent()) == EFI_FV_FILETYPE_PEIM ||
-            model->subtype(index.parent()) == 
EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER)) {
+                model->subtype(index.parent()) == EFI_FV_FILETYPE_PEIM ||
+                model->subtype(index.parent()) == 
EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER)) {
             UINT16 teFixup = 0;
-            //TODO: add proper handling
-            /*if (model->subtype(index) == EFI_SECTION_TE) {
-                const EFI_IMAGE_TE_HEADER* teHeader = (const 
EFI_IMAGE_TE_HEADER*)model->body(index).constData();
-                teFixup = teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER);
-            }*/
+
+            // Most EFI images today include teFixup in ImageBase value,
+            // which doesn't follow the UEFI spec, but is so popular that
+            // only a few images out of thousands are different
+
+            // There are some heuristics possible here to detect if an entry 
point is calculated correctly
+            // or needs a proper fixup, but new_engine already have them and 
it's better to work on proper
+            // builder for it than trying to fix this mess
+
+            //if (model->subtype(index) == EFI_SECTION_TE) {
+            //  const EFI_IMAGE_TE_HEADER* teHeader = (const 
EFI_IMAGE_TE_HEADER*)model->body(index).constData();
+            //  teFixup = teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER);
+            //
 
             if (base) {
-                result = rebase(reconstructed, base - teFixup + header.size());
+                result = rebase(reconstructed, base - teFixup + header.size(), 
index);
                 if (result) {
                     msg(tr("reconstructSection: executable section rebase 
failed"), index);
                     return result;
@@ -4147,7 +4249,7 @@
     return ERR_SUCCESS;
 }
 
-UINT8 FfsEngine::rebase(QByteArray &executable, const UINT32 base)
+UINT8 FfsEngine::rebase(QByteArray &executable, const UINT32 base, const 
QModelIndex & index)
 {
     UINT32 delta;       // Difference between old and new base addresses
     UINT32 relocOffset; // Offset of relocation region
@@ -4220,6 +4322,9 @@
         relocSize = 
teHeader->DataDirectory[EFI_IMAGE_TE_DIRECTORY_ENTRY_BASERELOC].Size;
         // Set new base
         teHeader->ImageBase = base;
+
+        // Warn the user about possible outcome of incorrect rebase of TE image
+        msg(tr("rebase: can't determine if TE image base is adjusted or not, 
rebased TE image may stop working"), index);
     }
     else
         return ERR_UNKNOWN_IMAGE_TYPE;
@@ -4249,6 +4354,12 @@
 
         // Run this relocation record
         while (Reloc < RelocEnd) {
+            if (*Reloc == 0x0000) {
+                // Skip last emtpy reloc entry
+                Reloc += 1;
+                continue;
+            }
+
             UINT32 RelocLocation = RelocBase->VirtualAddress - teFixup + 
(*Reloc & 0x0FFF);
             if ((UINT32)file.size() < RelocLocation)
                 return ERR_BAD_RELOCATION_ENTRY;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/UEFITool-20170506/ffsengine.h 
new/UEFITool-20180225/ffsengine.h
--- old/UEFITool-20170506/ffsengine.h   2017-05-07 02:24:47.000000000 +0200
+++ new/UEFITool-20180225/ffsengine.h   2018-02-26 00:40:14.000000000 +0100
@@ -70,7 +70,7 @@
     UINT8 parseEcRegion(const QByteArray & ec, QModelIndex & index, const 
QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND);
     UINT8 parseBios(const QByteArray & bios, const QModelIndex & parent = 
QModelIndex());
     UINT8 parseVolume(const QByteArray & volume, QModelIndex & index, const 
QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND);
-    UINT8 parseFile(const QByteArray & file, QModelIndex & index, const UINT8 
erasePolarity = ERASE_POLARITY_UNKNOWN, const QModelIndex & parent = 
QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND);
+    UINT8 parseFile(const QByteArray & file, QModelIndex & index, const UINT8 
revision = 2, const UINT8 erasePolarity = ERASE_POLARITY_UNKNOWN, const 
QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND);
     UINT8 parseSections(const QByteArray & body, const QModelIndex & parent = 
QModelIndex());
     UINT8 parseSection(const QByteArray & section, QModelIndex & index, const 
QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND);
 
@@ -84,7 +84,6 @@
     UINT8 reconstructIntelImage(const QModelIndex& index, QByteArray & 
reconstructed);
     UINT8 reconstructRegion(const QModelIndex& index, QByteArray & 
reconstructed, bool includeHeader = true);
     UINT8 reconstructPadding(const QModelIndex& index, QByteArray & 
reconstructed);
-    UINT8 reconstructBios(const QModelIndex& index, QByteArray & 
reconstructed);
     UINT8 reconstructVolume(const QModelIndex& index, QByteArray & 
reconstructed);
     UINT8 reconstructFile(const QModelIndex& index, const UINT8 revision, 
const UINT8 erasePolarity, const UINT32 base, QByteArray& reconstructed);
     UINT8 reconstructSection(const QModelIndex& index, const UINT32 base, 
QByteArray & reconstructed);
@@ -117,7 +116,6 @@
     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, UINT32 & bmVolumeSize);
-    UINT8 getFileSize(const QByteArray & volume, const UINT32 fileOffset, 
UINT32 & fileSize);
     UINT8 getSectionSize(const QByteArray & file, const UINT32 sectionOffset, 
UINT32 & sectionSize);
 
     // Reconstruction helpers
@@ -127,7 +125,7 @@
     // Rebase routines
     UINT8 getBase(const QByteArray& file, UINT32& base);
     UINT8 getEntryPoint(const QByteArray& file, UINT32 &entryPoint);
-    UINT8 rebase(QByteArray & executable, const UINT32 base);
+    UINT8 rebase(QByteArray & executable, const UINT32 base, const QModelIndex 
& index);
     void  rebasePeiFiles(const QModelIndex & index);
 
     // Patch routines
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/UEFITool-20170506/types.cpp 
new/UEFITool-20180225/types.cpp
--- old/UEFITool-20170506/types.cpp     2017-05-07 02:24:47.000000000 +0200
+++ new/UEFITool-20180225/types.cpp     2018-02-26 00:40:14.000000000 +0100
@@ -69,7 +69,7 @@
     case Types::Image:
         if (subtype == Subtypes::IntelImage)
             return QObject::tr("Intel");
-        else if (Subtypes::UefiImage)
+        else if (subtype == Subtypes::UefiImage)
             return QObject::tr("UEFI");
         else
             return QObject::tr("Unknown subtype");
@@ -153,4 +153,4 @@
     default:
         return QObject::tr("Unknown");
     }
-}
\ No newline at end of file
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/UEFITool-20170506/uefitool.cpp 
new/UEFITool-20180225/uefitool.cpp
--- old/UEFITool-20170506/uefitool.cpp  2017-05-07 02:24:47.000000000 +0200
+++ new/UEFITool-20180225/uefitool.cpp  2018-02-26 00:40:14.000000000 +0100
@@ -17,7 +17,7 @@
 UEFITool::UEFITool(QWidget *parent) :
 QMainWindow(parent),
 ui(new Ui::UEFITool),
-version(tr("0.21.5"))
+version(tr("0.22.4"))
 {
     clipboard = QApplication::clipboard();
 

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.hOQ5u9/_old  2018-03-09 10:46:28.474940565 +0100
+++ /var/tmp/diff_new_pack.hOQ5u9/_new  2018-03-09 10:46:28.474940565 +0100
@@ -1,4 +1,4 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/LongSoft/UEFITool.git</param>
-              <param 
name="changesrevision">5ba63418bde66681ae81b8f1ae890ab65d746752</param></service></servicedata>
\ No newline at end of file
+              <param 
name="changesrevision">60d6494841fd5258a222342f53b1f5554fbbaa37</param></service></servicedata>
\ No newline at end of file


Reply via email to