Engine 0.20.6

- added support for recalculation of Apple-specific free space offset
value stored in volume's ZeroVector. Thanks to osxreverser for reporting
the issue #29.
- ZeroVectorCRC renamed to AppleCRC32, because it's Apple-specific after
all.
- ParsingData handling removed from old codebase, because it's only
needed for the new engine.
This commit is contained in:
Nikolaj Schlej 2015-07-05 13:28:53 +02:00
parent d78df75de6
commit c5fec376f7
7 changed files with 78 additions and 137 deletions

View File

@ -221,7 +221,7 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer)
.hexarg(flashImage.size()).arg(flashImage.size()); .hexarg(flashImage.size()).arg(flashImage.size());
// Add tree item // Add tree item
index = model->addItem(Types::Image, Subtypes::UefiImage, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), flashImage, QByteArray(), index); index = model->addItem(Types::Image, Subtypes::UefiImage, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), flashImage, index);
return parseBios(flashImage, index); return parseBios(flashImage, index);
} }
@ -359,7 +359,7 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
.arg(descriptorMap->NumberOfIccTableEntries); .arg(descriptorMap->NumberOfIccTableEntries);
// Add Intel image tree item // Add Intel image tree item
index = model->addItem(Types::Image, Subtypes::IntelImage, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), intelImage, QByteArray(), parent); index = model->addItem(Types::Image, Subtypes::IntelImage, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), intelImage, parent);
// Descriptor // Descriptor
// Get descriptor info // Get descriptor info
@ -426,7 +426,7 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
} }
// Add descriptor tree item // Add descriptor tree item
model->addItem(Types::Region, Subtypes::DescriptorRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), body, QByteArray(), index); model->addItem(Types::Region, Subtypes::DescriptorRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), body, index);
// Sort regions in ascending order // Sort regions in ascending order
qSort(offsets); qSort(offsets);
@ -483,7 +483,7 @@ UINT8 FfsEngine::parseGbeRegion(const QByteArray & gbe, QModelIndex & index, con
.arg(version->minor); .arg(version->minor);
// Add tree item // Add tree item
index = model->addItem(Types::Region, Subtypes::GbeRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), gbe, QByteArray(), parent, mode); index = model->addItem(Types::Region, Subtypes::GbeRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), gbe, parent, mode);
return ERR_SUCCESS; return ERR_SUCCESS;
} }
@ -532,7 +532,7 @@ UINT8 FfsEngine::parseMeRegion(const QByteArray & me, QModelIndex & index, const
} }
// Add tree item // Add tree item
index = model->addItem(Types::Region, Subtypes::MeRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), me, QByteArray(), parent, mode); index = model->addItem(Types::Region, Subtypes::MeRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), me, parent, mode);
// Show messages // Show messages
if (emptyRegion) { if (emptyRegion) {
@ -557,7 +557,7 @@ UINT8 FfsEngine::parsePdrRegion(const QByteArray & pdr, QModelIndex & index, con
hexarg(pdr.size()).arg(pdr.size()); hexarg(pdr.size()).arg(pdr.size());
// Add tree item // Add tree item
index = model->addItem(Types::Region, Subtypes::PdrRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), pdr, QByteArray(), parent, mode); index = model->addItem(Types::Region, Subtypes::PdrRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), pdr, parent, mode);
// Parse PDR region as BIOS space // Parse PDR region as BIOS space
UINT8 result = parseBios(pdr, index); UINT8 result = parseBios(pdr, index);
@ -578,7 +578,7 @@ UINT8 FfsEngine::parseBiosRegion(const QByteArray & bios, QModelIndex & index, c
hexarg(bios.size()).arg(bios.size()); hexarg(bios.size()).arg(bios.size());
// Add tree item // Add tree item
index = model->addItem(Types::Region, Subtypes::BiosRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), bios, QByteArray(), parent, mode); index = model->addItem(Types::Region, Subtypes::BiosRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), bios, parent, mode);
return parseBios(bios, index); return parseBios(bios, index);
} }
@ -613,7 +613,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
.hexarg(padding.size()).arg(padding.size()); .hexarg(padding.size()).arg(padding.size());
// Add tree item // Add tree item
model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent); model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, parent);
} }
// Search for and parse all volumes // Search for and parse all volumes
@ -638,7 +638,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
info = tr("Full size: %1h (%2)") info = tr("Full size: %1h (%2)")
.hexarg(padding.size()).arg(padding.size()); .hexarg(padding.size()).arg(padding.size());
// Add tree item // Add tree item
model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent); model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, parent);
} }
// Get volume size // Get volume size
@ -712,7 +712,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
info = tr("Full size: %1h (%2)") info = tr("Full size: %1h (%2)")
.hexarg(padding.size()).arg(padding.size()); .hexarg(padding.size()).arg(padding.size());
// Add tree item // Add tree item
model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent); model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, parent);
} }
break; break;
} }
@ -784,12 +784,6 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
/*volumeFfsVersion = 2;*/ /*volumeFfsVersion = 2;*/
} }
// Check for FFS v3 volume
/*if (FFSv3Volumes.contains(QByteArray::fromRawData((const char*)volumeHeader->FileSystemGuid.Data, sizeof(EFI_GUID)))) {
volumeIsUnknown = false;
volumeFfsVersion = 3;
}*/
// Check attributes // Check attributes
// Determine value of empty byte // Determine value of empty byte
char empty = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00'; char empty = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00';
@ -804,13 +798,20 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
// Check for Apple CRC32 in ZeroVector // Check for Apple CRC32 in ZeroVector
bool volumeHasZVCRC = false; bool volumeHasZVCRC = false;
bool volumeHasZVFSO = false;
UINT32 crc32FromZeroVector = *(UINT32*)(volume.constData() + 8); UINT32 crc32FromZeroVector = *(UINT32*)(volume.constData() + 8);
UINT32 freeSpaceOffsetFromZeroVector = *(UINT32*)(volume.constData() + 12);
if (crc32FromZeroVector != 0) { if (crc32FromZeroVector != 0) {
// Calculate CRC32 of the volume body // Calculate CRC32 of the volume body
UINT32 crc = crc32(0, (const UINT8*)(volume.constData() + volumeHeader->HeaderLength), volumeSize - volumeHeader->HeaderLength); UINT32 crc = crc32(0, (const UINT8*)(volume.constData() + volumeHeader->HeaderLength), volumeSize - volumeHeader->HeaderLength);
if (crc == crc32FromZeroVector) { if (crc == crc32FromZeroVector) {
volumeHasZVCRC = true; volumeHasZVCRC = true;
} }
// Check for free space size in zero vector
if (freeSpaceOffsetFromZeroVector != 0) {
volumeHasZVFSO = true;
}
} }
// Check header checksum by recalculating it // Check header checksum by recalculating it
@ -834,11 +835,6 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
.hexarg2(volumeHeader->Attributes, 8) .hexarg2(volumeHeader->Attributes, 8)
.arg(empty ? "1" : "0"); .arg(empty ? "1" : "0");
// Apple CRC32 volume
if (volumeHasZVCRC) {
info += tr("\nCRC32 in ZeroVector: valid");
}
// Extended header present // Extended header present
if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) { if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) {
const EFI_FIRMWARE_VOLUME_EXT_HEADER* extendedHeader = (const EFI_FIRMWARE_VOLUME_EXT_HEADER*)(volume.constData() + volumeHeader->ExtHeaderOffset); const EFI_FIRMWARE_VOLUME_EXT_HEADER* extendedHeader = (const EFI_FIRMWARE_VOLUME_EXT_HEADER*)(volume.constData() + volumeHeader->ExtHeaderOffset);
@ -847,21 +843,17 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
.arg(guidToQString(extendedHeader->FvName)); .arg(guidToQString(extendedHeader->FvName));
} }
// Construct parsing data structure
QByteArray parsingData(sizeof(PARSING_DATA), 0);
PARSING_DATA* pdata = (PARSING_DATA*)parsingData.data();
pdata->Type = VolumeParsingData;
pdata->Data.Volume.HasZeroVectorCRC = volumeHasZVCRC;
// Add text // Add text
QString text; QString text;
if (volumeHasZVCRC) if (volumeHasZVCRC)
text += tr("ZeroVectorCRC "); text += tr("AppleCRC32 ");
if (volumeHasZVFSO)
text += tr("AppleFSO ");
// Add tree item // Add tree item
QByteArray header = volume.left(headerSize); QByteArray header = volume.left(headerSize);
QByteArray body = volume.mid(headerSize, volumeSize - 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, parsingData, parent, mode); index = model->addItem(Types::Volume, volumeIsUnknown ? Subtypes::UnknownVolume : Subtypes::Ffs2Volume, COMPRESSION_ALGORITHM_NONE, name, text, info, header, body, parent, mode);
// Show messages // Show messages
if (volumeIsUnknown) { if (volumeIsUnknown) {
@ -917,16 +909,16 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
// Add all bytes before as free space... // Add all bytes before as free space...
if (i > 0) { if (i > 0) {
QByteArray free = freeSpace.left(i); QByteArray free = freeSpace.left(i);
model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(free.size()).arg(free.size()), QByteArray(), free, QByteArray(), index, mode); model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(free.size()).arg(free.size()), QByteArray(), free, index, mode);
} }
// ... and all bytes after as a padding // ... and all bytes after as a padding
QByteArray padding = freeSpace.mid(i); QByteArray padding = freeSpace.mid(i);
QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size()), QByteArray(), padding, QByteArray(), index, mode); QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size()), QByteArray(), padding, index, mode);
msg(tr("parseVolume: non-UEFI data found in volume's free space"), dataIndex); msg(tr("parseVolume: non-UEFI data found in volume's free space"), dataIndex);
} }
else { else {
// Add free space element // Add free space element
model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(freeSpace.size()).arg(freeSpace.size()), QByteArray(), freeSpace, QByteArray(), index, mode); model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(freeSpace.size()).arg(freeSpace.size()), QByteArray(), freeSpace, index, mode);
} }
break; // Exit from loop break; // Exit from loop
} }
@ -951,14 +943,6 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
if (result && result != ERR_VOLUMES_NOT_FOUND && result != ERR_INVALID_VOLUME) 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); msg(tr("parseVolume: FFS file parsing failed with error \"%1\"").arg(errorMessage(result)), index);
// Construct parsing data structure
QByteArray parsingData(sizeof(PARSING_DATA), 0);
PARSING_DATA* pdata = (PARSING_DATA*)parsingData.data();
pdata->Type = FileParsingData;
pdata->Data.File.Offset = fileOffset;
model->setParsingData(fileIndex, parsingData);
// Show messages // Show messages
if (msgUnalignedFile) if (msgUnalignedFile)
msg(tr("parseVolume: unaligned file %1").arg(guidToQString(fileHeader->Name)), fileIndex); msg(tr("parseVolume: unaligned file %1").arg(guidToQString(fileHeader->Name)), fileIndex);
@ -1108,7 +1092,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U
.hexarg2(fileHeader->State, 2); .hexarg2(fileHeader->State, 2);
// Add tree item // Add tree item
index = model->addItem(Types::File, fileHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::File, fileHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
// Show messages // Show messages
if (msgInvalidHeaderChecksum) if (msgInvalidHeaderChecksum)
@ -1137,11 +1121,11 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U
// Add all bytes before as free space... // Add all bytes before as free space...
if (i > 0) { if (i > 0) {
QByteArray free = body.left(i); QByteArray free = body.left(i);
model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Free space"), "", tr("Full size: %1h (%2)").hexarg(free.size()).arg(free.size()), QByteArray(), free, QByteArray(), index, mode); model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Free space"), "", tr("Full size: %1h (%2)").hexarg(free.size()).arg(free.size()), QByteArray(), free, index, mode);
} }
// ... and all bytes after as a padding // ... and all bytes after as a padding
QByteArray padding = body.mid(i); QByteArray padding = body.mid(i);
QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size()), QByteArray(), padding, QByteArray(), index, mode); QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size()), QByteArray(), padding, index, mode);
// Show message // Show message
msg(tr("parseFile: non-empty pad-file contents will be destroyed after volume modifications"), dataIndex); msg(tr("parseFile: non-empty pad-file contents will be destroyed after volume modifications"), dataIndex);
@ -1348,7 +1332,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
.hexarg(compressedSectionHeader->UncompressedLength).arg(compressedSectionHeader->UncompressedLength); .hexarg(compressedSectionHeader->UncompressedLength).arg(compressedSectionHeader->UncompressedLength);
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, algorithm, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, algorithm, name, "", info, header, body, parent, mode);
// Show message // Show message
if (!parseCurrentSection) if (!parseCurrentSection)
@ -1488,7 +1472,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
} }
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, algorithm, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, algorithm, name, "", info, header, body, parent, mode);
// Show messages // Show messages
if (msgUnknownGuid) if (msgUnknownGuid)
@ -1527,7 +1511,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
.hexarg(body.size()).arg(body.size()); .hexarg(body.size()).arg(body.size());
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
// Parse section body // Parse section body
result = parseSections(body, index); result = parseSections(body, index);
@ -1560,7 +1544,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
info += tr("\nParsed expression:%1").arg(str); info += tr("\nParsed expression:%1").arg(str);
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
// Show messages // Show messages
if (msgDepexParseFailed) if (msgDepexParseFailed)
@ -1600,7 +1584,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
.hexarg(teHeader->ImageBase + teHeader->AddressOfEntryPoint - teFixup); .hexarg(teHeader->ImageBase + teHeader->AddressOfEntryPoint - teFixup);
} }
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
// Show messages // Show messages
if (msgInvalidSignature) { if (msgInvalidSignature) {
@ -1683,7 +1667,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
} }
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
// Show messages // Show messages
if (msgInvalidDosSignature) { if (msgInvalidDosSignature) {
@ -1719,7 +1703,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
.hexarg(body.size()).arg(body.size()); .hexarg(body.size()).arg(body.size());
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
} break; } break;
case EFI_SECTION_FREEFORM_SUBTYPE_GUID: { case EFI_SECTION_FREEFORM_SUBTYPE_GUID: {
@ -1736,7 +1720,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
.arg(guidToQString(fsgHeader->SubTypeGuid)); .arg(guidToQString(fsgHeader->SubTypeGuid));
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
// Rename section // Rename section
model->setName(index, guidToQString(fsgHeader->SubTypeGuid)); model->setName(index, guidToQString(fsgHeader->SubTypeGuid));
@ -1758,7 +1742,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
.arg(QString::fromUtf16((const ushort*)body.constData())); .arg(QString::fromUtf16((const ushort*)body.constData()));
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
} break; } break;
case EFI_SECTION_USER_INTERFACE: { case EFI_SECTION_USER_INTERFACE: {
@ -1775,7 +1759,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
.arg(text); .arg(text);
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
// Rename parent file // Rename parent file
model->setText(model->findParentOfType(parent, Types::File), text); model->setText(model->findParentOfType(parent, Types::File), text);
@ -1793,7 +1777,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
.hexarg(body.size()).arg(body.size()); .hexarg(body.size()).arg(body.size());
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
// Parse section body as BIOS space // Parse section body as BIOS space
result = parseBios(body, index); result = parseBios(body, index);
@ -1846,7 +1830,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
} }
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
// Parse section body as BIOS space // Parse section body as BIOS space
if (!parsed) { if (!parsed) {
@ -1874,7 +1858,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
.hexarg(postcodeHeader->Postcode); .hexarg(postcodeHeader->Postcode);
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
} break; } break;
default: default:
@ -1888,7 +1872,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
.hexarg(body.size()).arg(body.size()); .hexarg(body.size()).arg(body.size());
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
msg(tr("parseSection: section with unknown type %1h").hexarg2(sectionHeader->Type, 2), index); msg(tr("parseSection: section with unknown type %1h").hexarg2(sectionHeader->Type, 2), index);
} }
return ERR_SUCCESS; return ERR_SUCCESS;
@ -2829,6 +2813,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
UINT32 volumeSize = header.size() + body.size(); UINT32 volumeSize = header.size() + body.size();
// Reconstruct volume body // Reconstruct volume body
UINT32 freeSpaceOffset = 0;
if (model->rowCount(index)) { if (model->rowCount(index)) {
reconstructed.clear(); reconstructed.clear();
UINT8 polarity = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? ERASE_POLARITY_TRUE : ERASE_POLARITY_FALSE; UINT8 polarity = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? ERASE_POLARITY_TRUE : ERASE_POLARITY_FALSE;
@ -3007,6 +2992,17 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
return ERR_INVALID_VOLUME; return ERR_INVALID_VOLUME;
} }
// Check for free space offset in ZeroVector
if (model->text(index).contains("AppleFSO ")) {
// Align current offset to 8 byte boundary
UINT32 alignment = offset % 8;
freeSpaceOffset = model->header(index).size() + offset;
if (alignment) {
alignment = 8 - alignment;
freeSpaceOffset += alignment;
}
}
// Insert VTF or non-UEFI data to it's correct place // Insert VTF or non-UEFI data to it's correct place
if (!vtf.isEmpty()) { // VTF found if (!vtf.isEmpty()) { // VTF found
// Determine correct VTF offset // Determine correct VTF offset
@ -3108,22 +3104,36 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
reconstructed = header.append(reconstructed); reconstructed = header.append(reconstructed);
// Recalculate CRC32 in ZeroVector, if needed // Recalculate CRC32 in ZeroVector, if needed
const PARSING_DATA* pdata = (const PARSING_DATA*)model->parsingData(index).constData(); if (model->text(index).contains("AppleCRC32 ")) {
if (pdata->Type == VolumeParsingData && pdata->Data.Volume.HasZeroVectorCRC) {
// Get current CRC32 value from volume header // Get current CRC32 value from volume header
const UINT32 current = *(const UINT32*)(reconstructed.constData() + 8); const UINT32 currentCrc = *(const UINT32*)(reconstructed.constData() + 8);
// Calculate new value // Calculate new value
UINT32 crc = crc32(0, (const UINT8*)reconstructed.constData() + volumeHeader->HeaderLength, reconstructed.size() - volumeHeader->HeaderLength); UINT32 crc = crc32(0, (const UINT8*)reconstructed.constData() + volumeHeader->HeaderLength, reconstructed.size() - volumeHeader->HeaderLength);
// Update the value // Update the value
if (current != crc) { if (currentCrc != crc) {
*(UINT32*)(reconstructed.data() + 8) = crc; *(UINT32*)(reconstructed.data() + 8) = crc;
// Recalculate header checksum again // Recalculate header checksum
volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)reconstructed.data(); volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)reconstructed.data();
volumeHeader->Checksum = 0; volumeHeader->Checksum = 0;
volumeHeader->Checksum = calculateChecksum16((const UINT16*)volumeHeader, volumeHeader->HeaderLength); 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
const UINT32 currentFso = *(const UINT32*)(reconstructed.constData() + 12);
// Update the value
if (freeSpaceOffset != 0 && currentFso != freeSpaceOffset) {
*(UINT32*)(reconstructed.data() + 12) = freeSpaceOffset;
// Recalculate header checksum
volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)reconstructed.data();
volumeHeader->Checksum = 0;
volumeHeader->Checksum = calculateChecksum16((const UINT16*)volumeHeader, volumeHeader->HeaderLength);
}
}
return ERR_SUCCESS; return ERR_SUCCESS;
} }

View File

@ -17,7 +17,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
TreeItem::TreeItem(const UINT8 type, const UINT8 subtype, const UINT8 compression, TreeItem::TreeItem(const UINT8 type, const UINT8 subtype, const UINT8 compression,
const QString & name, const QString & text, const QString & info, const QString & name, const QString & text, const QString & info,
const QByteArray & header, const QByteArray & body, const QByteArray & parsingData, const QByteArray & header, const QByteArray & body,
TreeItem *parent) : TreeItem *parent) :
itemAction(Actions::NoAction), itemAction(Actions::NoAction),
itemType(type), itemType(type),
@ -28,7 +28,6 @@ TreeItem::TreeItem(const UINT8 type, const UINT8 subtype, const UINT8 compressio
itemInfo(info), itemInfo(info),
itemHeader(header), itemHeader(header),
itemBody(body), itemBody(body),
itemParsingData(parsingData),
parentItem(parent) parentItem(parent)
{ {
} }
@ -184,11 +183,6 @@ QByteArray TreeItem::body() const
return itemBody; return itemBody;
} }
QByteArray TreeItem::parsingData() const
{
return itemParsingData;
}
bool TreeItem::hasEmptyHeader() const bool TreeItem::hasEmptyHeader() const
{ {
return itemHeader.isEmpty(); return itemHeader.isEmpty();
@ -199,16 +193,6 @@ bool TreeItem::hasEmptyBody() const
return itemBody.isEmpty(); return itemBody.isEmpty();
} }
bool TreeItem::hasEmptyParsingData() const
{
return itemParsingData.isEmpty();
}
void TreeItem::setParsingData(const QByteArray & data)
{
itemParsingData = data;
}
UINT8 TreeItem::action() const UINT8 TreeItem::action() const
{ {
return itemAction; return itemAction;

View File

@ -26,7 +26,7 @@ class TreeItem
public: public:
TreeItem(const UINT8 type, const UINT8 subtype = 0, const UINT8 compression = COMPRESSION_ALGORITHM_NONE, TreeItem(const UINT8 type, const UINT8 subtype = 0, const UINT8 compression = COMPRESSION_ALGORITHM_NONE,
const QString &name = QString(), const QString &text = QString(), const QString &info = QString(), const QString &name = QString(), const QString &text = QString(), const QString &info = QString(),
const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(), const QByteArray & parsingData = QByteArray(), const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(),
TreeItem *parent = 0); TreeItem *parent = 0);
~TreeItem(); ~TreeItem();
@ -63,10 +63,6 @@ public:
QByteArray body() const; QByteArray body() const;
bool hasEmptyBody() const; bool hasEmptyBody() const;
QByteArray parsingData() const;
bool hasEmptyParsingData() const;
void setParsingData(const QByteArray & data);
QString info() const; QString info() const;
void addInfo(const QString &info); void addInfo(const QString &info);
void setInfo(const QString &info); void setInfo(const QString &info);
@ -87,7 +83,6 @@ private:
QString itemInfo; QString itemInfo;
QByteArray itemHeader; QByteArray itemHeader;
QByteArray itemBody; QByteArray itemBody;
QByteArray itemParsingData;
TreeItem *parentItem; TreeItem *parentItem;
}; };

View File

@ -178,22 +178,6 @@ bool TreeModel::hasEmptyBody(const QModelIndex &index) const
return item->hasEmptyBody(); return item->hasEmptyBody();
} }
QByteArray TreeModel::parsingData(const QModelIndex &index) const
{
if (!index.isValid())
return QByteArray();
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item->parsingData();
}
bool TreeModel::hasEmptyParsingData(const QModelIndex &index) const
{
if (!index.isValid())
return true;
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item->hasEmptyParsingData();
}
QString TreeModel::name(const QModelIndex &index) const QString TreeModel::name(const QModelIndex &index) const
{ {
if (!index.isValid()) if (!index.isValid())
@ -284,20 +268,9 @@ void TreeModel::setAction(const QModelIndex &index, const UINT8 action)
emit dataChanged(this->index(0, 0), index); emit dataChanged(this->index(0, 0), index);
} }
void TreeModel::setParsingData(const QModelIndex &index, const QByteArray &data)
{
if (!index.isValid())
return;
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
item->setParsingData(data);
emit dataChanged(this->index(0, 0), index);
}
QModelIndex TreeModel::addItem(const UINT8 type, const UINT8 subtype, const UINT8 compression, QModelIndex TreeModel::addItem(const UINT8 type, const UINT8 subtype, const UINT8 compression,
const QString & name, const QString & text, const QString & info, const QString & name, const QString & text, const QString & info,
const QByteArray & header, const QByteArray & body, const QByteArray & parsingData, const QByteArray & header, const QByteArray & body, const QModelIndex & parent, const UINT8 mode)
const QModelIndex & parent, const UINT8 mode)
{ {
TreeItem *item = 0; TreeItem *item = 0;
TreeItem *parentItem = 0; TreeItem *parentItem = 0;
@ -318,7 +291,7 @@ QModelIndex TreeModel::addItem(const UINT8 type, const UINT8 subtype, const UINT
} }
} }
TreeItem *newItem = new TreeItem(type, subtype, compression, name, text, info, header, body, parsingData, parentItem); TreeItem *newItem = new TreeItem(type, subtype, compression, name, text, info, header, body, parentItem);
if (mode == CREATE_MODE_APPEND) { if (mode == CREATE_MODE_APPEND) {
emit layoutAboutToBeChanged(); emit layoutAboutToBeChanged();
parentItem->appendChild(newItem); parentItem->appendChild(newItem);

View File

@ -65,7 +65,7 @@ public:
QModelIndex addItem(const UINT8 type, const UINT8 subtype = 0, const UINT8 compression = COMPRESSION_ALGORITHM_NONE, QModelIndex addItem(const UINT8 type, const UINT8 subtype = 0, const UINT8 compression = COMPRESSION_ALGORITHM_NONE,
const QString & name = QString(), const QString & text = QString(), const QString & info = QString(), const QString & name = QString(), const QString & text = QString(), const QString & info = QString(),
const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(), const QByteArray & parsingData = QByteArray(), const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(),
const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND); const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND);
QModelIndex findParentOfType(const QModelIndex & index, UINT8 type) const; QModelIndex findParentOfType(const QModelIndex & index, UINT8 type) const;

21
types.h
View File

@ -85,25 +85,4 @@ extern QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype);
extern QString compressionTypeToQString(const UINT8 algorithm); extern QString compressionTypeToQString(const UINT8 algorithm);
extern QString regionTypeToQString(const UINT8 type); extern QString regionTypeToQString(const UINT8 type);
enum ParsingDataTypes {
UnknownParsingData,
VolumeParsingData,
FileParsingData
};
typedef union _PARSING_DATA_UNION {
struct _PARSING_DATA_UNION_VOLUME {
bool HasZeroVectorCRC;
} Volume;
struct _PARSING_DATA_UNION_FILE {
UINT32 Offset;
} File;
} PARSING_DATA_UNION;
typedef struct _PARSING_DATA {
UINT8 Type;
PARSING_DATA_UNION Data;
} PARSING_DATA;
#endif #endif

View File

@ -17,7 +17,7 @@
UEFITool::UEFITool(QWidget *parent) : UEFITool::UEFITool(QWidget *parent) :
QMainWindow(parent), QMainWindow(parent),
ui(new Ui::UEFITool), ui(new Ui::UEFITool),
version(tr("0.20.5")) version(tr("0.20.6"))
{ {
clipboard = QApplication::clipboard(); clipboard = QApplication::clipboard();