diff --git a/UEFITool/ffsops.cpp b/UEFITool/ffsops.cpp
index 82e7b18..c16c78a 100644
--- a/UEFITool/ffsops.cpp
+++ b/UEFITool/ffsops.cpp
@@ -44,7 +44,7 @@ STATUS FfsOperations::extract(const QModelIndex & index, QString & name, QByteAr
         return ERR_INVALID_PARAMETER;
 
     // Get data from parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(index);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(index);
 
     // Construct a name for extracted data
     QString itemName = model->name(index);
diff --git a/UEFITool/uefitool.cpp b/UEFITool/uefitool.cpp
index e6319c5..37b96df 100644
--- a/UEFITool/uefitool.cpp
+++ b/UEFITool/uefitool.cpp
@@ -17,7 +17,7 @@
 UEFITool::UEFITool(QWidget *parent) :
 QMainWindow(parent),
 ui(new Ui::UEFITool), 
-version(tr("0.30.0_alpha4"))
+version(tr("0.30.0_alpha5"))
 {
     clipboard = QApplication::clipboard();
 
@@ -26,6 +26,7 @@ version(tr("0.30.0_alpha4"))
     searchDialog = new SearchDialog(this);
     model = NULL;
     ffsParser = NULL;
+    fitParser = NULL;
     ffsFinder = NULL;
     ffsOps = NULL;
 
@@ -69,6 +70,7 @@ version(tr("0.30.0_alpha4"))
     ui->infoEdit->setFont(font);
     ui->parserMessagesListWidget->setFont(font);
     ui->finderMessagesListWidget->setFont(font);
+    ui->fitTableWidget->setFont(font);
     ui->structureTreeView->setFont(font);
     searchDialog->ui->guidEdit->setFont(font);
     searchDialog->ui->hexEdit->setFont(font);
@@ -84,6 +86,7 @@ UEFITool::~UEFITool()
 {
     delete ffsOps;
     delete ffsFinder;
+    delete fitParser;
     delete ffsParser;
     delete model;
     delete searchDialog;
@@ -95,6 +98,7 @@ void UEFITool::init()
     // Clear components
     ui->parserMessagesListWidget->clear();
     ui->finderMessagesListWidget->clear();
+    ui->fitTableWidget->clear();
     ui->infoEdit->clear();
 
     // Set window title
@@ -120,6 +124,10 @@ void UEFITool::init()
     if (ffsParser)
         delete ffsParser;
     ffsParser = new FfsParser(model);
+    // ... and fitParser
+    if (fitParser)
+        delete fitParser;
+    fitParser = new FitParser(model);
 
     // Connect
     connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
@@ -602,6 +610,12 @@ void UEFITool::openImageFile(QString path)
     else
         ui->statusBar->showMessage(tr("Opened: %1").arg(fileInfo.fileName()));
 
+    // Parse FIT
+    //!TODO: expand and chek errors
+    result = fitParser->parse(model->index(0, 0), ffsParser->getLastVtf());
+    if (!result)
+        showFitTable();
+
     // Enable search ...
     if (ffsFinder)
         delete ffsFinder;
@@ -789,3 +803,78 @@ void UEFITool::writeSettings()
     settings.setValue("tree/columnWidth2", ui->structureTreeView->columnWidth(2));
     settings.setValue("tree/columnWidth3", ui->structureTreeView->columnWidth(3));
 }
+
+void UEFITool::showFitTable()
+{
+    QVector<QPair<FIT_ENTRY, QString> > fitEntries = fitParser->getFitEntries();
+    if (fitEntries.isEmpty())
+        return;
+
+    // Set up the FIT table
+    ui->fitTableWidget->clear();
+    ui->fitTableWidget->setRowCount(fitEntries.length());
+    ui->fitTableWidget->setColumnCount(6);
+    //ui->fitTableWidget->verticalHeader()->setVisible(false);
+    ui->fitTableWidget->setHorizontalHeaderLabels(QStringList() << tr("Address") << tr("Size") << tr("Version") << tr("Type") << tr("Checksum") << tr("Remark"));
+    ui->fitTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
+    ui->fitTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
+    ui->fitTableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
+    ui->fitTableWidget->horizontalHeader()->setStretchLastSection(true);
+
+    // Add all data to the table widget
+    for (INT32 i = 0; i < fitEntries.length(); i++) {
+        FIT_ENTRY* entry = &(fitEntries[i].first);
+        if (i)
+            ui->fitTableWidget->setItem(i, 0, new QTableWidgetItem(tr("%1h").hexarg2(entry->Address, 16)));
+        else
+            ui->fitTableWidget->setItem(i, 0, new QTableWidgetItem(tr("_FIT_   ")));
+
+        ui->fitTableWidget->setItem(i, 1, new QTableWidgetItem(tr("%1h (%2)").hexarg2(entry->Size * 16, 8).arg(entry->Size * 16)));
+        ui->fitTableWidget->setItem(i, 2, new QTableWidgetItem(tr("%1h").hexarg2(entry->Version, 4)));
+
+        QString typeString;
+        switch (entry->Type & 0x7F) {
+        case FIT_TYPE_HEADER:
+            typeString.append(tr("Header"));
+            break;
+        case FIT_TYPE_MICROCODE:
+            typeString.append(tr("Microcode"));
+            break;
+        case FIT_TYPE_BIOS_AC_MODULE:
+            typeString.append(tr("BIOS ACM"));
+            break;
+        case FIT_TYPE_BIOS_INIT_MODULE:
+            typeString.append(tr("BIOS Init"));
+            break;
+        case FIT_TYPE_TPM_POLICY:
+            typeString.append(tr("TPM Policy"));
+            break;
+        case FIT_TYPE_BIOS_POLICY_DATA:
+            typeString.append(tr("BIOS Policy Data"));
+            break;
+        case FIT_TYPE_TXT_CONF_POLICY:
+            typeString.append(tr("TXT Configuration Policy"));
+            break;
+        case FIT_TYPE_AC_KEY_MANIFEST:
+            typeString.append(tr("BootGuard Key Manifest"));
+            break;
+        case FIT_TYPE_AC_BOOT_POLICY:
+            typeString.append(tr("BootGuard Boot Policy"));
+            break;
+        case FIT_TYPE_EMPTY:
+            typeString.append(tr("Empty"));
+            break;
+        default:
+            typeString.append(tr("Unknown"));
+        }
+
+        ui->fitTableWidget->setItem(i, 3, new QTableWidgetItem(typeString));
+        ui->fitTableWidget->setItem(i, 4, new QTableWidgetItem(tr("%1h").hexarg2(entry->Checksum, 2)));
+        ui->fitTableWidget->setItem(i, 5, new QTableWidgetItem(fitEntries[i].second));
+    }
+
+    ui->fitTableWidget->resizeColumnsToContents();
+    ui->fitTableWidget->resizeRowsToContents();
+    ui->messagesTabWidget->setCurrentIndex(2);
+
+}
\ No newline at end of file
diff --git a/UEFITool/uefitool.h b/UEFITool/uefitool.h
index e996b93..7dd7766 100644
--- a/UEFITool/uefitool.h
+++ b/UEFITool/uefitool.h
@@ -37,6 +37,7 @@
 #include "../common/utility.h"
 #include "../common/ffs.h"
 #include "../common/ffsparser.h"
+#include "../common/fitparser.h"
 #include "searchdialog.h"
 #include "messagelistitem.h"
 #include "ffsfinder.h"
@@ -97,6 +98,7 @@ private:
     Ui::UEFITool* ui;
     TreeModel* model;
     FfsParser* ffsParser;
+    FitParser* fitParser;
     FfsFinder* ffsFinder;
     FfsOperations* ffsOps;
     SearchDialog* searchDialog;
@@ -110,6 +112,7 @@ private:
     void readSettings();
     void showParserMessages();
     void showFinderMessages();
+    void showFitTable();
 };
 
 #endif
diff --git a/UEFITool/uefitool.pro b/UEFITool/uefitool.pro
index 659f416..067e83e 100644
--- a/UEFITool/uefitool.pro
+++ b/UEFITool/uefitool.pro
@@ -18,6 +18,7 @@ SOURCES += uefitool_main.cpp \
  ../common/utility.cpp \
  ../common/ffsbuilder.cpp \
  ../common/ffsparser.cpp \
+ ../common/fitparser.cpp \
  ../common/treeitem.cpp \
  ../common/treemodel.cpp \
  ../common/LZMA/LzmaCompress.c \
@@ -47,6 +48,7 @@ HEADERS += uefitool.h \
  ../common/parsingdata.h \
  ../common/ffsbuilder.h \
  ../common/ffsparser.h \
+ ../common/fitparser.h \
  ../common/treeitem.h \
  ../common/treemodel.h \
  ../common/LZMA/LzmaCompress.h \
diff --git a/UEFITool/uefitool.ui b/UEFITool/uefitool.ui
index 1343690..b1eb808 100644
--- a/UEFITool/uefitool.ui
+++ b/UEFITool/uefitool.ui
@@ -202,6 +202,31 @@
          </item>
         </layout>
        </widget>
+       <widget class="QWidget" name="fitTab">
+        <attribute name="title">
+         <string>FIT</string>
+        </attribute>
+        <layout class="QHBoxLayout" name="horizontalLayout_3">
+         <property name="spacing">
+          <number>0</number>
+         </property>
+         <property name="leftMargin">
+          <number>5</number>
+         </property>
+         <property name="topMargin">
+          <number>5</number>
+         </property>
+         <property name="rightMargin">
+          <number>5</number>
+         </property>
+         <property name="bottomMargin">
+          <number>5</number>
+         </property>
+         <item>
+          <widget class="QTableWidget" name="fitTableWidget"/>
+         </item>
+        </layout>
+       </widget>
       </widget>
      </widget>
     </item>
diff --git a/common/ffs.cpp b/common/ffs.cpp
index cd2cff4..2649b3b 100644
--- a/common/ffs.cpp
+++ b/common/ffs.cpp
@@ -30,36 +30,6 @@ const QVector<QByteArray> FFSv3Volumes =
 const UINT8 ffsAlignmentTable[] =
 { 0, 4, 7, 9, 10, 12, 15, 16 };
 
-UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize)
-{
-    if (!buffer)
-        return 0;
-
-    UINT8 counter = 0;
-
-    while (bufferSize--)
-        counter += buffer[bufferSize];
-
-    return (UINT8)(0x100 - counter);
-}
-
-UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize)
-{
-    if (!buffer)
-        return 0;
-
-    UINT16 counter = 0;
-    UINT32 index = 0;
-
-    bufferSize /= sizeof(UINT16);
-
-    for (; index < bufferSize; index++) {
-        counter = (UINT16)(counter + buffer[index]);
-    }
-
-    return (UINT16)(0x10000 - counter);
-}
-
 VOID uint32ToUint24(UINT32 size, UINT8* ffsSize)
 {
     ffsSize[2] = (UINT8)((size) >> 16);
diff --git a/common/ffs.h b/common/ffs.h
index 4bbec90..ef13e67 100644
--- a/common/ffs.h
+++ b/common/ffs.h
@@ -240,9 +240,6 @@ typedef struct _EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE {
     //UINT8 Data[];
 } EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE;
 
-// Volume header 16bit checksum calculation routine
-extern UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize);
-
 //*****************************************************************************
 // EFI FFS File
 //*****************************************************************************
@@ -341,8 +338,6 @@ const QByteArray EFI_FFS_PAD_FILE_GUID
 // FFS size conversion routines
 extern VOID uint32ToUint24(UINT32 size, UINT8* ffsSize);
 extern UINT32 uint24ToUint32(const UINT8* ffsSize);
-// FFS file 8bit checksum calculation routine
-extern UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize);
 
 //*****************************************************************************
 // EFI FFS File Section
diff --git a/common/ffsbuilder.cpp b/common/ffsbuilder.cpp
index 7d2a9eb..dc489f9 100644
--- a/common/ffsbuilder.cpp
+++ b/common/ffsbuilder.cpp
@@ -43,7 +43,7 @@ STATUS FfsBuilder::erase(const QModelIndex & index, QByteArray & erased)
     if (!index.isValid())
         return ERR_INVALID_PARAMETER;
 
-    PARSING_DATA pdata = parsingDataFromQByteArray(index);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(index);
     erased.fill(pdata.emptyByte);
     return ERR_SUCCESS;
 }
diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp
index c042302..465c865 100644
--- a/common/ffsparser.cpp
+++ b/common/ffsparser.cpp
@@ -85,7 +85,7 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
             .hexarg2(capsuleHeader->Flags, 8);
 
         // Construct parsing data
-        PARSING_DATA pdata = parsingDataFromQByteArray(QModelIndex());
+        PARSING_DATA pdata = parsingDataFromQModelIndex(QModelIndex());
         pdata.fixed = TRUE;
 
         // Add tree item
@@ -108,7 +108,7 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
             .hexarg2(capsuleHeader->CapsuleHeader.Flags, 8);
 
         // Construct parsing data
-        PARSING_DATA pdata = parsingDataFromQByteArray(QModelIndex());
+        PARSING_DATA pdata = parsingDataFromQModelIndex(QModelIndex());
         pdata.fixed = TRUE;
 
         // Add tree item
@@ -146,7 +146,7 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
         .hexarg(capsuleHeaderSize).hexarg(flashImage.size()).arg(flashImage.size());
 
     // Construct parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(index);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(index);
     pdata.fixed = TRUE;
     pdata.offset = capsuleHeaderSize;
 
@@ -160,7 +160,7 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
 
     // Check if the last VTF is found
     if (!lastVtf.isValid()) {
-        msg(tr("parseImageFile: not a single Volume Top File is found, physical memory addresses can't be calculated"), biosIndex);
+        msg(tr("parseImageFile: not a single Volume Top File is found, the image may be corrupted"), biosIndex);
     }
     else {
         return performSecondPass(biosIndex);
@@ -176,7 +176,7 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const QModelInd
         return EFI_INVALID_PARAMETER;
 
     // Get parent's parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(parent);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
 
     // Store the beginning of descriptor as descriptor base address
     const UINT8* descriptor = (const UINT8*)intelImage.constData();
@@ -412,7 +412,7 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const QModelInd
 
     // Check if the last VTF is found
     if (!lastVtf.isValid()) {
-        msg(tr("parseIntelImage: not a single Volume Top File is found, physical memory addresses can't be calculated"), index);
+        msg(tr("parseIntelImage: not a single Volume Top File is found, the image may be corrupted"), index);
     }
     else {
         return performSecondPass(index);
@@ -428,7 +428,7 @@ STATUS FfsParser::parseGbeRegion(const QByteArray & gbe, const UINT32 parentOffs
         return ERR_EMPTY_REGION;
 
     // Get parent's parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(parent);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
 
     // Get info
     QString name = tr("GbE region");
@@ -463,7 +463,7 @@ STATUS FfsParser::parseMeRegion(const QByteArray & me, const UINT32 parentOffset
         return ERR_EMPTY_REGION;
 
     // Get parent's parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(parent);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
 
     // Get info
     QString name = tr("ME region");
@@ -528,7 +528,7 @@ STATUS FfsParser::parsePdrRegion(const QByteArray & pdr, const UINT32 parentOffs
         return ERR_EMPTY_REGION;
 
     // Get parent's parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(parent);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
 
     // Get info
     QString name = tr("PDR region");
@@ -558,7 +558,7 @@ STATUS FfsParser::parseBiosRegion(const QByteArray & bios, const UINT32 parentOf
         return ERR_EMPTY_REGION;
 
     // Get parent's parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(parent);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
 
     // Get info
     QString name = tr("BIOS region");
@@ -592,7 +592,7 @@ STATUS FfsParser::parseRawArea(const QByteArray & data, const QModelIndex & inde
         return ERR_INVALID_PARAMETER;
 
     // Get parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(index);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(index);
     UINT32 offset = pdata.offset;
     UINT32 headerSize = model->header(index).size();
 
@@ -746,7 +746,7 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare
         return ERR_INVALID_PARAMETER;
 
     // Get parent's parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(parent);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
 
     // Populate volume header
     const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(volume.constData());
@@ -831,14 +831,14 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare
     UINT8 emptyByte = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00';
 
     // Check for Apple CRC32 in ZeroVector
-    bool hasZeroVectorCRC32 = false;
+    bool hasAppleCrc32 = false;
     UINT32 volumeSize = volume.size();
-    UINT32 crc32FromZeroVector = *(UINT32*)(volume.constData() + 8);
-    if (crc32FromZeroVector != 0) {
+    UINT32 appleCrc32 = *(UINT32*)(volume.constData() + 8);
+    if (appleCrc32 != 0) {
         // Calculate CRC32 of the volume body
         UINT32 crc = crc32(0, (const UINT8*)(volume.constData() + volumeHeader->HeaderLength), volumeSize - volumeHeader->HeaderLength);
-        if (crc == crc32FromZeroVector) {
-            hasZeroVectorCRC32 = true;
+        if (crc == appleCrc32) {
+            hasAppleCrc32 = true;
         }
     }
 
@@ -865,11 +865,6 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare
         .hexarg2(volumeHeader->Attributes, 8)
         .arg(emptyByte ? "1" : "0");
 
-    // Apple CRC32 volume
-    if (hasZeroVectorCRC32) {
-        info += tr("\nCRC32 in ZeroVector: valid");
-    }
-
     // Extended header present
     if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) {
         const EFI_FIRMWARE_VOLUME_EXT_HEADER* extendedHeader = (const EFI_FIRMWARE_VOLUME_EXT_HEADER*)(volume.constData() + volumeHeader->ExtHeaderOffset);
@@ -887,14 +882,14 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare
     pdata.volume.extendedHeaderGuid = extendedHeaderGuid;
     pdata.volume.alignment = alignment;
     pdata.volume.revision = volumeHeader->Revision;
-    pdata.volume.hasZeroVectorCRC32 = hasZeroVectorCRC32;
+    pdata.volume.hasAppleCrc32 = hasAppleCrc32;
     pdata.volume.isWeakAligned = (volumeHeader->Revision > 1 && (volumeHeader->Attributes & EFI_FVB2_WEAK_ALIGNMENT));
     if (pdata.isOnFlash) info.prepend(tr("Offset: %1h\n").hexarg(pdata.offset));
 
     // Add text
     QString text;
-    if (hasZeroVectorCRC32)
-        text += tr("ZeroVectorCRC32 ");
+    if (hasAppleCrc32)
+        text += tr("AppleCRC32 ");
 
     // Add tree item
     UINT8 subtype = Subtypes::UnknownVolume;
@@ -967,7 +962,7 @@ STATUS FfsParser::parseVolumeBody(const QModelIndex & index)
     UINT32 volumeHeaderSize = model->header(index).size();
 
     // Get parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(index);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(index);
     UINT32 offset = pdata.offset;
 
     if (pdata.ffsVersion != 2 && pdata.ffsVersion != 3) // Don't parse unknown volumes
@@ -1146,7 +1141,7 @@ STATUS FfsParser::parseFileHeader(const QByteArray & file, const UINT32 parentOf
         return ERR_INVALID_PARAMETER;
 
     // Get parent's parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(parent);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
 
     // Get file header
     QByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER));
@@ -1328,7 +1323,7 @@ STATUS FfsParser::parsePadFileBody(const QModelIndex & index)
         return ERR_INVALID_PARAMETER;
 
     // Get data from parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(index);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(index);
 
     // Check if all bytes of the file are empty
     QByteArray body = model->body(index);
@@ -1395,7 +1390,7 @@ STATUS FfsParser::parseSections(QByteArray sections, const QModelIndex & index)
         return ERR_INVALID_PARAMETER;
 
     // Get data from parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(index);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(index);
 
     // Search for and parse all sections
     UINT32 bodySize = sections.size();
@@ -1491,7 +1486,7 @@ STATUS FfsParser::parseSectionHeader(const QByteArray & section, const UINT32 pa
 STATUS FfsParser::parseCommonSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
 {
     // Get data from parent's parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(parent);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
 
     // Obtain header fields
     const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData());
@@ -1523,7 +1518,7 @@ STATUS FfsParser::parseCommonSectionHeader(const QByteArray & section, const UIN
 STATUS FfsParser::parseCompressedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
 {
     // Get data from parent's parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(parent);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
 
     // Obtain header fields
     const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData());
@@ -1566,7 +1561,7 @@ STATUS FfsParser::parseCompressedSectionHeader(const QByteArray & section, const
 STATUS FfsParser::parseGuidedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
 {
     // Get data from parent's parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(parent);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
 
     // Obtain header fields
     const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData());
@@ -1610,7 +1605,7 @@ STATUS FfsParser::parseGuidedSectionHeader(const QByteArray & section, const UIN
 STATUS FfsParser::parseFreeformGuidedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
 {
     // Get data from parent's parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(parent);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
 
     // Obtain header fields
     const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData());
@@ -1697,7 +1692,7 @@ STATUS FfsParser::parseFreeformGuidedSectionHeader(const QByteArray & section, c
 STATUS FfsParser::parseVersionSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
 {
     // Get data from parent's parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(parent);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
 
     // Obtain header fields
     const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData());
@@ -1735,7 +1730,7 @@ STATUS FfsParser::parseVersionSectionHeader(const QByteArray & section, const UI
 STATUS FfsParser::parsePostcodeSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
 {
     // Get data from parent's parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(parent);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
 
     // Obtain header fields
     const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData());
@@ -1812,7 +1807,7 @@ STATUS FfsParser::parseCompressedSectionBody(const QModelIndex & index)
         return ERR_INVALID_PARAMETER;
 
     // Get data from parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(index);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(index);
     UINT8 algorithm = pdata.section.compressed.compressionType;
 
     // Decompress section
@@ -1852,7 +1847,7 @@ STATUS FfsParser::parseGuidedSectionBody(const QModelIndex & index)
         return ERR_INVALID_PARAMETER;
 
     // Get data from parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(index);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(index);
     UINT32 attributes = pdata.section.guidDefined.attributes;
     EFI_GUID guid = pdata.section.guidDefined.guid;
 
@@ -2243,7 +2238,7 @@ STATUS FfsParser::parseTeImageSectionBody(const QModelIndex & index)
     }
 
     // Get data from parsing data
-    PARSING_DATA pdata = parsingDataFromQByteArray(index);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(index);
     pdata.section.teImage.imageBase = teHeader->ImageBase;
     pdata.section.teImage.adjustedImageBase = teHeader->ImageBase + teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER);
     
@@ -2264,22 +2259,19 @@ STATUS FfsParser::performSecondPass(const QModelIndex & index)
         return ERR_INVALID_PARAMETER;
 
     // Get parsing data for the last VTF
-    PARSING_DATA pdata = parsingDataFromQByteArray(lastVtf);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(lastVtf);
     if (!pdata.isOnFlash) {
-        msg(tr("addPhysicalAddressInfo: the last VTF appears inside compressed item, the image may be damaged"), lastVtf);
+        msg(tr("performSecondPass: the last VTF appears inside compressed item, the image may be damaged"), lastVtf);
         return ERR_SUCCESS;
     }
 
     // Calculate address difference
     const UINT32 vtfSize = model->header(lastVtf).size() + model->body(lastVtf).size() + (pdata.file.hasTail ? sizeof(UINT16) : 0);
-    const UINT32 diff = 0xFFFFFFFF - pdata.offset - vtfSize + 1;
+    const UINT32 diff = 0xFFFFFFFFUL - pdata.offset - vtfSize + 1;
 
     // Apply address information to index and all it's child items
     addMemoryAddressesRecursive(index, diff);
 
-    // Find and parse FIT
-    parseFit();
-
     return ERR_SUCCESS;
 }
 
@@ -2290,12 +2282,12 @@ STATUS FfsParser::addMemoryAddressesRecursive(const QModelIndex & index, const U
         return ERR_SUCCESS;
 
     // Get parsing data for the current item
-    PARSING_DATA pdata = parsingDataFromQByteArray(index);
+    PARSING_DATA pdata = parsingDataFromQModelIndex(index);
 
     // Set address value for non-compressed data
     if (pdata.isOnFlash) {
         // Check address sanity
-        if ((const UINT64)diff + pdata.offset <= 0xFFFFFFFF)  {
+        if ((const UINT64)diff + pdata.offset <= 0xFFFFFFFFUL)  {
             // Update info
             pdata.address = diff + pdata.offset;
             UINT32 headerSize = model->header(index).size();
@@ -2335,13 +2327,69 @@ STATUS FfsParser::addMemoryAddressesRecursive(const QModelIndex & index, const U
     return ERR_SUCCESS;
 }
 
-STATUS FfsParser::parseFit()
+/*STATUS FfsParser::parseFit(const QModelIndex & index)
 {
     // Check sanity
-    if (!lastVtf.isValid)
+    if (!lastVtf.isValid())
         return EFI_INVALID_PARAMETER;
 
+    // Search for FIT
+    QModelIndex fitIndex;
+    STATUS result = findFitRecursive(index, fitIndex);
+    if (result)
+        return result;
 
+    // FIT not found
+    if (!fitIndex.isValid())
+        return ERR_SUCCESS;
+    
+    // Get parsing data for the current item
+    PARSING_DATA pdata = parsingDataFromQModelIndex(fitIndex);
+
+    // Explicitly set the item as fixed
+    pdata.fixed = TRUE;
+
+    // Set modified parsing data
+    model->setParsingData(fitIndex, parsingDataToQByteArray(pdata));
 
     return ERR_SUCCESS;
-}
\ No newline at end of file
+}
+
+STATUS FfsParser::findFitRecursive(const QModelIndex & index, QModelIndex & found)
+{
+    // Sanity check
+    if (!index.isValid())
+        return EFI_SUCCESS;
+
+    // Process child items
+    for (int i = 0; i < model->rowCount(index); i++) {
+        findFitRecursive(index.child(i, 0), found);
+        if (found.isValid())
+            return EFI_SUCCESS;
+    }
+
+    // Get parsing data for the current item
+    PARSING_DATA pdata = parsingDataFromQModelIndex(index);
+
+    // Check item's address to be in required range
+    INT32 offset = model->body(index).indexOf(FIT_SIGNATURE);
+    // Check for FIT signature in item's body
+    if (offset >= 0) {
+        // FIT candidate found, calculate it's offset and physical address
+        UINT32 fitOffset = pdata.offset + model->header(index).size() + (UINT32)offset;
+        UINT32 fitAddress = pdata.address + model->header(index).size() + (UINT32)offset;
+            
+        // Check FIT address to be in the last VTF
+        QByteArray lastVtfBody = model->body(lastVtf);
+        if (*(const UINT32*)(lastVtfBody.constData() + lastVtfBody.size() - FIT_POINTER_OFFSET) == fitAddress) {
+            msg(tr("findFitRecursive: FIT table found at offset %1h, physical address %2h")
+                .hexarg2(fitOffset, 8)
+                .hexarg2(fitAddress, 8),
+                index);
+            found = index;
+            return ERR_SUCCESS;
+        }
+    }
+
+    return ERR_SUCCESS;
+}*/
\ No newline at end of file
diff --git a/common/ffsparser.h b/common/ffsparser.h
index 347a95e..c24980e 100644
--- a/common/ffsparser.h
+++ b/common/ffsparser.h
@@ -53,6 +53,9 @@ public:
     STATUS parseSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
     STATUS parseSectionBody(const QModelIndex & index);
 
+    // Retuns index of the last VTF after parsing is done
+    const QModelIndex getLastVtf() {return lastVtf;};
+
 private:
     TreeModel *model;
     QVector<QPair<QString, QModelIndex> > messagesVector;
@@ -92,7 +95,8 @@ private:
 
     STATUS performSecondPass(const QModelIndex & index);
     STATUS addMemoryAddressesRecursive(const QModelIndex & index, const UINT32 diff);
-    STATUS parseFit();
+    /*STATUS parseFit(const QModelIndex & index);
+    STATUS findFitRecursive(const QModelIndex & index, QModelIndex & found);*/
 
     // Internal operations
     BOOLEAN hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2);
diff --git a/common/fit.h b/common/fit.h
index c12c1a8..ea9d126 100644
--- a/common/fit.h
+++ b/common/fit.h
@@ -20,10 +20,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #pragma pack(push,1)
 
 // Memory address of a pointer to FIT, 40h back from the end of flash chip
-#define FIT_POINTER_ADDRESS 0xFFFFFFC0
-
-// FIT can reside in the last 1 MB of the flash chip
-#define FIT_TABLE_LOWEST_ADDRESS 0xFF000000
+#define FIT_POINTER_OFFSET 0x40
 
 // Entry types 
 #define FIT_TYPE_HEADER            0x00
@@ -35,7 +32,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #define FIT_TYPE_TXT_CONF_POLICY   0x0A
 #define FIT_TYPE_AC_KEY_MANIFEST   0x0B
 #define FIT_TYPE_AC_BOOT_POLICY    0x0C
-#define FIT_TYPE_EMPTY             0xFF
+#define FIT_TYPE_EMPTY             0x7F
 
 #define FIT_HEADER_VERSION         0x0100
 #define FIT_MICROCODE_VERSION      0x0100
@@ -45,10 +42,9 @@ const QByteArray FIT_SIGNATURE
 
 typedef struct _FIT_ENTRY {
     UINT64 Address;
-    UINT64 ReservedSize;
+    UINT32 Size;
     UINT16 Version;
-    UINT8  ChecksumValid : 1;
-    UINT8  Type : 7;
+    UINT8  Type;
     UINT8  Checksum;
 } FIT_ENTRY;
 
diff --git a/common/fitparser.cpp b/common/fitparser.cpp
new file mode 100644
index 0000000..c034f33
--- /dev/null
+++ b/common/fitparser.cpp
@@ -0,0 +1,152 @@
+/* fitparser.cpp
+
+Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*/
+#include "fitparser.h"
+#include "types.h"
+#include "treemodel.h"
+
+
+FitParser::FitParser(TreeModel* treeModel, QObject *parent)
+    : QObject(parent), model(treeModel)
+{
+}
+
+FitParser::~FitParser()
+{
+}
+
+STATUS FitParser::parse(const QModelIndex & index, const QModelIndex & lastVtfIndex)
+{
+    // Check sanity
+    if (!index.isValid() || !lastVtfIndex.isValid())
+        return EFI_INVALID_PARAMETER;
+
+    // Store lastVtfIndex
+    lastVtf = lastVtfIndex;
+
+    // Search for FIT
+    QModelIndex fitIndex;
+    UINT32 fitOffset;
+    STATUS result = findFitRecursive(index, fitIndex, fitOffset);
+    if (result)
+        return result;
+
+    // FIT not found
+    if (!fitIndex.isValid())
+        return ERR_SUCCESS;
+    
+    // Get parsing data for the current item
+    PARSING_DATA pdata = parsingDataFromQModelIndex(fitIndex);
+
+    // Explicitly set the item as fixed
+    pdata.fixed = TRUE;
+
+    // Set modified parsing data
+    model->setParsingData(fitIndex, parsingDataToQByteArray(pdata));
+
+    // Add all FIT entries into QVector
+    const FIT_ENTRY* fitHeader = (const FIT_ENTRY*)(model->body(fitIndex).constData() + fitOffset);
+
+    // Special case of FIT header
+    QString remark;
+
+    // Check FIT checksum, if present
+    if (fitHeader->Type & 0x80) {
+        // Calculate FIT entry checksum
+        UINT32 fitSize = (fitHeader->Size & 0xFFFFFF) << 4;
+        UINT8 calculated = calculateChecksum8((const UINT8*)fitHeader, fitSize);
+        if (calculated) {
+            remark.append(tr("Invalid FIT table checksum, ").hexarg2(calculated, 2));
+        }
+    }
+
+    // Check fit header version and type
+    if (fitHeader->Version != FIT_HEADER_VERSION) {
+        remark.append(tr("Invalid FIT header version, "));
+    }
+    if ((fitHeader->Type & 0x7F) != FIT_TYPE_HEADER) {
+        remark.append(tr("Invalid FIT header type, "));
+    }
+
+    // Remove the last ", " from remark string, if needed
+    if (!remark.isEmpty())
+        remark = remark.left(remark.length() - 2);
+
+    // Add FIT header to fitEntries vector
+    fitEntries.append(QPair<FIT_ENTRY, QString>(*fitHeader, remark));
+
+    // Process all other entries
+    for (UINT32 i = 1; i < fitHeader->Size; i++) {
+        remark.clear();
+        const FIT_ENTRY* currentEntry = fitHeader + i;
+
+        // Check entry type
+        switch (currentEntry->Type & 0x7F) {
+        case FIT_TYPE_HEADER:
+            remark.append(tr("Second FIT header found, the table is damaged"));
+            break;
+
+        case FIT_TYPE_EMPTY:
+        case FIT_TYPE_MICROCODE:
+            break;
+
+        case FIT_TYPE_BIOS_AC_MODULE:
+        case FIT_TYPE_BIOS_INIT_MODULE:
+        case FIT_TYPE_TPM_POLICY:
+        case FIT_TYPE_BIOS_POLICY_DATA:
+        case FIT_TYPE_TXT_CONF_POLICY:
+        case FIT_TYPE_AC_KEY_MANIFEST:
+        case FIT_TYPE_AC_BOOT_POLICY:
+        default:
+            remark.append(tr("Modified image may not work"));
+            break;
+        }
+
+        fitEntries.append(QPair<FIT_ENTRY, QString>(*currentEntry, remark));
+    }
+
+    return ERR_SUCCESS;
+}
+
+STATUS FitParser::findFitRecursive(const QModelIndex & index, QModelIndex & found, UINT32 & fitOffset)
+{
+    // Sanity check
+    if (!index.isValid())
+        return EFI_SUCCESS;
+
+    // Process child items
+    for (int i = 0; i < model->rowCount(index); i++) {
+        findFitRecursive(index.child(i, 0), found, fitOffset);
+        if (found.isValid())
+            return EFI_SUCCESS;
+    }
+
+    // Get parsing data for the current item
+    PARSING_DATA pdata = parsingDataFromQModelIndex(index);
+
+    // Check item's address to be in required range
+    INT32 offset = model->body(index).indexOf(FIT_SIGNATURE);
+    // Check for FIT signature in item's body
+    if (offset >= 0) {
+        // FIT candidate found, calculate it's physical address
+        UINT32 fitAddress = pdata.address + model->header(index).size() + (UINT32)offset;
+            
+        // Check FIT address to be in the last VTF
+        QByteArray lastVtfBody = model->body(lastVtf);
+        if (*(const UINT32*)(lastVtfBody.constData() + lastVtfBody.size() - FIT_POINTER_OFFSET) == fitAddress) {
+            found = index;
+            fitOffset = offset;
+            return ERR_SUCCESS;
+        }
+    }
+
+    return ERR_SUCCESS;
+}
\ No newline at end of file
diff --git a/common/fitparser.h b/common/fitparser.h
new file mode 100644
index 0000000..ab296b8
--- /dev/null
+++ b/common/fitparser.h
@@ -0,0 +1,50 @@
+/* fitparser.h
+
+Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*/
+
+#ifndef __FITPARSER_H__
+#define __FITPARSER_H__
+
+#include <QObject>
+#include <QModelIndex>
+#include <QByteArray>
+#include <QStringList>
+#include <QVector>
+
+#include "basetypes.h"
+#include "treemodel.h"
+#include "utility.h"
+#include "parsingdata.h"
+#include "fit.h"
+
+class TreeModel;
+
+class FitParser : public QObject
+{
+    Q_OBJECT
+
+public:
+    // Default constructor and destructor
+    FitParser(TreeModel* treeModel, QObject *parent = 0);
+    ~FitParser();
+
+    STATUS parse(const QModelIndex & index, const QModelIndex & lastVtf);
+    QVector<QPair<FIT_ENTRY, QString> > getFitEntries() const { return fitEntries; }
+
+private:
+    TreeModel *model;
+    QModelIndex lastVtf;
+    QVector<QPair<FIT_ENTRY, QString> > fitEntries;
+    
+    STATUS findFitRecursive(const QModelIndex & index, QModelIndex & found, UINT32 & fitOffset);
+};
+
+#endif
diff --git a/common/parsingdata.h b/common/parsingdata.h
index 3be8071..5ee9eaa 100644
--- a/common/parsingdata.h
+++ b/common/parsingdata.h
@@ -34,7 +34,8 @@ typedef struct _VOLUME_PARSING_DATA {
     UINT32   alignment;
     UINT8    revision;
     BOOLEAN  hasExtendedHeader;
-    BOOLEAN  hasZeroVectorCRC32;
+    BOOLEAN  hasAppleCrc32;
+    BOOLEAN  hasAppleFSO;
     BOOLEAN  isWeakAligned;
 } VOLUME_PARSING_DATA;
 
diff --git a/common/utility.cpp b/common/utility.cpp
index 0054cf2..2073e2b 100644
--- a/common/utility.cpp
+++ b/common/utility.cpp
@@ -20,7 +20,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include "LZMA/LzmaDecompress.h"
 
 // Returns either new parsing data instance or obtains it from index
-PARSING_DATA parsingDataFromQByteArray(const QModelIndex & index)
+PARSING_DATA parsingDataFromQModelIndex(const QModelIndex & index)
 {
     if (index.isValid()) {
         TreeModel* model = (TreeModel*)index.model();
@@ -257,3 +257,34 @@ STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArr
     }
 }
 
+// 8bit checksum calculation routine
+UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize)
+{
+    if (!buffer)
+        return 0;
+
+    UINT8 counter = 0;
+
+    while (bufferSize--)
+        counter += buffer[bufferSize];
+
+    return (UINT8)(0x100 - counter);
+}
+
+// 16bit checksum calculation routine
+UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize)
+{
+    if (!buffer)
+        return 0;
+
+    UINT16 counter = 0;
+    UINT32 index = 0;
+
+    bufferSize /= sizeof(UINT16);
+
+    for (; index < bufferSize; index++) {
+        counter = (UINT16)(counter + buffer[index]);
+    }
+
+    return (UINT16)(0x10000 - counter);
+}
\ No newline at end of file
diff --git a/common/utility.h b/common/utility.h
index 708e683..ba44d04 100644
--- a/common/utility.h
+++ b/common/utility.h
@@ -20,7 +20,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include "parsingdata.h"
 
 // Returns either new parsing data instance or obtains it from index
-PARSING_DATA parsingDataFromQByteArray(const QModelIndex & index);
+PARSING_DATA parsingDataFromQModelIndex(const QModelIndex & index);
 
 // Converts parsing data to byte array
 QByteArray parsingDataToQByteArray(const PARSING_DATA & pdata);
@@ -34,7 +34,13 @@ extern STATUS decompress(const QByteArray & compressed, UINT8 & algorithm, QByte
 // Compression routine
 //STATUS compress(const QByteArray & decompressed, QByteArray & compressed, const UINT8 & algorithm);
 
-// CRC32
+// CRC32 calculation routine
 extern UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length);
 
+// 8bit checksum calculation routine
+extern UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize);
+
+// 16bit checksum calculation routine
+extern UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize);
+
 #endif
\ No newline at end of file