Version 0.2.0

Initial public commit
This commit is contained in:
Nikolaj Schlej 2013-10-08 09:07:03 +02:00
commit 4afe74850d
46 changed files with 13817 additions and 0 deletions

22
.gitattributes vendored Normal file
View file

@ -0,0 +1,22 @@
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

215
.gitignore vendored Normal file
View file

@ -0,0 +1,215 @@
#################
## Eclipse
#################
*.pydevproject
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
x64/
build/
[Bb]in/
[Oo]bj/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.log
*.scc
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
*.ncrunch*
.*crunch*.local.xml
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.Publish.xml
*.pubxml
# NuGet Packages Directory
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
#packages/
# Windows Azure Build Output
csx
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.[Pp]ublish.xml
*.pfx
*.publishsettings
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
App_Data/*.mdf
App_Data/*.ldf
#############
## Windows detritus
#############
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Mac crap
.DS_Store
#############
## Python
#############
*.py[co]
# Packages
*.egg
*.egg-info
dist/
build/
eggs/
parts/
var/
sdist/
develop-eggs/
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg

BIN
LZMA/._LzmaCompress.c Normal file

Binary file not shown.

BIN
LZMA/._LzmaCompress.h Normal file

Binary file not shown.

110
LZMA/LzmaCompress.c Normal file
View file

@ -0,0 +1,110 @@
/* LZMA Compress Implementation
Copyright (c) 2012, 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 "LzmaCompress.h"
#include "Sdk/C/7zVersion.h"
#include "Sdk/C/LzmaEnc.h"
#include <stdlib.h>
#define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + 8)
static void * AllocForLzma(void *p, size_t size) { return malloc(size); }
static void FreeForLzma(void *p, void *address) { free(address); }
static ISzAlloc SzAllocForLzma = { &AllocForLzma, &FreeForLzma };
SRes OnProgress(void *p, UInt64 inSize, UInt64 outSize)
{
return SZ_OK;
}
static ICompressProgress g_ProgressCallback = { &OnProgress };
STATIC
UINT64
EFIAPI
RShiftU64 (
UINT64 Operand,
UINT32 Count
)
{
return Operand >> Count;
}
VOID
SetEncodedSizeOfBuf(
UINT64 EncodedSize,
UINT8 *EncodedData
)
{
INT32 Index;
EncodedData[LZMA_PROPS_SIZE] = EncodedSize & 0xFF;
for (Index = LZMA_PROPS_SIZE+1; Index <= LZMA_PROPS_SIZE + 7; Index++)
{
EncodedSize = RShiftU64(EncodedSize, 8);
EncodedData[Index] = EncodedSize & 0xFF;
}
}
INT32
EFIAPI
LzmaCompress (
CONST VOID *Source,
SizeT SourceSize,
VOID *Destination,
SizeT *DestinationSize
)
{
SRes LzmaResult;
CLzmaEncProps props;
SizeT propsSize = LZMA_PROPS_SIZE;
SizeT destLen = SourceSize + SourceSize / 3 + 128;
if (*DestinationSize < destLen)
{
*DestinationSize = destLen;
return ERR_BUFFER_TOO_SMALL;
}
LzmaEncProps_Init(&props);
props.dictSize = LZMA_DICTIONARY_SIZE;
props.level = 9;
props.fb = 273;
LzmaResult = LzmaEncode(
(Byte*)((UINT8*)Destination + LZMA_HEADER_SIZE),
&destLen,
Source,
SourceSize,
&props,
(UINT8*)Destination,
&propsSize,
props.writeEndMark,
&g_ProgressCallback,
&SzAllocForLzma,
&SzAllocForLzma);
*DestinationSize = destLen + LZMA_HEADER_SIZE;
SetEncodedSizeOfBuf((UINT64)SourceSize, Destination);
if (LzmaResult == SZ_OK) {
return ERR_SUCCESS;
} else {
return ERR_INVALID_PARAMETER;
}
}

39
LZMA/LzmaCompress.h Normal file
View file

@ -0,0 +1,39 @@
/* LZMA Compress Header
Copyright (c) 2012, 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 __LZMACOMPRESS_H__
#define __LZMACOMPRESS_H__
#include "Sdk/C/Types.h"
#include "../basetypes.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LZMA_DICTIONARY_SIZE 0x800000
#define _LZMA_SIZE_OPT
INT32
EFIAPI
LzmaCompress (
const VOID *Source,
SizeT SourceSize,
VOID *Destination,
SizeT *DestinationSize
);
#ifdef __cplusplus
}
#endif
#endif

159
LZMA/LzmaDecompress.c Normal file
View file

@ -0,0 +1,159 @@
/* LZMA Decompress Implementation
Copyright (c) 2009 - 2010, Intel Corporation. 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 "LzmaDecompress.h"
#include "Sdk/C/Types.h"
#include "Sdk/C/7zVersion.h"
#include <stdlib.h>
UINT64
EFIAPI
LShiftU64 (
UINT64 Operand,
UINT32 Count
)
{
return Operand << Count;
}
static void * AllocForLzma(void *p, size_t size) { return malloc(size); }
static void FreeForLzma(void *p, void *address) { free(address); }
static ISzAlloc SzAllocForLzma = { &AllocForLzma, &FreeForLzma };
/*
Get the size of the uncompressed buffer by parsing EncodeData header.
@param EncodedData Pointer to the compressed data.
@return The size of the uncompressed buffer.
*/
UINT64
GetDecodedSizeOfBuf(
UINT8 *EncodedData
)
{
UINT64 DecodedSize;
INT32 Index;
// Parse header
DecodedSize = 0;
for (Index = LZMA_PROPS_SIZE + 7; Index >= LZMA_PROPS_SIZE; Index--)
DecodedSize = LShiftU64(DecodedSize, 8) + EncodedData[Index];
return DecodedSize;
}
//
// LZMA functions and data as defined local LzmaDecompressLibInternal.h
//
/*
Given a Lzma compressed source buffer, this function retrieves the size of
the uncompressed buffer and the size of the scratch buffer required
to decompress the compressed source buffer.
Retrieves the size of the uncompressed buffer and the temporary scratch buffer
required to decompress the buffer specified by Source and SourceSize.
The size of the uncompressed buffer is returned DestinationSize,
the size of the scratch buffer is returned ScratchSize, and RETURN_SUCCESS is returned.
This function does not have scratch buffer available to perform a thorough
checking of the validity of the source data. It just retrieves the "Original Size"
field from the LZMA_HEADER_SIZE beginning bytes of the source data and output it as DestinationSize.
And ScratchSize is specific to the decompression implementation.
If SourceSize is less than LZMA_HEADER_SIZE, then ASSERT().
@param Source The source buffer containing the compressed data.
@param SourceSize The size, bytes, of the source buffer.
@param DestinationSize A pointer to the size, bytes, of the uncompressed buffer
that will be generated when the compressed buffer specified
by Source and SourceSize is decompressed.
@retval EFI_SUCCESS The size of the uncompressed data was returned
DestinationSize and the size of the scratch
buffer was returned ScratchSize.
*/
INT32
EFIAPI
LzmaGetInfo (
CONST VOID *Source,
UINT32 SourceSize,
UINT32 *DestinationSize
)
{
UInt64 DecodedSize;
ASSERT(SourceSize >= LZMA_HEADER_SIZE);
DecodedSize = GetDecodedSizeOfBuf((UINT8*)Source);
*DestinationSize = (UINT32)DecodedSize;
return ERR_SUCCESS;
}
/*
Decompresses a Lzma compressed source buffer.
Extracts decompressed data to its original form.
If the compressed source data specified by Source is successfully decompressed
into Destination, then RETURN_SUCCESS is returned. If the compressed source data
specified by Source is not a valid compressed data format,
then RETURN_INVALID_PARAMETER is returned.
@param Source The source buffer containing the compressed data.
@param SourceSize The size of source buffer.
@param Destination The destination buffer to store the decompressed data
@retval EFI_SUCCESS Decompression completed successfully, and
the uncompressed buffer is returned Destination.
@retval EFI_INVALID_PARAMETER
The source buffer specified by Source is corrupted
(not a valid compressed format).
*/
INT32
EFIAPI
LzmaDecompress (
CONST VOID *Source,
UINT32 SourceSize,
VOID *Destination
)
{
SRes LzmaResult;
ELzmaStatus Status;
SizeT DecodedBufSize;
SizeT EncodedDataSize;
DecodedBufSize = (SizeT)GetDecodedSizeOfBuf((UINT8*)Source);
EncodedDataSize = (SizeT) (SourceSize - LZMA_HEADER_SIZE);
LzmaResult = LzmaDecode(
Destination,
&DecodedBufSize,
(Byte*)((UINT8*)Source + LZMA_HEADER_SIZE),
&EncodedDataSize,
Source,
LZMA_PROPS_SIZE,
LZMA_FINISH_END,
&Status,
&SzAllocForLzma
);
if (LzmaResult == SZ_OK) {
return ERR_SUCCESS;
} else {
return ERR_INVALID_PARAMETER;
}
}

99
LZMA/LzmaDecompress.h Normal file
View file

@ -0,0 +1,99 @@
/* LZMA Decompress Header
Copyright (c) 2009 - 2010, Intel Corporation. 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 __LZMADECOMPRESS_H__
#define __LZMADECOMPRESS_H__
#include "../basetypes.h"
#include "Sdk/C/LzmaDec.h"
#define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + 8)
#ifdef __cplusplus
extern "C" {
#endif
UINT64
EFIAPI
LShiftU64 (
UINT64 Operand,
UINT32 Count
);
/*
Given a Lzma compressed source buffer, this function retrieves the size of
the uncompressed buffer and the size of the scratch buffer required
to decompress the compressed source buffer.
Retrieves the size of the uncompressed buffer and the temporary scratch buffer
required to decompress the buffer specified by Source and SourceSize.
The size of the uncompressed buffer is returned DestinationSize,
the size of the scratch buffer is returned ScratchSize, and RETURN_SUCCESS is returned.
This function does not have scratch buffer available to perform a thorough
checking of the validity of the source data. It just retrieves the "Original Size"
field from the LZMA_HEADER_SIZE beginning bytes of the source data and output it as DestinationSize.
And ScratchSize is specific to the decompression implementation.
If SourceSize is less than LZMA_HEADER_SIZE, then ASSERT().
@param Source The source buffer containing the compressed data.
@param SourceSize The size, bytes, of the source buffer.
@param DestinationSize A pointer to the size, bytes, of the uncompressed buffer
that will be generated when the compressed buffer specified
by Source and SourceSize is decompressed.
@retval EFI_SUCCESS The size of the uncompressed data was returned
DestinationSize and the size of the scratch
buffer was returned ScratchSize.
*/
INT32
EFIAPI
LzmaGetInfo (
const VOID *Source,
UINT32 SourceSize,
UINT32 *DestinationSize
);
/*
Decompresses a Lzma compressed source buffer.
Extracts decompressed data to its original form.
If the compressed source data specified by Source is successfully decompressed
into Destination, then RETURN_SUCCESS is returned. If the compressed source data
specified by Source is not a valid compressed data format,
then RETURN_INVALID_PARAMETER is returned.
@param Source The source buffer containing the compressed data.
@param SourceSize The size of source buffer.
@param Destination The destination buffer to store the decompressed data
@retval EFI_SUCCESS Decompression completed successfully, and
the uncompressed buffer is returned Destination.
@retval EFI_INVALID_PARAMETER
The source buffer specified by Source is corrupted
(not a valid compressed format).
*/
INT32
EFIAPI
LzmaDecompress (
const VOID *Source,
UINT32 SourceSize,
VOID *Destination
);
#ifdef __cplusplus
}
#endif
#endif

7
LZMA/SDK/C/7zVersion.h Normal file
View file

@ -0,0 +1,7 @@
#define MY_VER_MAJOR 9
#define MY_VER_MINOR 20
#define MY_VER_BUILD 0
#define MY_VERSION "9.20"
#define MY_DATE "2010-11-18"
#define MY_COPYRIGHT ": Igor Pavlov : Public domain"
#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE

68
LZMA/SDK/C/Bra.h Normal file
View file

@ -0,0 +1,68 @@
/* Bra.h -- Branch converters for executables
2009-02-07 : Igor Pavlov : Public domain */
#ifndef __BRA_H
#define __BRA_H
#include "Types.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
These functions convert relative addresses to absolute addresses
in CALL instructions to increase the compression ratio.
In:
data - data buffer
size - size of data
ip - current virtual Instruction Pinter (IP) value
state - state variable for x86 converter
encoding - 0 (for decoding), 1 (for encoding)
Out:
state - state variable for x86 converter
Returns:
The number of processed bytes. If you call these functions with multiple calls,
you must start next call with first byte after block of processed bytes.
Type Endian Alignment LookAhead
x86 little 1 4
ARMT little 2 2
ARM little 4 0
PPC big 4 0
SPARC big 4 0
IA64 little 16 0
size must be >= Alignment + LookAhead, if it's not last block.
If (size < Alignment + LookAhead), converter returns 0.
Example:
UInt32 ip = 0;
for ()
{
; size must be >= Alignment + LookAhead, if it's not last block
SizeT processed = Convert(data, size, ip, 1);
data += processed;
size -= processed;
ip += processed;
}
*/
#define x86_Convert_Init(state) { state = 0; }
SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding);
SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
#ifdef __cplusplus
}
#endif
#endif

85
LZMA/SDK/C/Bra86.c Normal file
View file

@ -0,0 +1,85 @@
/* Bra86.c -- Converter for x86 code (BCJ)
2008-10-04 : Igor Pavlov : Public domain */
#include "Bra.h"
#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
const Byte kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};
SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding)
{
SizeT bufferPos = 0, prevPosT;
UInt32 prevMask = *state & 0x7;
if (size < 5)
return 0;
ip += 5;
prevPosT = (SizeT)0 - 1;
for (;;)
{
Byte *p = data + bufferPos;
Byte *limit = data + size - 4;
for (; p < limit; p++)
if ((*p & 0xFE) == 0xE8)
break;
bufferPos = (SizeT)(p - data);
if (p >= limit)
break;
prevPosT = bufferPos - prevPosT;
if (prevPosT > 3)
prevMask = 0;
else
{
prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;
if (prevMask != 0)
{
Byte b = p[4 - kMaskToBitNumber[prevMask]];
if (!kMaskToAllowedStatus[prevMask] || Test86MSByte(b))
{
prevPosT = bufferPos;
prevMask = ((prevMask << 1) & 0x7) | 1;
bufferPos++;
continue;
}
}
}
prevPosT = bufferPos;
if (Test86MSByte(p[4]))
{
UInt32 src = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]);
UInt32 dest;
for (;;)
{
Byte b;
int index;
if (encoding)
dest = (ip + (UInt32)bufferPos) + src;
else
dest = src - (ip + (UInt32)bufferPos);
if (prevMask == 0)
break;
index = kMaskToBitNumber[prevMask] * 8;
b = (Byte)(dest >> (24 - index));
if (!Test86MSByte(b))
break;
src = dest ^ ((1 << (32 - index)) - 1);
}
p[4] = (Byte)(~(((dest >> 24) & 1) - 1));
p[3] = (Byte)(dest >> 16);
p[2] = (Byte)(dest >> 8);
p[1] = (Byte)dest;
bufferPos += 5;
}
else
{
prevMask = ((prevMask << 1) & 0x7) | 1;
bufferPos++;
}
}
prevPosT = bufferPos - prevPosT;
*state = ((prevPosT > 3) ? 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7));
return bufferPos;
}

155
LZMA/SDK/C/CpuArch.h Normal file
View file

@ -0,0 +1,155 @@
/* CpuArch.h -- CPU specific code
2010-10-26: Igor Pavlov : Public domain */
#ifndef __CPU_ARCH_H
#define __CPU_ARCH_H
#include "Types.h"
EXTERN_C_BEGIN
/*
MY_CPU_LE means that CPU is LITTLE ENDIAN.
If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN).
MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform.
*/
#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__)
#define MY_CPU_AMD64
#endif
#if defined(MY_CPU_AMD64) || defined(_M_IA64)
#define MY_CPU_64BIT
#endif
#if defined(_M_IX86) || defined(__i386__)
#define MY_CPU_X86
#endif
#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
#define MY_CPU_X86_OR_AMD64
#endif
#if defined(MY_CPU_X86) || defined(_M_ARM)
#define MY_CPU_32BIT
#endif
#if defined(_WIN32) && defined(_M_ARM)
#define MY_CPU_ARM_LE
#endif
#if defined(_WIN32) && defined(_M_IA64)
#define MY_CPU_IA64_LE
#endif
#if defined(MY_CPU_X86_OR_AMD64)
#define MY_CPU_LE_UNALIGN
#endif
#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__)
#define MY_CPU_LE
#endif
#if defined(__BIG_ENDIAN__)
#define MY_CPU_BE
#endif
#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
Stop_Compiling_Bad_Endian
#endif
#ifdef MY_CPU_LE_UNALIGN
#define GetUi16(p) (*(const UInt16 *)(p))
#define GetUi32(p) (*(const UInt32 *)(p))
#define GetUi64(p) (*(const UInt64 *)(p))
#define SetUi16(p, d) *(UInt16 *)(p) = (d);
#define SetUi32(p, d) *(UInt32 *)(p) = (d);
#define SetUi64(p, d) *(UInt64 *)(p) = (d);
#else
#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8))
#define GetUi32(p) ( \
((const Byte *)(p))[0] | \
((UInt32)((const Byte *)(p))[1] << 8) | \
((UInt32)((const Byte *)(p))[2] << 16) | \
((UInt32)((const Byte *)(p))[3] << 24))
#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
#define SetUi16(p, d) { UInt32 _x_ = (d); \
((Byte *)(p))[0] = (Byte)_x_; \
((Byte *)(p))[1] = (Byte)(_x_ >> 8); }
#define SetUi32(p, d) { UInt32 _x_ = (d); \
((Byte *)(p))[0] = (Byte)_x_; \
((Byte *)(p))[1] = (Byte)(_x_ >> 8); \
((Byte *)(p))[2] = (Byte)(_x_ >> 16); \
((Byte *)(p))[3] = (Byte)(_x_ >> 24); }
#define SetUi64(p, d) { UInt64 _x64_ = (d); \
SetUi32(p, (UInt32)_x64_); \
SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); }
#endif
#if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300)
#pragma intrinsic(_byteswap_ulong)
#pragma intrinsic(_byteswap_uint64)
#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p))
#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p))
#else
#define GetBe32(p) ( \
((UInt32)((const Byte *)(p))[0] << 24) | \
((UInt32)((const Byte *)(p))[1] << 16) | \
((UInt32)((const Byte *)(p))[2] << 8) | \
((const Byte *)(p))[3] )
#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
#endif
#define GetBe16(p) (((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1])
#ifdef MY_CPU_X86_OR_AMD64
typedef struct
{
UInt32 maxFunc;
UInt32 vendor[3];
UInt32 ver;
UInt32 b;
UInt32 c;
UInt32 d;
} Cx86cpuid;
enum
{
CPU_FIRM_INTEL,
CPU_FIRM_AMD,
CPU_FIRM_VIA
};
Bool x86cpuid_CheckAndRead(Cx86cpuid *p);
int x86cpuid_GetFirm(const Cx86cpuid *p);
#define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F)
#define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F)
#define x86cpuid_GetStepping(p) ((p)->ver & 0xF)
Bool CPU_Is_InOrder();
Bool CPU_Is_Aes_Supported();
#endif
EXTERN_C_END
#endif

761
LZMA/SDK/C/LzFind.c Normal file
View file

@ -0,0 +1,761 @@
/* LzFind.c -- Match finder for LZ algorithms
2009-04-22 : Igor Pavlov : Public doma*/
#include <string.h>
#include "LzFind.h"
#include "LzHash.h"
#define kEmptyHashValue 0
#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
#define kNormalizeMask (~(kNormalizeStepMin - 1))
#define kMaxHistorySize ((UInt32)3 << 30)
#define kStartMaxLen 3
static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
{
if (!p->directInput)
{
alloc->Free(alloc, p->bufferBase);
p->bufferBase = 0;
}
}
/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
{
UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
if (p->directInput)
{
p->blockSize = blockSize;
return 1;
}
if (p->bufferBase == 0 || p->blockSize != blockSize)
{
LzInWindow_Free(p, alloc);
p->blockSize = blockSize;
p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize);
}
return (p->bufferBase != 0);
}
Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
{
p->posLimit -= subValue;
p->pos -= subValue;
p->streamPos -= subValue;
}
static void MatchFinder_ReadBlock(CMatchFinder *p)
{
if (p->streamEndWasReached || p->result != SZ_OK)
return;
if (p->directInput)
{
UInt32 curSize = 0xFFFFFFFF - p->streamPos;
if (curSize > p->directInputRem)
curSize = (UInt32)p->directInputRem;
p->directInputRem -= curSize;
p->streamPos += curSize;
if (p->directInputRem == 0)
p->streamEndWasReached = 1;
return;
}
for (;;)
{
Byte *dest = p->buffer + (p->streamPos - p->pos);
size_t size = (p->bufferBase + p->blockSize - dest);
if (size == 0)
return;
p->result = p->stream->Read(p->stream, dest, &size);
if (p->result != SZ_OK)
return;
if (size == 0)
{
p->streamEndWasReached = 1;
return;
}
p->streamPos += (UInt32)size;
if (p->streamPos - p->pos > p->keepSizeAfter)
return;
}
}
void MatchFinder_MoveBlock(CMatchFinder *p)
{
memmove(p->bufferBase,
p->buffer - p->keepSizeBefore,
(size_t)(p->streamPos - p->pos + p->keepSizeBefore));
p->buffer = p->bufferBase + p->keepSizeBefore;
}
int MatchFinder_NeedMove(CMatchFinder *p)
{
if (p->directInput)
return 0;
/* if (p->streamEndWasReached) return 0; */
return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
}
void MatchFinder_ReadIfRequired(CMatchFinder *p)
{
if (p->streamEndWasReached)
return;
if (p->keepSizeAfter >= p->streamPos - p->pos)
MatchFinder_ReadBlock(p);
}
static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
{
if (MatchFinder_NeedMove(p))
MatchFinder_MoveBlock(p);
MatchFinder_ReadBlock(p);
}
static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
{
p->cutValue = 32;
p->btMode = 1;
p->numHashBytes = 4;
p->bigHash = 0;
}
#define kCrcPoly 0xEDB88320
void MatchFinder_Construct(CMatchFinder *p)
{
UInt32 i;
p->bufferBase = 0;
p->directInput = 0;
p->hash = 0;
MatchFinder_SetDefaultSettings(p);
for (i = 0; i < 256; i++)
{
UInt32 r = i;
int j;
for (j = 0; j < 8; j++)
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
p->crc[i] = r;
}
}
static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
{
alloc->Free(alloc, p->hash);
p->hash = 0;
}
void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
{
MatchFinder_FreeThisClassMemory(p, alloc);
LzInWindow_Free(p, alloc);
}
static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
{
size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
if (sizeInBytes / sizeof(CLzRef) != num)
return 0;
return (CLzRef *)alloc->Alloc(alloc, sizeInBytes);
}
int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
ISzAlloc *alloc)
{
UInt32 sizeReserv;
if (historySize > kMaxHistorySize)
{
MatchFinder_Free(p, alloc);
return 0;
}
sizeReserv = historySize >> 1;
if (historySize > ((UInt32)2 << 30))
sizeReserv = historySize >> 2;
sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
/* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
if (LzInWindow_Create(p, sizeReserv, alloc))
{
UInt32 newCyclicBufferSize = historySize + 1;
UInt32 hs;
p->matchMaxLen = matchMaxLen;
{
p->fixedHashSize = 0;
if (p->numHashBytes == 2)
hs = (1 << 16) - 1;
else
{
hs = historySize - 1;
hs |= (hs >> 1);
hs |= (hs >> 2);
hs |= (hs >> 4);
hs |= (hs >> 8);
hs >>= 1;
hs |= 0xFFFF; /* don't change it! It's required for Deflate */
if (hs > (1 << 24))
{
if (p->numHashBytes == 3)
hs = (1 << 24) - 1;
else
hs >>= 1;
}
}
p->hashMask = hs;
hs++;
if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
hs += p->fixedHashSize;
}
{
UInt32 prevSize = p->hashSizeSum + p->numSons;
UInt32 newSize;
p->historySize = historySize;
p->hashSizeSum = hs;
p->cyclicBufferSize = newCyclicBufferSize;
p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
newSize = p->hashSizeSum + p->numSons;
if (p->hash != 0 && prevSize == newSize)
return 1;
MatchFinder_FreeThisClassMemory(p, alloc);
p->hash = AllocRefs(newSize, alloc);
if (p->hash != 0)
{
p->son = p->hash + p->hashSizeSum;
return 1;
}
}
}
MatchFinder_Free(p, alloc);
return 0;
}
static void MatchFinder_SetLimits(CMatchFinder *p)
{
UInt32 limit = kMaxValForNormalize - p->pos;
UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
if (limit2 < limit)
limit = limit2;
limit2 = p->streamPos - p->pos;
if (limit2 <= p->keepSizeAfter)
{
if (limit2 > 0)
limit2 = 1;
}
else
limit2 -= p->keepSizeAfter;
if (limit2 < limit)
limit = limit2;
{
UInt32 lenLimit = p->streamPos - p->pos;
if (lenLimit > p->matchMaxLen)
lenLimit = p->matchMaxLen;
p->lenLimit = lenLimit;
}
p->posLimit = p->pos + limit;
}
void MatchFinder_Init(CMatchFinder *p)
{
UInt32 i;
for (i = 0; i < p->hashSizeSum; i++)
p->hash[i] = kEmptyHashValue;
p->cyclicBufferPos = 0;
p->buffer = p->bufferBase;
p->pos = p->streamPos = p->cyclicBufferSize;
p->result = SZ_OK;
p->streamEndWasReached = 0;
MatchFinder_ReadBlock(p);
MatchFinder_SetLimits(p);
}
static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
{
return (p->pos - p->historySize - 1) & kNormalizeMask;
}
void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
{
UInt32 i;
for (i = 0; i < numItems; i++)
{
UInt32 value = items[i];
if (value <= subValue)
value = kEmptyHashValue;
else
value -= subValue;
items[i] = value;
}
}
static void MatchFinder_Normalize(CMatchFinder *p)
{
UInt32 subValue = MatchFinder_GetSubValue(p);
MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
MatchFinder_ReduceOffsets(p, subValue);
}
static void MatchFinder_CheckLimits(CMatchFinder *p)
{
if (p->pos == kMaxValForNormalize)
MatchFinder_Normalize(p);
if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
MatchFinder_CheckAndMoveAndRead(p);
if (p->cyclicBufferPos == p->cyclicBufferSize)
p->cyclicBufferPos = 0;
MatchFinder_SetLimits(p);
}
static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
UInt32 *distances, UInt32 maxLen)
{
son[_cyclicBufferPos] = curMatch;
for (;;)
{
UInt32 delta = pos - curMatch;
if (cutValue-- == 0 || delta >= _cyclicBufferSize)
return distances;
{
const Byte *pb = cur - delta;
curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
if (pb[maxLen] == cur[maxLen] && *pb == *cur)
{
UInt32 len = 0;
while (++len != lenLimit)
if (pb[len] != cur[len])
break;
if (maxLen < len)
{
*distances++ = maxLen = len;
*distances++ = delta - 1;
if (len == lenLimit)
return distances;
}
}
}
}
}
UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
UInt32 *distances, UInt32 maxLen)
{
CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
UInt32 len0 = 0, len1 = 0;
for (;;)
{
UInt32 delta = pos - curMatch;
if (cutValue-- == 0 || delta >= _cyclicBufferSize)
{
*ptr0 = *ptr1 = kEmptyHashValue;
return distances;
}
{
CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
const Byte *pb = cur - delta;
UInt32 len = (len0 < len1 ? len0 : len1);
if (pb[len] == cur[len])
{
if (++len != lenLimit && pb[len] == cur[len])
while (++len != lenLimit)
if (pb[len] != cur[len])
break;
if (maxLen < len)
{
*distances++ = maxLen = len;
*distances++ = delta - 1;
if (len == lenLimit)
{
*ptr1 = pair[0];
*ptr0 = pair[1];
return distances;
}
}
}
if (pb[len] < cur[len])
{
*ptr1 = curMatch;
ptr1 = pair + 1;
curMatch = *ptr1;
len1 = len;
}
else
{
*ptr0 = curMatch;
ptr0 = pair;
curMatch = *ptr0;
len0 = len;
}
}
}
}
static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
{
CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
UInt32 len0 = 0, len1 = 0;
for (;;)
{
UInt32 delta = pos - curMatch;
if (cutValue-- == 0 || delta >= _cyclicBufferSize)
{
*ptr0 = *ptr1 = kEmptyHashValue;
return;
}
{
CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
const Byte *pb = cur - delta;
UInt32 len = (len0 < len1 ? len0 : len1);
if (pb[len] == cur[len])
{
while (++len != lenLimit)
if (pb[len] != cur[len])
break;
{
if (len == lenLimit)
{
*ptr1 = pair[0];
*ptr0 = pair[1];
return;
}
}
}
if (pb[len] < cur[len])
{
*ptr1 = curMatch;
ptr1 = pair + 1;
curMatch = *ptr1;
len1 = len;
}
else
{
*ptr0 = curMatch;
ptr0 = pair;
curMatch = *ptr0;
len0 = len;
}
}
}
}
#define MOVE_POS \
++p->cyclicBufferPos; \
p->buffer++; \
if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
#define MOVE_POS_RET MOVE_POS return offset;
static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
#define GET_MATCHES_HEADER2(minLen, ret_op) \
UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
cur = p->buffer;
#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue)
#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
#define GET_MATCHES_FOOTER(offset, maxLen) \
offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
distances + offset, maxLen) - distances); MOVE_POS_RET;
#define SKIP_FOOTER \
SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
{
UInt32 offset;
GET_MATCHES_HEADER(2)
HASH2_CALC;
curMatch = p->hash[hashValue];
p->hash[hashValue] = p->pos;
offset = 0;
GET_MATCHES_FOOTER(offset, 1)
}
UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
{
UInt32 offset;
GET_MATCHES_HEADER(3)
HASH_ZIP_CALC;
curMatch = p->hash[hashValue];
p->hash[hashValue] = p->pos;
offset = 0;
GET_MATCHES_FOOTER(offset, 2)
}
static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
{
UInt32 hash2Value, delta2, maxLen, offset;
GET_MATCHES_HEADER(3)
HASH3_CALC;
delta2 = p->pos - p->hash[hash2Value];
curMatch = p->hash[kFix3HashSize + hashValue];
p->hash[hash2Value] =
p->hash[kFix3HashSize + hashValue] = p->pos;
maxLen = 2;
offset = 0;
if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
{
for (; maxLen != lenLimit; maxLen++)
if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
break;
distances[0] = maxLen;
distances[1] = delta2 - 1;
offset = 2;
if (maxLen == lenLimit)
{
SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
MOVE_POS_RET;
}
}
GET_MATCHES_FOOTER(offset, maxLen)
}
static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
{
UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
GET_MATCHES_HEADER(4)
HASH4_CALC;
delta2 = p->pos - p->hash[ hash2Value];
delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
curMatch = p->hash[kFix4HashSize + hashValue];
p->hash[ hash2Value] =
p->hash[kFix3HashSize + hash3Value] =
p->hash[kFix4HashSize + hashValue] = p->pos;
maxLen = 1;
offset = 0;
if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
{
distances[0] = maxLen = 2;
distances[1] = delta2 - 1;
offset = 2;
}
if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
{
maxLen = 3;
distances[offset + 1] = delta3 - 1;
offset += 2;
delta2 = delta3;
}
if (offset != 0)
{
for (; maxLen != lenLimit; maxLen++)
if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
break;
distances[offset - 2] = maxLen;
if (maxLen == lenLimit)
{
SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
MOVE_POS_RET;
}
}
if (maxLen < 3)
maxLen = 3;
GET_MATCHES_FOOTER(offset, maxLen)
}
static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
{
UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
GET_MATCHES_HEADER(4)
HASH4_CALC;
delta2 = p->pos - p->hash[ hash2Value];
delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
curMatch = p->hash[kFix4HashSize + hashValue];
p->hash[ hash2Value] =
p->hash[kFix3HashSize + hash3Value] =
p->hash[kFix4HashSize + hashValue] = p->pos;
maxLen = 1;
offset = 0;
if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
{
distances[0] = maxLen = 2;
distances[1] = delta2 - 1;
offset = 2;
}
if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
{
maxLen = 3;
distances[offset + 1] = delta3 - 1;
offset += 2;
delta2 = delta3;
}
if (offset != 0)
{
for (; maxLen != lenLimit; maxLen++)
if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
break;
distances[offset - 2] = maxLen;
if (maxLen == lenLimit)
{
p->son[p->cyclicBufferPos] = curMatch;
MOVE_POS_RET;
}
}
if (maxLen < 3)
maxLen = 3;
offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
distances + offset, maxLen) - (distances));
MOVE_POS_RET
}
UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
{
UInt32 offset;
GET_MATCHES_HEADER(3)
HASH_ZIP_CALC;
curMatch = p->hash[hashValue];
p->hash[hashValue] = p->pos;
offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
distances, 2) - (distances));
MOVE_POS_RET
}
static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
{
do
{
SKIP_HEADER(2)
HASH2_CALC;
curMatch = p->hash[hashValue];
p->hash[hashValue] = p->pos;
SKIP_FOOTER
}
while (--num != 0);
}
void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
{
do
{
SKIP_HEADER(3)
HASH_ZIP_CALC;
curMatch = p->hash[hashValue];
p->hash[hashValue] = p->pos;
SKIP_FOOTER
}
while (--num != 0);
}
static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
{
do
{
UInt32 hash2Value;
SKIP_HEADER(3)
HASH3_CALC;
curMatch = p->hash[kFix3HashSize + hashValue];
p->hash[hash2Value] =
p->hash[kFix3HashSize + hashValue] = p->pos;
SKIP_FOOTER
}
while (--num != 0);
}
static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
{
do
{
UInt32 hash2Value, hash3Value;
SKIP_HEADER(4)
HASH4_CALC;
curMatch = p->hash[kFix4HashSize + hashValue];
p->hash[ hash2Value] =
p->hash[kFix3HashSize + hash3Value] = p->pos;
p->hash[kFix4HashSize + hashValue] = p->pos;
SKIP_FOOTER
}
while (--num != 0);
}
static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
{
do
{
UInt32 hash2Value, hash3Value;
SKIP_HEADER(4)
HASH4_CALC;
curMatch = p->hash[kFix4HashSize + hashValue];
p->hash[ hash2Value] =
p->hash[kFix3HashSize + hash3Value] =
p->hash[kFix4HashSize + hashValue] = p->pos;
p->son[p->cyclicBufferPos] = curMatch;
MOVE_POS
}
while (--num != 0);
}
void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
{
do
{
SKIP_HEADER(3)
HASH_ZIP_CALC;
curMatch = p->hash[hashValue];
p->hash[hashValue] = p->pos;
p->son[p->cyclicBufferPos] = curMatch;
MOVE_POS
}
while (--num != 0);
}
void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
{
vTable->Init = (Mf_Init_Func)MatchFinder_Init;
vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
if (!p->btMode)
{
vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
}
else if (p->numHashBytes == 2)
{
vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
}
else if (p->numHashBytes == 3)
{
vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
}
else
{
vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
}
}

115
LZMA/SDK/C/LzFind.h Normal file
View file

@ -0,0 +1,115 @@
/* LzFind.h -- Match finder for LZ algorithms
2009-04-22 : Igor Pavlov : Public domain */
#ifndef __LZ_FIND_H
#define __LZ_FIND_H
#include "Types.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef UInt32 CLzRef;
typedef struct _CMatchFinder
{
Byte *buffer;
UInt32 pos;
UInt32 posLimit;
UInt32 streamPos;
UInt32 lenLimit;
UInt32 cyclicBufferPos;
UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
UInt32 matchMaxLen;
CLzRef *hash;
CLzRef *son;
UInt32 hashMask;
UInt32 cutValue;
Byte *bufferBase;
ISeqInStream *stream;
int streamEndWasReached;
UInt32 blockSize;
UInt32 keepSizeBefore;
UInt32 keepSizeAfter;
UInt32 numHashBytes;
int directInput;
size_t directInputRem;
int btMode;
int bigHash;
UInt32 historySize;
UInt32 fixedHashSize;
UInt32 hashSizeSum;
UInt32 numSons;
SRes result;
UInt32 crc[256];
} CMatchFinder;
#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
int MatchFinder_NeedMove(CMatchFinder *p);
Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
void MatchFinder_MoveBlock(CMatchFinder *p);
void MatchFinder_ReadIfRequired(CMatchFinder *p);
void MatchFinder_Construct(CMatchFinder *p);
/* Conditions:
historySize <= 3 GB
keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
*/
int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
ISzAlloc *alloc);
void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
UInt32 *distances, UInt32 maxLen);
/*
Conditions:
Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
*/
typedef void (*Mf_Init_Func)(void *object);
typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
typedef void (*Mf_Skip_Func)(void *object, UInt32);
typedef struct _IMatchFinder
{
Mf_Init_Func Init;
Mf_GetIndexByte_Func GetIndexByte;
Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
Mf_GetMatches_Func GetMatches;
Mf_Skip_Func Skip;
} IMatchFinder;
void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
void MatchFinder_Init(CMatchFinder *p);
UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
#ifdef __cplusplus
}
#endif
#endif

54
LZMA/SDK/C/LzHash.h Normal file
View file

@ -0,0 +1,54 @@
/* LzHash.h -- HASH functions for LZ algorithms
2009-02-07 : Igor Pavlov : Public domain */
#ifndef __LZ_HASH_H
#define __LZ_HASH_H
#define kHash2Size (1 << 10)
#define kHash3Size (1 << 16)
#define kHash4Size (1 << 20)
#define kFix3HashSize (kHash2Size)
#define kFix4HashSize (kHash2Size + kHash3Size)
#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
#define HASH3_CALC { \
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
hash2Value = temp & (kHash2Size - 1); \
hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
#define HASH4_CALC { \
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
hash2Value = temp & (kHash2Size - 1); \
hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
#define HASH5_CALC { \
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
hash2Value = temp & (kHash2Size - 1); \
hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \
hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \
hash4Value &= (kHash4Size - 1); }
/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
#define MT_HASH2_CALC \
hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
#define MT_HASH3_CALC { \
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
hash2Value = temp & (kHash2Size - 1); \
hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
#define MT_HASH4_CALC { \
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
hash2Value = temp & (kHash2Size - 1); \
hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
#endif

999
LZMA/SDK/C/LzmaDec.c Normal file
View file

@ -0,0 +1,999 @@
/* LzmaDec.c -- LZMA Decoder
2009-09-20 : Igor Pavlov : Public doma*/
#include "LzmaDec.h"
#include <string.h>
#define kNumTopBits 24
#define kTopValue ((UInt32)1 << kNumTopBits)
#define kNumBitModelTotalBits 11
#define kBitModelTotal (1 << kNumBitModelTotalBits)
#define kNumMoveBits 5
#define RC_INIT_SIZE 5
#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
{ UPDATE_0(p); i = (i + i); A0; } else \
{ UPDATE_1(p); i = (i + i) + 1; A1; }
#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;)
#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); }
#define TREE_DECODE(probs, limit, i) \
{ i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
/* #define _LZMA_SIZE_OPT */
#ifdef _LZMA_SIZE_OPT
#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
#else
#define TREE_6_DECODE(probs, i) \
{ i = 1; \
TREE_GET_BIT(probs, i); \
TREE_GET_BIT(probs, i); \
TREE_GET_BIT(probs, i); \
TREE_GET_BIT(probs, i); \
TREE_GET_BIT(probs, i); \
TREE_GET_BIT(probs, i); \
i -= 0x40; }
#endif
#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
#define UPDATE_0_CHECK range = bound;
#define UPDATE_1_CHECK range -= bound; code -= bound;
#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
{ UPDATE_0_CHECK; i = (i + i); A0; } else \
{ UPDATE_1_CHECK; i = (i + i) + 1; A1; }
#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
#define TREE_DECODE_CHECK(probs, limit, i) \
{ i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
#define kNumPosBitsMax 4
#define kNumPosStatesMax (1 << kNumPosBitsMax)
#define kLenNumLowBits 3
#define kLenNumLowSymbols (1 << kLenNumLowBits)
#define kLenNumMidBits 3
#define kLenNumMidSymbols (1 << kLenNumMidBits)
#define kLenNumHighBits 8
#define kLenNumHighSymbols (1 << kLenNumHighBits)
#define LenChoice 0
#define LenChoice2 (LenChoice + 1)
#define LenLow (LenChoice2 + 1)
#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
#define kNumStates 12
#define kNumLitStates 7
#define kStartPosModelIndex 4
#define kEndPosModelIndex 14
#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
#define kNumPosSlotBits 6
#define kNumLenToPosStates 4
#define kNumAlignBits 4
#define kAlignTableSize (1 << kNumAlignBits)
#define kMatchMinLen 2
#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
#define IsMatch 0
#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
#define IsRepG0 (IsRep + kNumStates)
#define IsRepG1 (IsRepG0 + kNumStates)
#define IsRepG2 (IsRepG1 + kNumStates)
#define IsRep0Long (IsRepG2 + kNumStates)
#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
#define LenCoder (Align + kAlignTableSize)
#define RepLenCoder (LenCoder + kNumLenProbs)
#define Literal (RepLenCoder + kNumLenProbs)
#define LZMA_BASE_SIZE 1846
#define LZMA_LIT_SIZE 768
#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
#if Literal != LZMA_BASE_SIZE
StopCompilingDueBUG
#endif
#define LZMA_DIC_MIN (1 << 12)
/* First LZMA-symbol is always decoded.
And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is withlast normalization
Out:
Result:
SZ_OK - OK
SZ_ERROR_DATA - Error
p->remainLen:
< kMatchSpecLenStart : normal remain
= kMatchSpecLenStart : finished
= kMatchSpecLenStart + 1 : Flush marker
= kMatchSpecLenStart + 2 : State Init Marker
*/
static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
{
CLzmaProb *probs = p->probs;
unsigned state = p->state;
UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1;
unsigned lc = p->prop.lc;
Byte *dic = p->dic;
SizeT dicBufSize = p->dicBufSize;
SizeT dicPos = p->dicPos;
UInt32 processedPos = p->processedPos;
UInt32 checkDicSize = p->checkDicSize;
unsigned len = 0;
const Byte *buf = p->buf;
UInt32 range = p->range;
UInt32 code = p->code;
do
{
CLzmaProb *prob;
UInt32 bound;
unsigned ttt;
unsigned posState = processedPos & pbMask;
prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
IF_BIT_0(prob)
{
unsigned symbol;
UPDATE_0(prob);
prob = probs + Literal;
if (checkDicSize != 0 || processedPos != 0)
prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) +
(dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
if (state < kNumLitStates)
{
state -= (state < 4) ? state : 3;
symbol = 1;
do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
}
else
{
unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
unsigned offs = 0x100;
state -= (state < 10) ? 3 : 6;
symbol = 1;
do
{
unsigned bit;
CLzmaProb *probLit;
matchByte <<= 1;
bit = (matchByte & offs);
probLit = prob + offs + bit + symbol;
GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
}
while (symbol < 0x100);
}
dic[dicPos++] = (Byte)symbol;
processedPos++;
continue;
}
else
{
UPDATE_1(prob);
prob = probs + IsRep + state;
IF_BIT_0(prob)
{
UPDATE_0(prob);
state += kNumStates;
prob = probs + LenCoder;
}
else
{
UPDATE_1(prob);
if (checkDicSize == 0 && processedPos == 0)
return SZ_ERROR_DATA;
prob = probs + IsRepG0 + state;
IF_BIT_0(prob)
{
UPDATE_0(prob);
prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
IF_BIT_0(prob)
{
UPDATE_0(prob);
dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
dicPos++;
processedPos++;
state = state < kNumLitStates ? 9 : 11;
continue;
}
UPDATE_1(prob);
}
else
{
UInt32 distance;
UPDATE_1(prob);
prob = probs + IsRepG1 + state;
IF_BIT_0(prob)
{
UPDATE_0(prob);
distance = rep1;
}
else
{
UPDATE_1(prob);
prob = probs + IsRepG2 + state;
IF_BIT_0(prob)
{
UPDATE_0(prob);
distance = rep2;
}
else
{
UPDATE_1(prob);
distance = rep3;
rep3 = rep2;
}
rep2 = rep1;
}
rep1 = rep0;
rep0 = distance;
}
state = state < kNumLitStates ? 8 : 11;
prob = probs + RepLenCoder;
}
{
unsigned limit, offset;
CLzmaProb *probLen = prob + LenChoice;
IF_BIT_0(probLen)
{
UPDATE_0(probLen);
probLen = prob + LenLow + (posState << kLenNumLowBits);
offset = 0;
limit = (1 << kLenNumLowBits);
}
else
{
UPDATE_1(probLen);
probLen = prob + LenChoice2;
IF_BIT_0(probLen)
{
UPDATE_0(probLen);
probLen = prob + LenMid + (posState << kLenNumMidBits);
offset = kLenNumLowSymbols;
limit = (1 << kLenNumMidBits);
}
else
{
UPDATE_1(probLen);
probLen = prob + LenHigh;
offset = kLenNumLowSymbols + kLenNumMidSymbols;
limit = (1 << kLenNumHighBits);
}
}
TREE_DECODE(probLen, limit, len);
len += offset;
}
if (state >= kNumStates)
{
UInt32 distance;
prob = probs + PosSlot +
((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
TREE_6_DECODE(prob, distance);
if (distance >= kStartPosModelIndex)
{
unsigned posSlot = (unsigned)distance;
int numDirectBits = (int)(((distance >> 1) - 1));
distance = (2 | (distance & 1));
if (posSlot < kEndPosModelIndex)
{
distance <<= numDirectBits;
prob = probs + SpecPos + distance - posSlot - 1;
{
UInt32 mask = 1;
unsigned i = 1;
do
{
GET_BIT2(prob + i, i, ; , distance |= mask);
mask <<= 1;
}
while (--numDirectBits != 0);
}
}
else
{
numDirectBits -= kNumAlignBits;
do
{
NORMALIZE
range >>= 1;
{
UInt32 t;
code -= range;
t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
distance = (distance << 1) + (t + 1);
code += range & t;
}
/*
distance <<= 1;
if (code >= range)
{
code -= range;
distance |= 1;
}
*/
}
while (--numDirectBits != 0);
prob = probs + Align;
distance <<= kNumAlignBits;
{
unsigned i = 1;
GET_BIT2(prob + i, i, ; , distance |= 1);
GET_BIT2(prob + i, i, ; , distance |= 2);
GET_BIT2(prob + i, i, ; , distance |= 4);
GET_BIT2(prob + i, i, ; , distance |= 8);
}
if (distance == (UInt32)0xFFFFFFFF)
{
len += kMatchSpecLenStart;
state -= kNumStates;
break;
}
}
}
rep3 = rep2;
rep2 = rep1;
rep1 = rep0;
rep0 = distance + 1;
if (checkDicSize == 0)
{
if (distance >= processedPos)
return SZ_ERROR_DATA;
}
else if (distance >= checkDicSize)
return SZ_ERROR_DATA;
state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
}
len += kMatchMinLen;
if (limit == dicPos)
return SZ_ERROR_DATA;
{
SizeT rem = limit - dicPos;
unsigned curLen = ((rem < len) ? (unsigned)rem : len);
SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0);
processedPos += curLen;
len -= curLen;
if (pos + curLen <= dicBufSize)
{
Byte *dest = dic + dicPos;
ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
const Byte *lim = dest + curLen;
dicPos += curLen;
do
*(dest) = (Byte)*(dest + src);
while (++dest != lim);
}
else
{
do
{
dic[dicPos++] = dic[pos];
if (++pos == dicBufSize)
pos = 0;
}
while (--curLen != 0);
}
}
}
}
while (dicPos < limit && buf < bufLimit);
NORMALIZE;
p->buf = buf;
p->range = range;
p->code = code;
p->remainLen = len;
p->dicPos = dicPos;
p->processedPos = processedPos;
p->reps[0] = rep0;
p->reps[1] = rep1;
p->reps[2] = rep2;
p->reps[3] = rep3;
p->state = state;
return SZ_OK;
}
static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
{
if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
{
Byte *dic = p->dic;
SizeT dicPos = p->dicPos;
SizeT dicBufSize = p->dicBufSize;
unsigned len = p->remainLen;
UInt32 rep0 = p->reps[0];
if (limit - dicPos < len)
len = (unsigned)(limit - dicPos);
if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
p->checkDicSize = p->prop.dicSize;
p->processedPos += len;
p->remainLen -= len;
while (len-- != 0)
{
dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
dicPos++;
}
p->dicPos = dicPos;
}
}
static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
{
do
{
SizeT limit2 = limit;
if (p->checkDicSize == 0)
{
UInt32 rem = p->prop.dicSize - p->processedPos;
if (limit - p->dicPos > rem)
limit2 = p->dicPos + rem;
}
RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
if (p->processedPos >= p->prop.dicSize)
p->checkDicSize = p->prop.dicSize;
LzmaDec_WriteRem(p, limit);
}
while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
if (p->remainLen > kMatchSpecLenStart)
{
p->remainLen = kMatchSpecLenStart;
}
return 0;
}
typedef enum
{
DUMMY_ERROR, /* unexpected end of input stream */
DUMMY_LIT,
DUMMY_MATCH,
DUMMY_REP
} ELzmaDummy;
static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
{
UInt32 range = p->range;
UInt32 code = p->code;
const Byte *bufLimit = buf + inSize;
CLzmaProb *probs = p->probs;
unsigned state = p->state;
ELzmaDummy res;
{
CLzmaProb *prob;
UInt32 bound;
unsigned ttt;
unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
IF_BIT_0_CHECK(prob)
{
UPDATE_0_CHECK
/* if (bufLimit - buf >= 7) return DUMMY_LIT; */
prob = probs + Literal;
if (p->checkDicSize != 0 || p->processedPos != 0)
prob += (LZMA_LIT_SIZE *
((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
(p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
if (state < kNumLitStates)
{
unsigned symbol = 1;
do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
}
else
{
unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)];
unsigned offs = 0x100;
unsigned symbol = 1;
do
{
unsigned bit;
CLzmaProb *probLit;
matchByte <<= 1;
bit = (matchByte & offs);
probLit = prob + offs + bit + symbol;
GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit)
}
while (symbol < 0x100);
}
res = DUMMY_LIT;
}
else
{
unsigned len;
UPDATE_1_CHECK;
prob = probs + IsRep + state;
IF_BIT_0_CHECK(prob)
{
UPDATE_0_CHECK;
state = 0;
prob = probs + LenCoder;
res = DUMMY_MATCH;
}
else
{
UPDATE_1_CHECK;
res = DUMMY_REP;
prob = probs + IsRepG0 + state;
IF_BIT_0_CHECK(prob)
{
UPDATE_0_CHECK;
prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
IF_BIT_0_CHECK(prob)
{
UPDATE_0_CHECK;
NORMALIZE_CHECK;
return DUMMY_REP;
}
else
{
UPDATE_1_CHECK;
}
}
else
{
UPDATE_1_CHECK;
prob = probs + IsRepG1 + state;
IF_BIT_0_CHECK(prob)
{
UPDATE_0_CHECK;
}
else
{
UPDATE_1_CHECK;
prob = probs + IsRepG2 + state;
IF_BIT_0_CHECK(prob)
{
UPDATE_0_CHECK;
}
else
{
UPDATE_1_CHECK;
}
}
}
state = kNumStates;
prob = probs + RepLenCoder;
}
{
unsigned limit, offset;
CLzmaProb *probLen = prob + LenChoice;
IF_BIT_0_CHECK(probLen)
{
UPDATE_0_CHECK;
probLen = prob + LenLow + (posState << kLenNumLowBits);
offset = 0;
limit = 1 << kLenNumLowBits;
}
else
{
UPDATE_1_CHECK;
probLen = prob + LenChoice2;
IF_BIT_0_CHECK(probLen)
{
UPDATE_0_CHECK;
probLen = prob + LenMid + (posState << kLenNumMidBits);
offset = kLenNumLowSymbols;
limit = 1 << kLenNumMidBits;
}
else
{
UPDATE_1_CHECK;
probLen = prob + LenHigh;
offset = kLenNumLowSymbols + kLenNumMidSymbols;
limit = 1 << kLenNumHighBits;
}
}
TREE_DECODE_CHECK(probLen, limit, len);
len += offset;
}
if (state < 4)
{
unsigned posSlot;
prob = probs + PosSlot +
((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
kNumPosSlotBits);
TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
if (posSlot >= kStartPosModelIndex)
{
int numDirectBits = ((posSlot >> 1) - 1);
/* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
if (posSlot < kEndPosModelIndex)
{
prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1;
}
else
{
numDirectBits -= kNumAlignBits;
do
{
NORMALIZE_CHECK
range >>= 1;
code -= range & (((code - range) >> 31) - 1);
/* if (code >= range) code -= range; */
}
while (--numDirectBits != 0);
prob = probs + Align;
numDirectBits = kNumAlignBits;
}
{
unsigned i = 1;
do
{
GET_BIT_CHECK(prob + i, i);
}
while (--numDirectBits != 0);
}
}
}
}
}
NORMALIZE_CHECK;
return res;
}
static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
{
p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
p->range = 0xFFFFFFFF;
p->needFlush = 0;
}
void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
{
p->needFlush = 1;
p->remainLen = 0;
p->tempBufSize = 0;
if (initDic)
{
p->processedPos = 0;
p->checkDicSize = 0;
p->needInitState = 1;
}
if (initState)
p->needInitState = 1;
}
void LzmaDec_Init(CLzmaDec *p)
{
p->dicPos = 0;
LzmaDec_InitDicAndState(p, True, True);
}
static void LzmaDec_InitStateReal(CLzmaDec *p)
{
UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp));
UInt32 i;
CLzmaProb *probs = p->probs;
for (i = 0; i < numProbs; i++)
probs[i] = kBitModelTotal >> 1;
p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
p->state = 0;
p->needInitState = 0;
}
SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
ELzmaFinishMode finishMode, ELzmaStatus *status)
{
SizeT inSize = *srcLen;
(*srcLen) = 0;
LzmaDec_WriteRem(p, dicLimit);
*status = LZMA_STATUS_NOT_SPECIFIED;
while (p->remainLen != kMatchSpecLenStart)
{
int checkEndMarkNow;
if (p->needFlush != 0)
{
for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
p->tempBuf[p->tempBufSize++] = *src++;
if (p->tempBufSize < RC_INIT_SIZE)
{
*status = LZMA_STATUS_NEEDS_MORE_INPUT;
return SZ_OK;
}
if (p->tempBuf[0] != 0)
return SZ_ERROR_DATA;
LzmaDec_InitRc(p, p->tempBuf);
p->tempBufSize = 0;
}
checkEndMarkNow = 0;
if (p->dicPos >= dicLimit)
{
if (p->remainLen == 0 && p->code == 0)
{
*status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
return SZ_OK;
}
if (finishMode == LZMA_FINISH_ANY)
{
*status = LZMA_STATUS_NOT_FINISHED;
return SZ_OK;
}
if (p->remainLen != 0)
{
*status = LZMA_STATUS_NOT_FINISHED;
return SZ_ERROR_DATA;
}
checkEndMarkNow = 1;
}
if (p->needInitState)
LzmaDec_InitStateReal(p);
if (p->tempBufSize == 0)
{
SizeT processed;
const Byte *bufLimit;
if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
{
int dummyRes = LzmaDec_TryDummy(p, src, inSize);
if (dummyRes == DUMMY_ERROR)
{
memcpy(p->tempBuf, src, inSize);
p->tempBufSize = (unsigned)inSize;
(*srcLen) += inSize;
*status = LZMA_STATUS_NEEDS_MORE_INPUT;
return SZ_OK;
}
if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
{
*status = LZMA_STATUS_NOT_FINISHED;
return SZ_ERROR_DATA;
}
bufLimit = src;
}
else
bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
p->buf = src;
if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
return SZ_ERROR_DATA;
processed = (SizeT)(p->buf - src);
(*srcLen) += processed;
src += processed;
inSize -= processed;
}
else
{
unsigned rem = p->tempBufSize, lookAhead = 0;
while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
p->tempBuf[rem++] = src[lookAhead++];
p->tempBufSize = rem;
if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
{
int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem);
if (dummyRes == DUMMY_ERROR)
{
(*srcLen) += lookAhead;
*status = LZMA_STATUS_NEEDS_MORE_INPUT;
return SZ_OK;
}
if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
{
*status = LZMA_STATUS_NOT_FINISHED;
return SZ_ERROR_DATA;
}
}
p->buf = p->tempBuf;
if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
return SZ_ERROR_DATA;
lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf));
(*srcLen) += lookAhead;
src += lookAhead;
inSize -= lookAhead;
p->tempBufSize = 0;
}
}
if (p->code == 0)
*status = LZMA_STATUS_FINISHED_WITH_MARK;
return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
}
SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
{
SizeT outSize = *destLen;
SizeT inSize = *srcLen;
*srcLen = *destLen = 0;
for (;;)
{
SizeT inSizeCur = inSize, outSizeCur, dicPos;
ELzmaFinishMode curFinishMode;
SRes res;
if (p->dicPos == p->dicBufSize)
p->dicPos = 0;
dicPos = p->dicPos;
if (outSize > p->dicBufSize - dicPos)
{
outSizeCur = p->dicBufSize;
curFinishMode = LZMA_FINISH_ANY;
}
else
{
outSizeCur = dicPos + outSize;
curFinishMode = finishMode;
}
res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
src += inSizeCur;
inSize -= inSizeCur;
*srcLen += inSizeCur;
outSizeCur = p->dicPos - dicPos;
memcpy(dest, p->dic + dicPos, outSizeCur);
dest += outSizeCur;
outSize -= outSizeCur;
*destLen += outSizeCur;
if (res != 0)
return res;
if (outSizeCur == 0 || outSize == 0)
return SZ_OK;
}
}
void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
{
alloc->Free(alloc, p->probs);
p->probs = 0;
}
static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
{
alloc->Free(alloc, p->dic);
p->dic = 0;
}
void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
{
LzmaDec_FreeProbs(p, alloc);
LzmaDec_FreeDict(p, alloc);
}
SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
{
UInt32 dicSize;
Byte d;
if (size < LZMA_PROPS_SIZE)
return SZ_ERROR_UNSUPPORTED;
else
dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
if (dicSize < LZMA_DIC_MIN)
dicSize = LZMA_DIC_MIN;
p->dicSize = dicSize;
d = data[0];
if (d >= (9 * 5 * 5))
return SZ_ERROR_UNSUPPORTED;
p->lc = d % 9;
d /= 9;
p->pb = d / 5;
p->lp = d % 5;
return SZ_OK;
}
static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
{
UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
if (p->probs == 0 || numProbs != p->numProbs)
{
LzmaDec_FreeProbs(p, alloc);
p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
p->numProbs = numProbs;
if (p->probs == 0)
return SZ_ERROR_MEM;
}
return SZ_OK;
}
SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
{
CLzmaProps propNew;
RINOK(LzmaProps_Decode(&propNew, props, propsSize));
RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
p->prop = propNew;
return SZ_OK;
}
SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
{
CLzmaProps propNew;
SizeT dicBufSize;
RINOK(LzmaProps_Decode(&propNew, props, propsSize));
RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
dicBufSize = propNew.dicSize;
if (p->dic == 0 || dicBufSize != p->dicBufSize)
{
LzmaDec_FreeDict(p, alloc);
p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
if (p->dic == 0)
{
LzmaDec_FreeProbs(p, alloc);
return SZ_ERROR_MEM;
}
}
p->dicBufSize = dicBufSize;
p->prop = propNew;
return SZ_OK;
}
SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
ELzmaStatus *status, ISzAlloc *alloc)
{
CLzmaDec p;
SRes res;
SizeT inSize = *srcLen;
SizeT outSize = *destLen;
*srcLen = *destLen = 0;
if (inSize < RC_INIT_SIZE)
return SZ_ERROR_INPUT_EOF;
LzmaDec_Construct(&p);
res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc);
if (res != 0)
return res;
p.dic = dest;
p.dicBufSize = outSize;
LzmaDec_Init(&p);
*srcLen = inSize;
res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
res = SZ_ERROR_INPUT_EOF;
(*destLen) = p.dicPos;
LzmaDec_FreeProbs(&p, alloc);
return res;
}

231
LZMA/SDK/C/LzmaDec.h Normal file
View file

@ -0,0 +1,231 @@
/* LzmaDec.h -- LZMA Decoder
2009-02-07 : Igor Pavlov : Public domain */
#ifndef __LZMA_DEC_H
#define __LZMA_DEC_H
#include "Types.h"
#ifdef __cplusplus
extern "C" {
#endif
/* #define _LZMA_PROB32 */
/* _LZMA_PROB32 can increase the speed on some CPUs,
but memory usage for CLzmaDec::probs will be doubled in that case */
#ifdef _LZMA_PROB32
#define CLzmaProb UInt32
#else
#define CLzmaProb UInt16
#endif
/* ---------- LZMA Properties ---------- */
#define LZMA_PROPS_SIZE 5
typedef struct _CLzmaProps
{
unsigned lc, lp, pb;
UInt32 dicSize;
} CLzmaProps;
/* LzmaProps_Decode - decodes properties
Returns:
SZ_OK
SZ_ERROR_UNSUPPORTED - Unsupported properties
*/
SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
/* ---------- LZMA Decoder state ---------- */
/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
#define LZMA_REQUIRED_INPUT_MAX 20
typedef struct
{
CLzmaProps prop;
CLzmaProb *probs;
Byte *dic;
const Byte *buf;
UInt32 range, code;
SizeT dicPos;
SizeT dicBufSize;
UInt32 processedPos;
UInt32 checkDicSize;
unsigned state;
UInt32 reps[4];
unsigned remainLen;
int needFlush;
int needInitState;
UInt32 numProbs;
unsigned tempBufSize;
Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
} CLzmaDec;
#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
void LzmaDec_Init(CLzmaDec *p);
/* There are two types of LZMA streams:
0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
typedef enum
{
LZMA_FINISH_ANY, /* finish at any point */
LZMA_FINISH_END /* block must be finished at the end */
} ELzmaFinishMode;
/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
You must use LZMA_FINISH_END, when you know that current output buffer
covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
and output value of destLen will be less than output buffer size limit.
You can check status result also.
You can use multiple checks to test data integrity after full decompression:
1) Check Result and "status" variable.
2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
You must use correct finish mode in that case. */
typedef enum
{
LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */
LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
LZMA_STATUS_NOT_FINISHED, /* stream was not finished */
LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */
} ELzmaStatus;
/* ELzmaStatus is used only as output value for function call */
/* ---------- Interfaces ---------- */
/* There are 3 levels of interfaces:
1) Dictionary Interface
2) Buffer Interface
3) One Call Interface
You can select any of these interfaces, but don't mix functions from different
groups for same object. */
/* There are two variants to allocate state for Dictionary Interface:
1) LzmaDec_Allocate / LzmaDec_Free
2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
You can use variant 2, if you set dictionary buffer manually.
For Buffer Interface you must always use variant 1.
LzmaDec_Allocate* can return:
SZ_OK
SZ_ERROR_MEM - Memory allocation error
SZ_ERROR_UNSUPPORTED - Unsupported properties
*/
SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
/* ---------- Dictionary Interface ---------- */
/* You can use it, if you want to eliminate the overhead for data copying from
dictionary to some other external buffer.
You must work with CLzmaDec variables directly in this interface.
STEPS:
LzmaDec_Constr()
LzmaDec_Allocate()
for (each new stream)
{
LzmaDec_Init()
while (it needs more decompression)
{
LzmaDec_DecodeToDic()
use data from CLzmaDec::dic and update CLzmaDec::dicPos
}
}
LzmaDec_Free()
*/
/* LzmaDec_DecodeToDic
The decoding to internal dictionary buffer (CLzmaDec::dic).
You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
finishMode:
It has meaning only if the decoding reaches output limit (dicLimit).
LZMA_FINISH_ANY - Decode just dicLimit bytes.
LZMA_FINISH_END - Stream must be finished after dicLimit.
Returns:
SZ_OK
status:
LZMA_STATUS_FINISHED_WITH_MARK
LZMA_STATUS_NOT_FINISHED
LZMA_STATUS_NEEDS_MORE_INPUT
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
SZ_ERROR_DATA - Data error
*/
SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
/* ---------- Buffer Interface ---------- */
/* It's zlib-like interface.
See LzmaDec_DecodeToDic description for information about STEPS and return results,
but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
to work with CLzmaDec variables manually.
finishMode:
It has meaning only if the decoding reaches output limit (*destLen).
LZMA_FINISH_ANY - Decode just destLen bytes.
LZMA_FINISH_END - Stream must be finished after (*destLen).
*/
SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
/* ---------- One Call Interface ---------- */
/* LzmaDecode
finishMode:
It has meaning only if the decoding reaches output limit (*destLen).
LZMA_FINISH_ANY - Decode just destLen bytes.
LZMA_FINISH_END - Stream must be finished after (*destLen).
Returns:
SZ_OK
status:
LZMA_STATUS_FINISHED_WITH_MARK
LZMA_STATUS_NOT_FINISHED
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
SZ_ERROR_DATA - Data error
SZ_ERROR_MEM - Memory allocation error
SZ_ERROR_UNSUPPORTED - Unsupported properties
SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
*/
SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
ELzmaStatus *status, ISzAlloc *alloc);
#ifdef __cplusplus
}
#endif
#endif

2268
LZMA/SDK/C/LzmaEnc.c Normal file

File diff suppressed because it is too large Load diff

80
LZMA/SDK/C/LzmaEnc.h Normal file
View file

@ -0,0 +1,80 @@
/* LzmaEnc.h -- LZMA Encoder
2009-02-07 : Igor Pavlov : Public domain */
#ifndef __LZMA_ENC_H
#define __LZMA_ENC_H
#include "Types.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LZMA_PROPS_SIZE 5
typedef struct _CLzmaEncProps
{
int level; /* 0 <= level <= 9 */
UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
(1 << 12) <= dictSize <= (1 << 30) for 64-bit version
default = (1 << 24) */
int lc; /* 0 <= lc <= 8, default = 3 */
int lp; /* 0 <= lp <= 4, default = 0 */
int pb; /* 0 <= pb <= 4, default = 2 */
int algo; /* 0 - fast, 1 - normal, default = 1 */
int fb; /* 5 <= fb <= 273, default = 32 */
int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */
int numHashBytes; /* 2, 3 or 4, default = 4 */
UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */
unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */
int numThreads; /* 1 or 2, default = 2 */
} CLzmaEncProps;
void LzmaEncProps_Init(CLzmaEncProps *p);
void LzmaEncProps_Normalize(CLzmaEncProps *p);
UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
/* ---------- CLzmaEncHandle Interface ---------- */
/* LzmaEnc_* functions can return the following exit codes:
Returns:
SZ_OK - OK
SZ_ERROR_MEM - Memory allocation error
SZ_ERROR_PARAM - Incorrect paramater in props
SZ_ERROR_WRITE - Write callback error.
SZ_ERROR_PROGRESS - some break from progress callback
SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
*/
typedef void * CLzmaEncHandle;
CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc);
void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
/* ---------- One Call Interface ---------- */
/* LzmaEncode
Return code:
SZ_OK - OK
SZ_ERROR_MEM - Memory allocation error
SZ_ERROR_PARAM - Incorrect paramater
SZ_ERROR_OUTPUT_EOF - output buffer overflow
SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
*/
SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
#ifdef __cplusplus
}
#endif
#endif

256
LZMA/SDK/C/Types.h Normal file
View file

@ -0,0 +1,256 @@
/* Types.h -- Basic types
2010-10-09 : Igor Pavlov : Public domain */
#ifndef __7Z_TYPES_H
#define __7Z_TYPES_H
#include "../../UefiLzma.h"
#include <stddef.h>
#ifdef _WIN32
#include <windows.h>
#endif
#ifndef EXTERN_C_BEGIN
#ifdef __cplusplus
#define EXTERN_C_BEGIN extern "C" {
#define EXTERN_C_END }
#else
#define EXTERN_C_BEGIN
#define EXTERN_C_END
#endif
#endif
EXTERN_C_BEGIN
#define SZ_OK 0
#define SZ_ERROR_DATA 1
#define SZ_ERROR_MEM 2
#define SZ_ERROR_CRC 3
#define SZ_ERROR_UNSUPPORTED 4
#define SZ_ERROR_PARAM 5
#define SZ_ERROR_INPUT_EOF 6
#define SZ_ERROR_OUTPUT_EOF 7
#define SZ_ERROR_READ 8
#define SZ_ERROR_WRITE 9
#define SZ_ERROR_PROGRESS 10
#define SZ_ERROR_FAIL 11
#define SZ_ERROR_THREAD 12
#define SZ_ERROR_ARCHIVE 16
#define SZ_ERROR_NO_ARCHIVE 17
typedef int SRes;
#ifdef _WIN32
typedef DWORD WRes;
#else
typedef int WRes;
#endif
#ifndef RINOK
#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
#endif
typedef unsigned char Byte;
typedef short Int16;
typedef unsigned short UInt16;
#ifdef _LZMA_UINT32_IS_ULONG
typedef long Int32;
typedef unsigned long UInt32;
#else
typedef int Int32;
typedef unsigned int UInt32;
#endif
#ifdef _SZ_NO_INT_64
/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
NOTES: Some code will work incorrectly in that case! */
typedef long Int64;
typedef unsigned long UInt64;
#else
#if defined(_MSC_VER) || defined(__BORLANDC__)
typedef __int64 Int64;
typedef unsigned __int64 UInt64;
#define UINT64_CONST(n) n
#else
typedef long long int Int64;
typedef unsigned long long int UInt64;
#define UINT64_CONST(n) n ## ULL
#endif
#endif
#ifdef _LZMA_NO_SYSTEM_SIZE_T
typedef UInt32 SizeT;
#else
typedef size_t SizeT;
#endif
typedef int Bool;
#define True 1
#define False 0
#ifdef _WIN32
#define MY_STD_CALL __stdcall
#else
#define MY_STD_CALL
#endif
#ifdef _MSC_VER
#if _MSC_VER >= 1300
#define MY_NO_INLINE __declspec(noinline)
#else
#define MY_NO_INLINE
#endif
#define MY_CDECL __cdecl
#define MY_FAST_CALL __fastcall
#else
#define MY_CDECL
#define MY_FAST_CALL
#endif
/* The following interfaces use first parameter as pointer to structure */
typedef struct
{
Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */
} IByteIn;
typedef struct
{
void (*Write)(void *p, Byte b);
} IByteOut;
typedef struct
{
SRes (*Read)(void *p, void *buf, size_t *size);
/* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
(output(*size) < input(*size)) is allowed */
} ISeqInStream;
/* it can return SZ_ERROR_INPUT_EOF */
SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
typedef struct
{
size_t (*Write)(void *p, const void *buf, size_t size);
/* Returns: result - the number of actually written bytes.
(result < size) means error */
} ISeqOutStream;
typedef enum
{
SZ_SEEK_SET = 0,
SZ_SEEK_CUR = 1,
SZ_SEEK_END = 2
} ESzSeek;
typedef struct
{
SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
} ISeekInStream;
typedef struct
{
SRes (*Look)(void *p, const void **buf, size_t *size);
/* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
(output(*size) > input(*size)) is not allowed
(output(*size) < input(*size)) is allowed */
SRes (*Skip)(void *p, size_t offset);
/* offset must be <= output(*size) of Look */
SRes (*Read)(void *p, void *buf, size_t *size);
/* reads directly (without buffer). It's same as ISeqInStream::Read */
SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
} ILookInStream;
SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
/* reads via ILookInStream::Read */
SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
#define LookToRead_BUF_SIZE (1 << 14)
typedef struct
{
ILookInStream s;
ISeekInStream *realStream;
size_t pos;
size_t size;
Byte buf[LookToRead_BUF_SIZE];
} CLookToRead;
void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
void LookToRead_Init(CLookToRead *p);
typedef struct
{
ISeqInStream s;
ILookInStream *realStream;
} CSecToLook;
void SecToLook_CreateVTable(CSecToLook *p);
typedef struct
{
ISeqInStream s;
ILookInStream *realStream;
} CSecToRead;
void SecToRead_CreateVTable(CSecToRead *p);
typedef struct
{
SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
/* Returns: result. (result != SZ_OK) means break.
Value (UInt64)(Int64)-1 for size means unknown value. */
} ICompressProgress;
typedef struct
{
void *(*Alloc)(void *p, size_t size);
void (*Free)(void *p, void *address); /* address can be 0 */
} ISzAlloc;
#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
#define IAlloc_Free(p, a) (p)->Free((p), a)
#ifdef _WIN32
#define CHAR_PATH_SEPARATOR '\\'
#define WCHAR_PATH_SEPARATOR L'\\'
#define STRING_PATH_SEPARATOR "\\"
#define WSTRING_PATH_SEPARATOR L"\\"
#else
#define CHAR_PATH_SEPARATOR '/'
#define WCHAR_PATH_SEPARATOR L'/'
#define STRING_PATH_SEPARATOR "/"
#define WSTRING_PATH_SEPARATOR L"/"
#endif
EXTERN_C_END
#endif

31
LZMA/UefiLzma.h Normal file
View file

@ -0,0 +1,31 @@
/* LZMA UEFI header file
Copyright (c) 2009, Intel Corporation. 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 __UEFILZMA_H__
#define __UEFILZMA_H__
#include "../basetypes.h"
#ifdef _WIN32
#undef _WIN32
#endif
#ifdef _WIN64
#undef _WIN64
#endif
#define _LZMA_SIZE_OPT
#define _7ZIP_ST
#endif // __UEFILZMA_H__

1598
Tiano/EfiCompress.c Normal file

File diff suppressed because it is too large Load diff

101
Tiano/EfiTianoCompress.h Normal file
View file

@ -0,0 +1,101 @@
/* EFI/Tiano Compress Header
Copyright (c) 2004 - 2008, Intel Corporation. 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.
Module Name:
TianoCompress.h
Abstract:
Header file for compression routine.
*/
#ifndef _EFITIANOCOMPRESS_H_
#define _EFITIANOCOMPRESS_H_
#include <string.h>
#include <stdlib.h>
#include "../basetypes.h"
#ifdef __cplusplus
extern "C" {
#endif
/*++
Routine Description:
Tiano compression routine.
Arguments:
SrcBuffer - The buffer storing the source data
SrcSize - The size of source data
DstBuffer - The buffer to store the compressed data
DstSize - On input, the size of DstBuffer; On output,
the size of the actual compressed data.
Returns:
EFI_BUFFER_TOO_SMALL - The DstBuffer is too small. this case,
DstSize contains the size needed.
EFI_SUCCESS - Compression is successful.
EFI_OUT_OF_RESOURCES - No resource to complete function.
EFI_INVALID_PARAMETER - Parameter supplied is wrong.
--*/
INT32
TianoCompress (
UINT8 *SrcBuffer,
UINT32 SrcSize,
UINT8 *DstBuffer,
UINT32 *DstSize
)
;
/*++
Routine Description:
EFI 1.1 compression routine.
Arguments:
SrcBuffer - The buffer storing the source data
SrcSize - The size of source data
DstBuffer - The buffer to store the compressed data
DstSize - On input, the size of DstBuffer; On output,
the size of the actual compressed data.
Returns:
EFI_BUFFER_TOO_SMALL - The DstBuffer is too small. this case,
DstSize contains the size needed.
EFI_SUCCESS - Compression is successful.
EFI_OUT_OF_RESOURCES - No resource to complete function.
EFI_INVALID_PARAMETER - Parameter supplied is wrong.
--*/
INT32
EfiCompress (
UINT8 *SrcBuffer,
UINT32 SrcSize,
UINT8 *DstBuffer,
UINT32 *DstSize
)
;
#ifdef __cplusplus
}
#endif
#endif

994
Tiano/EfiTianoDecompress.c Normal file
View file

@ -0,0 +1,994 @@
/*++
Copyright (c) 2004 - 2006, Intel Corporation. All rights reserved.<BR>
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,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
Decompress.c
Abstract:
Decompressor. Algorithm Ported from OPSD code (Decomp.asm)
--*/
#include "EfiTianoDecompress.h"
//
// Decompression algorithm begins here
//
#define BITBUFSIZ 32
#define MAXMATCH 256
#define THRESHOLD 3
#define CODE_BIT 16
//#define UINT8_MAX 0xff
#define BAD_TABLE - 1
//
// C: Char&Len Set; P: Position Set; T: exTra Set
//
#define NC (0xff + MAXMATCH + 2 - THRESHOLD)
#define CBIT 9
#define MAXPBIT 5
#define TBIT 5
#define MAXNP ((1U << MAXPBIT) - 1)
#define NT (CODE_BIT + 3)
#if NT > MAXNP
#define NPT NT
#else
#define NPT MAXNP
#endif
typedef struct {
UINT8 *mSrcBase; // Starting address of compressed data
UINT8 *mDstBase; // Starting address of decompressed data
UINT32 mOutBuf;
UINT32 mInBuf;
UINT16 mBitCount;
UINT32 mBitBuf;
UINT32 mSubBitBuf;
UINT16 mBlockSize;
UINT32 mCompSize;
UINT32 mOrigSize;
UINT16 mBadTableFlag;
UINT16 mLeft[2 * NC - 1];
UINT16 mRight[2 * NC - 1];
UINT8 mCLen[NC];
UINT8 mPTLen[NPT];
UINT16 mCTable[4096];
UINT16 mPTTable[256];
//
// The length of the field 'Position Set Code Length Array Size'Block Header.
// For EFI 1.1 de/compression algorithm, mPBit = 4
// For Tiano de/compression algorithm, mPBit = 5
//
UINT8 mPBit;
} SCRATCH_DATA;
STATIC
VOID
FillBuf (
SCRATCH_DATA *Sd,
UINT16 NumOfBits
)
/*++
Routine Description:
Shift mBitBuf NumOfBits left. ReadNumOfBits of bits from source.
Arguments:
Sd - The global scratch data
NumOfBits - The number of bits to shift and read.
Returns: (VOID)
--*/
{
Sd->mBitBuf = (UINT32) (Sd->mBitBuf << NumOfBits);
while (NumOfBits > Sd->mBitCount) {
Sd->mBitBuf |= (UINT32) (Sd->mSubBitBuf << (NumOfBits = (UINT16) (NumOfBits - Sd->mBitCount)));
if (Sd->mCompSize > 0) {
//
// Get 1 byte into SubBitBuf
//
Sd->mCompSize--;
Sd->mSubBitBuf = 0;
Sd->mSubBitBuf = Sd->mSrcBase[Sd->mInBuf++];
Sd->mBitCount = 8;
} else {
//
// No more bits from the source, just pad zero bit.
//
Sd->mSubBitBuf = 0;
Sd->mBitCount = 8;
}
}
Sd->mBitCount = (UINT16) (Sd->mBitCount - NumOfBits);
Sd->mBitBuf |= Sd->mSubBitBuf >> Sd->mBitCount;
}
STATIC
UINT32
GetBits (
SCRATCH_DATA *Sd,
UINT16 NumOfBits
)
/*++
Routine Description:
Get NumOfBits of bits from mBitBuf. Fill mBitBuf with subsequent
NumOfBits of bits from source. Returns NumOfBits of bits that are
popped.
Arguments:
Sd - The global scratch data.
NumOfBits - The number of bits to pop and read.
Returns:
The bits that are popped.
--*/
{
UINT32 Bits;
Bits = (UINT32) (Sd->mBitBuf >> (BITBUFSIZ - NumOfBits));
FillBuf (Sd, NumOfBits);
return Bits;
}
STATIC
UINT16
MakeTable (
SCRATCH_DATA *Sd,
UINT16 NumOfChar,
UINT8 *BitLen,
UINT16 TableBits,
UINT16 *Table
)
/*++
Routine Description:
Creates Huffman Code mapping table according to code length array.
Arguments:
Sd - The global scratch data
NumOfChar - Number of symbolsthe symbol set
BitLen - Code length array
TableBits - The width of the mapping table
Table - The table
Returns:
0 - OK.
BAD_TABLE - The table is corrupted.
--*/
{
UINT16 Count[17];
UINT16 Weight[17];
UINT16 Start[18];
UINT16 *Pointer;
UINT16 Index3;
UINT16 Index;
UINT16 Len;
UINT16 Char;
UINT16 JuBits;
UINT16 Avail;
UINT16 NextCode;
UINT16 Mask;
for (Index = 1; Index <= 16; Index++) {
Count[Index] = 0;
}
for (Index = 0; Index < NumOfChar; Index++) {
Count[BitLen[Index]]++;
}
Start[1] = 0;
for (Index = 1; Index <= 16; Index++) {
Start[Index + 1] = (UINT16) (Start[Index] + (Count[Index] << (16 - Index)));
}
if (Start[17] != 0) {
/*(1U << 16)*/
return (UINT16) BAD_TABLE;
}
JuBits = (UINT16) (16 - TableBits);
for (Index = 1; Index <= TableBits; Index++) {
Start[Index] >>= JuBits;
Weight[Index] = (UINT16) (1U << (TableBits - Index));
}
while (Index <= 16) {
Weight[Index++] = (UINT16) (1U << (16 - Index));
}
Index = (UINT16) (Start[TableBits + 1] >> JuBits);
if (Index != 0) {
Index3 = (UINT16) (1U << TableBits);
while (Index != Index3) {
Table[Index++] = 0;
}
}
Avail = NumOfChar;
Mask = (UINT16) (1U << (15 - TableBits));
for (Char = 0; Char < NumOfChar; Char++) {
Len = BitLen[Char];
if (Len == 0) {
continue;
}
NextCode = (UINT16) (Start[Len] + Weight[Len]);
if (Len <= TableBits) {
for (Index = Start[Len]; Index < NextCode; Index++) {
Table[Index] = Char;
}
} else {
Index3 = Start[Len];
Pointer = &Table[Index3 >> JuBits];
Index = (UINT16) (Len - TableBits);
while (Index != 0) {
if (*Pointer == 0) {
Sd->mRight[Avail] = Sd->mLeft[Avail] = 0;
*Pointer = Avail++;
}
if (Index3 & Mask) {
Pointer = &Sd->mRight[*Pointer];
} else {
Pointer = &Sd->mLeft[*Pointer];
}
Index3 <<= 1;
Index--;
}
*Pointer = Char;
}
Start[Len] = NextCode;
}
//
// Succeeds
//
return 0;
}
STATIC
UINT32
DecodeP (
SCRATCH_DATA *Sd
)
/*++
Routine Description:
Decodes a position value.
Arguments:
Sd - the global scratch data
Returns:
The position value decoded.
--*/
{
UINT16 Val;
UINT32 Mask;
UINT32 Pos;
Val = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)];
if (Val >= MAXNP) {
Mask = 1U << (BITBUFSIZ - 1 - 8);
do {
if (Sd->mBitBuf & Mask) {
Val = Sd->mRight[Val];
} else {
Val = Sd->mLeft[Val];
}
Mask >>= 1;
} while (Val >= MAXNP);
}
//
// Advance what we have read
//
FillBuf (Sd, Sd->mPTLen[Val]);
Pos = Val;
if (Val > 1) {
Pos = (UINT32) ((1U << (Val - 1)) + GetBits (Sd, (UINT16) (Val - 1)));
}
return Pos;
}
STATIC
UINT16
ReadPTLen (
SCRATCH_DATA *Sd,
UINT16 nn,
UINT16 nbit,
UINT16 Special
)
/*++
Routine Description:
Reads code lengths for the Extra Set or the Position Set
Arguments:
Sd - The global scratch data
nn - Number of symbols
nbit - Number of bits needed to represent nn
Special - The special symbol that needs to be taken care of
Returns:
0 - OK.
BAD_TABLE - Table is corrupted.
--*/
{
UINT16 Number;
UINT16 CharC;
UINT16 Index;
UINT32 Mask;
Number = (UINT16) GetBits (Sd, nbit);
if (Number == 0) {
CharC = (UINT16) GetBits (Sd, nbit);
for (Index = 0; Index < 256; Index++) {
Sd->mPTTable[Index] = CharC;
}
for (Index = 0; Index < nn; Index++) {
Sd->mPTLen[Index] = 0;
}
return 0;
}
Index = 0;
while (Index < Number) {
CharC = (UINT16) (Sd->mBitBuf >> (BITBUFSIZ - 3));
if (CharC == 7) {
Mask = 1U << (BITBUFSIZ - 1 - 3);
while (Mask & Sd->mBitBuf) {
Mask >>= 1;
CharC += 1;
}
}
FillBuf (Sd, (UINT16) ((CharC < 7) ? 3 : CharC - 3));
Sd->mPTLen[Index++] = (UINT8) CharC;
if (Index == Special) {
CharC = (UINT16) GetBits (Sd, 2);
while ((INT16) (--CharC) >= 0) {
Sd->mPTLen[Index++] = 0;
}
}
}
while (Index < nn) {
Sd->mPTLen[Index++] = 0;
}
return MakeTable (Sd, nn, Sd->mPTLen, 8, Sd->mPTTable);
}
STATIC
VOID
ReadCLen (
SCRATCH_DATA *Sd
)
/*++
Routine Description:
Reads code lengths for Char&Len Set.
Arguments:
Sd - the global scratch data
Returns: (VOID)
--*/
{
UINT16 Number;
UINT16 CharC;
UINT16 Index;
UINT32 Mask;
Number = (UINT16) GetBits (Sd, CBIT);
if (Number == 0) {
CharC = (UINT16) GetBits (Sd, CBIT);
for (Index = 0; Index < NC; Index++) {
Sd->mCLen[Index] = 0;
}
for (Index = 0; Index < 4096; Index++) {
Sd->mCTable[Index] = CharC;
}
return ;
}
Index = 0;
while (Index < Number) {
CharC = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)];
if (CharC >= NT) {
Mask = 1U << (BITBUFSIZ - 1 - 8);
do {
if (Mask & Sd->mBitBuf) {
CharC = Sd->mRight[CharC];
} else {
CharC = Sd->mLeft[CharC];
}
Mask >>= 1;
} while (CharC >= NT);
}
//
// Advance what we have read
//
FillBuf (Sd, Sd->mPTLen[CharC]);
if (CharC <= 2) {
if (CharC == 0) {
CharC = 1;
} else if (CharC == 1) {
CharC = (UINT16) (GetBits (Sd, 4) + 3);
} else if (CharC == 2) {
CharC = (UINT16) (GetBits (Sd, CBIT) + 20);
}
while ((INT16) (--CharC) >= 0) {
Sd->mCLen[Index++] = 0;
}
} else {
Sd->mCLen[Index++] = (UINT8) (CharC - 2);
}
}
while (Index < NC) {
Sd->mCLen[Index++] = 0;
}
MakeTable (Sd, NC, Sd->mCLen, 12, Sd->mCTable);
return ;
}
STATIC
UINT16
DecodeC (
SCRATCH_DATA *Sd
)
/*++
Routine Description:
Decode a character/length value.
Arguments:
Sd - The global scratch data.
Returns:
The value decoded.
--*/
{
UINT16 Index2;
UINT32 Mask;
if (Sd->mBlockSize == 0) {
//
// Starting a new block
//
Sd->mBlockSize = (UINT16) GetBits (Sd, 16);
Sd->mBadTableFlag = ReadPTLen (Sd, NT, TBIT, 3);
if (Sd->mBadTableFlag != 0) {
return 0;
}
ReadCLen (Sd);
Sd->mBadTableFlag = ReadPTLen (Sd, MAXNP, Sd->mPBit, (UINT16) (-1));
if (Sd->mBadTableFlag != 0) {
return 0;
}
}
Sd->mBlockSize--;
Index2 = Sd->mCTable[Sd->mBitBuf >> (BITBUFSIZ - 12)];
if (Index2 >= NC) {
Mask = 1U << (BITBUFSIZ - 1 - 12);
do {
if (Sd->mBitBuf & Mask) {
Index2 = Sd->mRight[Index2];
} else {
Index2 = Sd->mLeft[Index2];
}
Mask >>= 1;
} while (Index2 >= NC);
}
//
// Advance what we have read
//
FillBuf (Sd, Sd->mCLen[Index2]);
return Index2;
}
STATIC
VOID
Decode (
SCRATCH_DATA *Sd
)
/*++
Routine Description:
Decode the source data and put the resulting data into the destination buffer.
Arguments:
Sd - The global scratch data
Returns: (VOID)
--*/
{
UINT16 BytesRemain;
UINT32 DataIdx;
UINT16 CharC;
BytesRemain = (UINT16) (-1);
DataIdx = 0;
for (;;) {
CharC = DecodeC (Sd);
if (Sd->mBadTableFlag != 0) {
return ;
}
if (CharC < 256) {
//
// Process an Original character
//
if (Sd->mOutBuf >= Sd->mOrigSize) {
return ;
} else {
Sd->mDstBase[Sd->mOutBuf++] = (UINT8) CharC;
}
} else {
//
// Process a Pointer
//
CharC = (UINT16) (CharC - (UINT8_MAX + 1 - THRESHOLD));
BytesRemain = CharC;
DataIdx = Sd->mOutBuf - DecodeP (Sd) - 1;
BytesRemain--;
while ((INT16) (BytesRemain) >= 0) {
Sd->mDstBase[Sd->mOutBuf++] = Sd->mDstBase[DataIdx++];
if (Sd->mOutBuf >= Sd->mOrigSize) {
return ;
}
BytesRemain--;
}
}
}
return ;
}
UINT32
GetInfo (
VOID *Source,
UINT32 SrcSize,
UINT32 *DstSize,
UINT32 *ScratchSize
)
/*++
Routine Description:
The internal implementation of *_DECOMPRESS_PROTOCOL.GetInfo().
Arguments:
Source - The source buffer containing the compressed data.
SrcSize - The size of source buffer
DstSize - The size of destination buffer.
ScratchSize - The size of scratch buffer.
Returns:
EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved.
EFI_INVALID_PARAMETER - The source data is corrupted
--*/
{
UINT8 *Src;
*ScratchSize = sizeof (SCRATCH_DATA);
Src = Source;
if (SrcSize < 8) {
return ERR_INVALID_PARAMETER;
}
*DstSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24);
return ERR_SUCCESS;
}
UINT32
Decompress (
VOID *Source,
UINT32 SrcSize,
VOID *Destination,
UINT32 DstSize,
VOID *Scratch,
UINT32 ScratchSize,
UINT8 Version
)
/*++
Routine Description:
The internal implementation of *_DECOMPRESS_PROTOCOL.Decompress().
Arguments:
Source - The source buffer containing the compressed data.
SrcSize - The size of source buffer
Destination - The destination buffer to store the decompressed data
DstSize - The size of destination buffer.
Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data.
ScratchSize - The size of scratch buffer.
Version - The version of de/compression algorithm.
Version 1 for EFI 1.1 de/compression algorithm.
Version 2 for Tiano de/compression algorithm.
Returns:
EFI_SUCCESS - Decompression is successfull
EFI_INVALID_PARAMETER - The source data is corrupted
--*/
{
UINT32 Index;
UINT32 CompSize;
UINT32 OrigSize;
UINT32 Status;
SCRATCH_DATA *Sd;
UINT8 *Src;
UINT8 *Dst;
Status = ERR_SUCCESS;
Src = Source;
Dst = Destination;
if (ScratchSize < sizeof (SCRATCH_DATA)) {
return ERR_INVALID_PARAMETER;
}
Sd = (SCRATCH_DATA *) Scratch;
if (SrcSize < 8) {
return ERR_INVALID_PARAMETER;
}
CompSize = Src[0] + (Src[1] << 8) + (Src[2] << 16) + (Src[3] << 24);
OrigSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24);
//
// If compressed file size is 0, return
//
if (OrigSize == 0) {
return Status;
}
if (SrcSize < CompSize + 8) {
return ERR_INVALID_PARAMETER;
}
if (DstSize != OrigSize) {
return ERR_INVALID_PARAMETER;
}
Src = Src + 8;
for (Index = 0; Index < sizeof (SCRATCH_DATA); Index++) {
((UINT8 *) Sd)[Index] = 0;
}
//
// The length of the field 'Position Set Code Length Array Size'Block Header.
// For EFI 1.1 de/compression algorithm(Version 1), mPBit = 4
// For Tiano de/compression algorithm(Version 2), mPBit = 5
//
switch (Version) {
case 1:
Sd->mPBit = 4;
break;
case 2:
Sd->mPBit = 5;
break;
default:
//
// Currently, only have 2 versions
//
return ERR_INVALID_PARAMETER;
}
Sd->mSrcBase = Src;
Sd->mDstBase = Dst;
Sd->mCompSize = CompSize;
Sd->mOrigSize = OrigSize;
//
// Fill the first BITBUFSIZ bits
//
FillBuf (Sd, BITBUFSIZ);
//
// Decompress it
//
Decode (Sd);
if (Sd->mBadTableFlag != 0) {
//
// Something wrong with the source
//
Status = ERR_INVALID_PARAMETER;
}
return Status;
}
UINT32
EFIAPI
EfiGetInfo (
VOID *Source,
UINT32 SrcSize,
UINT32 *DstSize,
UINT32 *ScratchSize
)
/*++
Routine Description:
The implementation is same as that of EFI_DECOMPRESS_PROTOCOL.GetInfo().
Arguments:
This - The protocol instance pointer
Source - The source buffer containing the compressed data.
SrcSize - The size of source buffer
DstSize - The size of destination buffer.
ScratchSize - The size of scratch buffer.
Returns:
EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved.
EFI_INVALID_PARAMETER - The source data is corrupted
--*/
{
return GetInfo (
Source,
SrcSize,
DstSize,
ScratchSize
);
}
UINT32
EFIAPI
EfiDecompress (
VOID *Source,
UINT32 SrcSize,
VOID *Destination,
UINT32 DstSize,
VOID *Scratch,
UINT32 ScratchSize
)
/*++
Routine Description:
The implementation is same as that of EFI_DECOMPRESS_PROTOCOL.Decompress().
Arguments:
This - The protocol instance pointer
Source - The source buffer containing the compressed data.
SrcSize - The size of source buffer
Destination - The destination buffer to store the decompressed data
DstSize - The size of destination buffer.
Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data.
ScratchSize - The size of scratch buffer.
Returns:
EFI_SUCCESS - Decompression is successfull
EFI_INVALID_PARAMETER - The source data is corrupted
--*/
{
//
// For EFI 1.1 de/compression algorithm, the version is 1.
//
return Decompress (
Source,
SrcSize,
Destination,
DstSize,
Scratch,
ScratchSize,
1
);
}
UINT32
EFIAPI
TianoGetInfo (
VOID *Source,
UINT32 SrcSize,
UINT32 *DstSize,
UINT32 *ScratchSize
)
/*++
Routine Description:
The implementation is same as that of EFI_TIANO_DECOMPRESS_PROTOCOL.GetInfo().
Arguments:
This - The protocol instance pointer
Source - The source buffer containing the compressed data.
SrcSize - The size of source buffer
DstSize - The size of destination buffer.
ScratchSize - The size of scratch buffer.
Returns:
EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved.
EFI_INVALID_PARAMETER - The source data is corrupted
--*/
{
return GetInfo (
Source,
SrcSize,
DstSize,
ScratchSize
);
}
UINT32
EFIAPI
TianoDecompress (
VOID *Source,
UINT32 SrcSize,
VOID *Destination,
UINT32 DstSize,
VOID *Scratch,
UINT32 ScratchSize
)
/*++
Routine Description:
The implementation is same as that of EFI_TIANO_DECOMPRESS_PROTOCOL.Decompress().
Arguments:
This - The protocol instance pointer
Source - The source buffer containing the compressed data.
SrcSize - The size of source buffer
Destination - The destination buffer to store the decompressed data
DstSize - The size of destination buffer.
Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data.
ScratchSize - The size of scratch buffer.
Returns:
EFI_SUCCESS - Decompression is successfull
EFI_INVALID_PARAMETER - The source data is corrupted
--*/
{
//
// For Tiano de/compression algorithm, the version is 2.
//
return Decompress (
Source,
SrcSize,
Destination,
DstSize,
Scratch,
ScratchSize,
2
);
}

185
Tiano/EfiTianoDecompress.h Normal file
View file

@ -0,0 +1,185 @@
/*++
Copyright (c) 2004 - 2006, Intel Corporation. All rights reserved.<BR>
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,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
Decompress.h
Abstract:
Header file for decompression routine.
Providing both EFI and Tiano decompress algorithms.
--*/
#ifndef _EFITIANODECOMPRESS_H_
#define _EFITIANODECOMPRESS_H_
#include <string.h>
#include <stdlib.h>
#include "../basetypes.h"
#ifdef __cplusplus
extern "C" {
#endif
UINT32
EFIAPI
EfiGetInfo (
VOID *Source,
UINT32 SrcSize,
UINT32 *DstSize,
UINT32 *ScratchSize
)
/*++
Routine Description:
The implementation is same as that of EFI_DECOMPRESS_PROTOCOL.GetInfo().
Arguments:
This - The protocol instance pointer
Source - The source buffer containing the compressed data.
SrcSize - The size of source buffer
DstSize - The size of destination buffer.
ScratchSize - The size of scratch buffer.
Returns:
EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved.
EFI_INVALID_PARAMETER - The source data is corrupted
--*/
;
UINT32
EFIAPI
EfiDecompress (
VOID *Source,
UINT32 SrcSize,
VOID *Destination,
UINT32 DstSize,
VOID *Scratch,
UINT32 ScratchSize
)
/*++
Routine Description:
The implementation is same as that of EFI_DECOMPRESS_PROTOCOL.Decompress().
Arguments:
This - The protocol instance pointer
Source - The source buffer containing the compressed data.
SrcSize - The size of source buffer
Destination - The destination buffer to store the decompressed data
DstSize - The size of destination buffer.
Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data.
ScratchSize - The size of scratch buffer.
Returns:
EFI_SUCCESS - Decompression is successfull
EFI_INVALID_PARAMETER - The source data is corrupted
--*/
;
UINT32
EFIAPI
TianoGetInfo (
VOID *Source,
UINT32 SrcSize,
UINT32 *DstSize,
UINT32 *ScratchSize
)
/*++
Routine Description:
The implementation is same as that of EFI_TIANO_DECOMPRESS_PROTOCOL.GetInfo().
Arguments:
This - The protocol instance pointer
Source - The source buffer containing the compressed data.
SrcSize - The size of source buffer
DstSize - The size of destination buffer.
ScratchSize - The size of scratch buffer.
Returns:
EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved.
EFI_INVALID_PARAMETER - The source data is corrupted
--*/
;
UINT32
EFIAPI
TianoDecompress (
VOID *Source,
UINT32 SrcSize,
VOID *Destination,
UINT32 DstSize,
VOID *Scratch,
UINT32 ScratchSize
)
/*++
Routine Description:
The implementation is same as that of EFI_TIANO_DECOMPRESS_PROTOCOL.Decompress().
Arguments:
This - The protocol instance pointer
Source - The source buffer containing the compressed data.
SrcSize - The size of source buffer
Destination - The destination buffer to store the decompressed data
DstSize - The size of destination buffer.
Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data.
ScratchSize - The size of scratch buffer.
Returns:
EFI_SUCCESS - Decompression is successfull
EFI_INVALID_PARAMETER - The source data is corrupted
--*/
;
typedef
UINT32
(*GETINFO_FUNCTION) (
VOID *Source,
UINT32 SrcSize,
UINT32 *DstSize,
UINT32 *ScratchSize
);
typedef
UINT32
(*DECOMPRESS_FUNCTION) (
VOID *Source,
UINT32 SrcSize,
VOID *Destination,
UINT32 DstSize,
VOID *Scratch,
UINT32 ScratchSize
);
#ifdef __cplusplus
}
#endif
#endif

1753
Tiano/TianoCompress.c Normal file

File diff suppressed because it is too large Load diff

86
basetypes.h Normal file
View file

@ -0,0 +1,86 @@
/* basetypes.h
Copyright (c) 2013, 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,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#ifndef __BASETYPES_H__
#define __BASETYPES_H__
#include <stdarg.h>
#include <stdint.h>
typedef uint8_t BOOLEAN;
typedef int8_t INT8;
typedef uint8_t UINT8;
typedef int16_t INT16;
typedef uint16_t UINT16;
typedef int32_t INT32;
typedef uint32_t UINT32;
typedef int64_t INT64;
typedef uint64_t UINT64;
typedef char CHAR8;
typedef uint16_t CHAR16;
#define CONST const
#define VOID void
#define STATIC static
#ifndef TRUE
#define TRUE ((BOOLEAN)(1==1))
#endif
#ifndef FALSE
#define FALSE ((BOOLEAN)(0==1))
#endif
#ifndef NULL
#define NULL ((VOID *) 0)
#endif
#if _MSC_EXTENSIONS
//
// Microsoft* compiler requires _EFIAPI useage, __cdecl is Microsoft* specific C.
//
#define EFIAPI __cdecl
#endif
#if __GNUC__
#define EFIAPI __attribute__((cdecl))
#endif
#define ERR_SUCCESS 0
#define ERR_INVALID_PARAMETER 1
#define ERR_BUFFER_TOO_SMALL 2
#define ERR_OUT_OF_RESOURCES 3
#define ERR_OUT_OF_MEMORY 4
#define ERR_FILE_OPEN 5
#define ERR_FILE_READ 6
#define ERR_FILE_WRITE 7
#define ERR_INVALID_FLASH_DESCRIPTOR 8
#define ERR_BIOS_REGION_NOT_FOUND 9
#define ERR_VOLUMES_NOT_FOUND 10
#define ERR_INVALID_VOLUME 11
#define ERR_VOLUME_REVISION_NOT_SUPPORTED 12
#define ERR_UNKNOWN_FFS 13
// EFI GUID
typedef struct{
UINT8 Data[16];
} EFI_GUID;
#define ALIGN4(Value) (((Value)+3) & ~3)
#define ALIGN8(Value) (((Value)+7) & ~7)
#include <assert.h>
#define ASSERT(x) assert(x)
#endif

34
descriptor.cpp Normal file
View file

@ -0,0 +1,34 @@
/* descriptor.cpp
Copyright (c) 2013, 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 "descriptor.h"
// Calculate address of data structure addressed by descriptor address format
// 8 bit base or limit
UINT8* calculateAddress8(UINT8* baseAddress, const UINT8 baseOrLimit)
{
return baseAddress + baseOrLimit * 0x10;
}
// 16 bit base or limit
UINT8* calculateAddress16(UINT8* baseAddress, const UINT16 baseOrLimit)
{
return baseAddress + baseOrLimit * 0x1000;
}
//Calculate size of region using its base and limit
UINT32 calculateRegionSize(const UINT16 base, const UINT16 limit)
{
if (limit)
return (limit + 1 - base) * 0x1000;
return 0;
}

163
descriptor.h Normal file
View file

@ -0,0 +1,163 @@
/* descriptor.h
Copyright (c) 2013, 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 __DESCRIPTOR_H__
#define __DESCRIPTOR_H__
#include "basetypes.h"
// Make sure we use right packing rules
#pragma pack(push,1)
// Flash descriptor header
typedef struct {
UINT8 FfVector[16]; // Must be 16 0xFFs
UINT32 Signature; // 0x0FF0A55A
} FLASH_DESCRIPTOR_HEADER;
// Flash descriptor signature
#define FLASH_DESCRIPTOR_SIGNATURE 0x0FF0A55A
// Descriptor region size
#define FLASH_DESCRIPTOR_SIZE 0x1000
// Descriptor map
// Base fields are storing bits [11:4] of actual base addresses, all other bits are 0
typedef struct {
UINT8 ComponentBase; // 0x03 on most machines
UINT8 NumberOfFlashChips; // Zero-based number of flash chips installed on board
UINT8 RegionBase; // 0x04 on most machines
UINT8 NumberOfRegions; // Zero-based number of flash regions (descriptor is always included)
UINT8 MasterBase; // 0x06 on most machines
UINT8 NumberOfMasters; // Zero-based number of flash masters
UINT8 PchStrapsBase; // 0x10 on most machines
UINT8 NumberOfPchStraps; // One-based number of UINT32s to read as PCH Straps, min=0, max=255 (1 Kb)
UINT8 ProcStrapsBase; // 0x20 on most machines
UINT8 NumberOfProcStraps; // Number of PROC staps to be read, can be 0 or 1
UINT8 IccTableBase; // 0x21 on most machines
UINT8 NumberOfIccTableEntries; // 0x00 on most machines
UINT8 DmiTableBase; // 0x25 on most machines
UINT8 NumberOfDmiTableEntries; // 0x00 on most machines
UINT16 ReservedZero; // Still unknown, zeroes in all descriptors I have seen
} FLASH_DESCRIPTOR_MAP;
// Component section
// Flash parameters dword structure
typedef struct {
UINT8 FirstChipDensity : 3;
UINT8 SecondFlashDensity : 3;
UINT8 ReservedZero0 : 2; // Still unknown, zeroes in all descriptors I have seen
UINT8 ReservedZero1 : 8; // Still unknown, zeroes in all descriptors I have seen
UINT8 ReservedZero2 : 4; // Still unknown, zeroes in all descriptors I have seen
UINT8 FastReadEnabled : 1;
UINT8 FastReadFreqency : 3;
UINT8 FlashReadStatusFrequency : 3;
UINT8 FlashWriteFrequency : 3;
UINT8 DualOutputFastReadSupported : 1;
UINT8 ReservedZero3 : 1; // Still unknown, zero in all descriptors I have seen
} FLASH_PARAMETERS;
// Flash densities
#define FLASH_DENSITY_512KB 0x00
#define FLASH_DENSITY_1MB 0x01
#define FLASH_DENSITY_2MB 0x02
#define FLASH_DENSITY_4MB 0x03
#define FLASH_DENSITY_8MB 0x04
#define FLASH_DENSITY_16MB 0x05
// Flash frequences
#define FLASH_FREQUENCY_20MHZ 0x00
#define FLASH_FREQUENCY_33MHZ 0x01
#define FLASH_FREQUENCY_50MHZ 0x04
// Component section structure
typedef struct {
FLASH_PARAMETERS FlashParameters;
UINT8 InvalidInstruction0; // Instructions for SPI chip, that must not be executed, like FLASH ERASE
UINT8 InvalidInstruction1; //
UINT8 InvalidInstruction2; //
UINT8 InvalidInstruction3; //
UINT16 PartitionBoundary; // Upper 16 bit of partition boundary address. Default is 0x0000, which makes the boundary to be 0x00001000
UINT16 RezervedZero; // Still unknown, zero in all descriptors I have seen
} FLASH_DESCRIPTOR_COMPONENT_SECTION;
// Region section
// All base and limit register are storing upper part of actual UINT32 base and limit
// If limit is zero - region is not present
typedef struct {
UINT16 RezervedZero; // Still unknown, zero in all descriptors I have seen
UINT16 FlashBlockEraseSize; // Size of block erased by single BLOCK ERASE command
UINT16 BiosBase;
UINT16 BiosLimit;
UINT16 MeBase;
UINT16 MeLimit;
UINT16 GbeBase;
UINT16 GbeLimit;
UINT16 PdrBase;
UINT16 PdrLimit;
} FLASH_DESCRIPTOR_REGION_SECTION;
// Flash block erase sizes
#define FLASH_BLOCK_ERASE_SIZE_4KB 0x0000
#define FLASH_BLOCK_ERASE_SIZE_8KB 0x0001
#define FLASH_BLOCK_ERASE_SIZE_64KB 0x000F
// Master section
typedef struct {
UINT16 BiosId;
UINT8 BiosRead;
UINT8 BiosWrite;
UINT16 MeId;
UINT8 MeRead;
UINT8 MeWrite;
UINT16 GbeId;
UINT8 GbeRead;
UINT8 GbeWrite;
} FLASH_DESCRIPTOR_MASTER_SECTION;
//!TODO: Describe PCH and PROC straps sections, as well as ICC and DMI tables
// Base address of descriptor upper map
#define FLASH_DESCRIPTOR_UPPER_MAP_BASE 0x0EFC
// Descriptor upper map structure
typedef struct {
UINT8 VsccTableBase; // Base address of VSCC Table for ME, bits [11:4]
UINT8 VsccTableSize; // Counted in UINT32s
UINT16 ReservedZero; // Still unknown, zero in all descriptors I have seen
} FLASH_DESCRIPTOR_UPPER_MAP;
// VSCC table entry structure
typedef struct {
UINT8 VendorId; // JEDEC VendorID byte
UINT8 DeviceId0; // JEDEC DeviceID first byte
UINT8 DeviceId1; // JEDEC DeviceID second byte
UINT8 ReservedZero; // Reserved, must be zero
UINT32 VsccId; // VSCC ID, normally it is 0x20052005 or 0x20152015
} VSCC_TABLE_ENTRY;
// Base address and size of OEM section
#define FLASH_DESCRIPTOR_OEM_SECTION_BASE 0x0F00
#define FLASH_DESCRIPTOR_OEM_SECTION_SIZE 0xFF
// Restore previous packing rules
#pragma pack(pop)
// Calculate address of data structure addressed by descriptor address format
// 8 bit base or limit
UINT8* calculateAddress8(UINT8* baseAddress, const UINT8 baseOrLimit);
// 16 bit base or limit
UINT8* calculateAddress16(UINT8* baseAddress, const UINT16 baseOrLimit);
//Calculate size of region using its base and limit
size_t calculateRegionSize(const UINT16 base, const UINT16 limit);
#endif

151
ffs.cpp Normal file
View file

@ -0,0 +1,151 @@
/* ffs.cpp
Copyright (c) 2013, 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 "ffs.h"
const UINT8 ffsAlignmentTable[] =
{0, 4, 7, 9, 10, 12, 15, 16};
UINT8 calculateChecksum8(UINT8* buffer, UINT32 bufferSize)
{
UINT8 counter = 0;
while(bufferSize--)
counter += buffer[bufferSize];
return ~counter + 1;
}
UINT16 calculateChecksum16(UINT8* buffer, UINT32 bufferSize)
{
UINT16 counter = 0;
while(bufferSize--)
counter += buffer[bufferSize];
return ~counter + 1;
}
VOID uint32ToUint24(UINT32 size, UINT8* ffsSize)
{
ffsSize[2] = (UINT8) ((size) >> 16);
ffsSize[1] = (UINT8) ((size) >> 8);
ffsSize[0] = (UINT8) ((size) );
}
UINT32 uint24ToUint32(UINT8* ffsSize)
{
return (ffsSize[2] << 16) +
(ffsSize[1] << 8) +
ffsSize[0];
}
QString guidToQString(const EFI_GUID guid)
{
QByteArray baGuid = QByteArray::fromRawData((const char*) guid.Data, sizeof(EFI_GUID));
UINT32 i32 = *(UINT32*)baGuid.left(4).constData();
UINT16 i16_0 = *(UINT16*)baGuid.mid(4, 2).constData();
UINT16 i16_1 = *(UINT16*)baGuid.mid(6, 2).constData();
UINT8 i8_0 = *(UINT8*)baGuid.mid(8, 1).constData();
UINT8 i8_1 = *(UINT8*)baGuid.mid(9, 1).constData();
UINT8 i8_2 = *(UINT8*)baGuid.mid(10, 1).constData();
UINT8 i8_3 = *(UINT8*)baGuid.mid(11, 1).constData();
UINT8 i8_4 = *(UINT8*)baGuid.mid(12, 1).constData();
UINT8 i8_5 = *(UINT8*)baGuid.mid(13, 1).constData();
UINT8 i8_6 = *(UINT8*)baGuid.mid(14, 1).constData();
UINT8 i8_7 = *(UINT8*)baGuid.mid(15, 1).constData();
return QString("%1-%2-%3-%4%5-%6%7%8%9%10%11")
.arg(i32, 8, 16, QChar('0'))
.arg(i16_0, 4, 16, QChar('0'))
.arg(i16_1, 4, 16, QChar('0'))
.arg(i8_0, 2, 16, QChar('0'))
.arg(i8_1, 2, 16, QChar('0'))
.arg(i8_2, 2, 16, QChar('0'))
.arg(i8_3, 2, 16, QChar('0'))
.arg(i8_4, 2, 16, QChar('0'))
.arg(i8_5, 2, 16, QChar('0'))
.arg(i8_6, 2, 16, QChar('0'))
.arg(i8_7, 2, 16, QChar('0')).toUpper();
}
QString fileTypeToQString(const UINT8 type)
{
switch (type)
{
case EFI_FV_FILETYPE_RAW:
return QObject::tr("Raw");
case EFI_FV_FILETYPE_FREEFORM:
return QObject::tr("Freeform");
case EFI_FV_FILETYPE_SECURITY_CORE:
return QObject::tr("Security core");
case EFI_FV_FILETYPE_PEI_CORE:
return QObject::tr("PEI core");
case EFI_FV_FILETYPE_DXE_CORE:
return QObject::tr("DXE core");
case EFI_FV_FILETYPE_PEIM:
return QObject::tr("PEI module");
case EFI_FV_FILETYPE_DRIVER:
return QObject::tr("DXE driver");
case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
return QObject::tr("Combined PEI/DXE");
case EFI_FV_FILETYPE_APPLICATION:
return QObject::tr("Application");
case EFI_FV_FILETYPE_SMM:
return QObject::tr("SMM module");
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_PAD:
return QObject::tr("Pad");
default:
return QObject::tr("Unknown");
};
}
QString sectionTypeToQString(const UINT8 type)
{
switch (type)
{
case EFI_SECTION_COMPRESSION:
return QObject::tr("Compressed");
case EFI_SECTION_GUID_DEFINED:
return QObject::tr("GUID defined");
case EFI_SECTION_DISPOSABLE:
return QObject::tr("Disposable");
case EFI_SECTION_PE32:
return QObject::tr("PE32+ image");
case EFI_SECTION_PIC:
return QObject::tr("PIC image");
case EFI_SECTION_TE:
return QObject::tr("TE image");
case EFI_SECTION_DXE_DEPEX:
return QObject::tr("DXE dependency");
case EFI_SECTION_VERSION:
return QObject::tr("Version");
case EFI_SECTION_USER_INTERFACE:
return QObject::tr("User interface");
case EFI_SECTION_COMPATIBILITY16:
return QObject::tr("16-bit image");
case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
return QObject::tr("Volume image");
case EFI_SECTION_FREEFORM_SUBTYPE_GUID:
return QObject::tr("Freeform subtype GUID");
case EFI_SECTION_RAW:
return QObject::tr("Raw");
case EFI_SECTION_PEI_DEPEX:
return QObject::tr("PEI dependency");
case EFI_SECTION_SMM_DEPEX:
return QObject::tr("SMM dependency");
default:
return QObject::tr("Unknown");
}
}

415
ffs.h Normal file
View file

@ -0,0 +1,415 @@
/* ffs.h
Copyright (c) 2013, 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 __FFS_H__
#define __FFS_H__
#include <QByteArray>
#include <QString>
#include <QObject>
#include "basetypes.h"
// C++ functions
// GUID to QString routine
extern QString guidToQString(const EFI_GUID guid);
// File type to QString routine
extern QString fileTypeToQString(const UINT8 type);
// Section type to QString routine
extern QString sectionTypeToQString(const UINT8 type);
#ifdef __cplusplus
extern "C" {
#endif
// Make sure we use right packing rules
#pragma pack(push,1)
//*****************************************************************************
// EFI Capsule
//*****************************************************************************
// Capsule header
typedef struct {
EFI_GUID CapsuleGuid;
UINT32 HeaderSize;
UINT32 Flags;
UINT32 CapsuleImageSize;
} EFI_CAPSULE_HEADER;
// Capsule flags
#define EFI_CAPSULE_HEADER_FLAG_SETUP 0x00000001
#define EFI_CAPSULE_HEADER_FLAG_PERSIST_ACROSS_RESET 0x00010000
#define EFI_CAPSULE_HEADER_FLAG_POPULATE_SYSTEM_TABLE 0x00020000
// Standard EFI capsule GUID
const QByteArray EFI_CAPSULE_GUID("\xBD\x86\x66\x3B\x76\x0D\x30\x40\xB7\x0E\xB5\x51\x9E\x2F\xC5\xA0", 16);
// AMI Aptio extended capsule header
typedef struct {
EFI_CAPSULE_HEADER CapsuleHeader;
UINT16 RomImageOffset; // offset in bytes from the beginning of the capsule header to the start of
// the capsule volume
//!TODO: Enable certificate and rom layout reading
//UINT16 RomLayoutOffset; // offset to the table of the module descriptors in the capsule's volume
// that are included in the signature calculation
//FW_CERTIFICATE FWCert;
//ROM_AREA RomAreaMap[1];
} APTIO_CAPSULE_HEADER;
// AMI Aptio extended capsule GUID
const QByteArray APTIO_CAPSULE_GUID("\x8B\xA6\x3C\x4A\x23\x77\xFB\x48\x80\x3D\x57\x8C\xC1\xFE\xC4\x4D", 16);
//*****************************************************************************
// EFI Firmware Volume
//*****************************************************************************
// Firmware block map entry
// FvBlockMap ends with an entry {0x00000000, 0x00000000}
typedef struct {
UINT32 NumBlocks;
UINT32 BlockLength;
} EFI_FV_BLOCK_MAP_ENTRY;
// Volume header
typedef struct {
UINT8 ZeroVector[16];
EFI_GUID FileSystemGuid;
UINT64 FvLength;
UINT32 Signature;
UINT32 Attributes;
UINT16 HeaderLength;
UINT16 Checksum;
UINT16 ExtHeaderOffset; //Reserved in Revision 1
UINT8 Reserved[1];
UINT8 Revision;
//EFI_FV_BLOCK_MAP_ENTRY FvBlockMap[1];
} EFI_FIRMWARE_VOLUME_HEADER;
// Filesystem GUIDs
const QByteArray EFI_FIRMWARE_FILE_SYSTEM_GUID
("\xD9\x54\x93\x7A\x68\x04\x4A\x44\x81\xCE\x0B\xF6\x17\xD8\x90\xDF", 16);
const QByteArray EFI_FIRMWARE_FILE_SYSTEM2_GUID
("\x78\xE5\x8C\x8C\x3D\x8A\x1C\x4F\x99\x35\x89\x61\x85\xC3\x2D\xD3", 16);
// Firmware volume signature
const QByteArray EFI_FV_SIGNATURE("_FVH", 4);
#define EFI_FV_SIGNATURE_OFFSET 0x28
// Firmware volume attributes
// Revision 1
#define EFI_FVB_READ_DISABLED_CAP 0x00000001
#define EFI_FVB_READ_ENABLED_CAP 0x00000002
#define EFI_FVB_READ_STATUS 0x00000004
#define EFI_FVB_WRITE_DISABLED_CAP 0x00000008
#define EFI_FVB_WRITE_ENABLED_CAP 0x00000010
#define EFI_FVB_WRITE_STATUS 0x00000020
#define EFI_FVB_LOCK_CAP 0x00000040
#define EFI_FVB_LOCK_STATUS 0x00000080
#define EFI_FVB_STICKY_WRITE 0x00000200
#define EFI_FVB_MEMORY_MAPPED 0x00000400
#define EFI_FVB_ERASE_POLARITY 0x00000800
#define EFI_FVB_ALIGNMENT_CAP 0x00008000
#define EFI_FVB_ALIGNMENT_2 0x00010000
#define EFI_FVB_ALIGNMENT_4 0x00020000
#define EFI_FVB_ALIGNMENT_8 0x00040000
#define EFI_FVB_ALIGNMENT_16 0x00080000
#define EFI_FVB_ALIGNMENT_32 0x00100000
#define EFI_FVB_ALIGNMENT_64 0x00200000
#define EFI_FVB_ALIGNMENT_128 0x00400000
#define EFI_FVB_ALIGNMENT_256 0x00800000
#define EFI_FVB_ALIGNMENT_512 0x01000000
#define EFI_FVB_ALIGNMENT_1K 0x02000000
#define EFI_FVB_ALIGNMENT_2K 0x04000000
#define EFI_FVB_ALIGNMENT_4K 0x08000000
#define EFI_FVB_ALIGNMENT_8K 0x10000000
#define EFI_FVB_ALIGNMENT_16K 0x20000000
#define EFI_FVB_ALIGNMENT_32K 0x40000000
#define EFI_FVB_ALIGNMENT_64K 0x80000000
// Revision 2
#define EFI_FVB2_READ_DISABLED_CAP 0x00000001
#define EFI_FVB2_READ_ENABLED_CAP 0x00000002
#define EFI_FVB2_READ_STATUS 0x00000004
#define EFI_FVB2_WRITE_DISABLED_CAP 0x00000008
#define EFI_FVB2_WRITE_ENABLED_CAP 0x00000010
#define EFI_FVB2_WRITE_STATUS 0x00000020
#define EFI_FVB2_LOCK_CAP 0x00000040
#define EFI_FVB2_LOCK_STATUS 0x00000080
#define EFI_FVB2_STICKY_WRITE 0x00000200
#define EFI_FVB2_MEMORY_MAPPED 0x00000400
#define EFI_FVB2_ERASE_POLARITY 0x00000800
#define EFI_FVB2_READ_LOCK_CAP 0x00001000
#define EFI_FVB2_READ_LOCK_STATUS 0x00002000
#define EFI_FVB2_WRITE_LOCK_CAP 0x00004000
#define EFI_FVB2_WRITE_LOCK_STATUS 0x00008000
#define EFI_FVB2_ALIGNMENT 0x001F0000
#define EFI_FVB2_ALIGNMENT_1 0x00000000
#define EFI_FVB2_ALIGNMENT_2 0x00010000
#define EFI_FVB2_ALIGNMENT_4 0x00020000
#define EFI_FVB2_ALIGNMENT_8 0x00030000
#define EFI_FVB2_ALIGNMENT_16 0x00040000
#define EFI_FVB2_ALIGNMENT_32 0x00050000
#define EFI_FVB2_ALIGNMENT_64 0x00060000
#define EFI_FVB2_ALIGNMENT_128 0x00070000
#define EFI_FVB2_ALIGNMENT_256 0x00080000
#define EFI_FVB2_ALIGNMENT_512 0x00090000
#define EFI_FVB2_ALIGNMENT_1K 0x000A0000
#define EFI_FVB2_ALIGNMENT_2K 0x000B0000
#define EFI_FVB2_ALIGNMENT_4K 0x000C0000
#define EFI_FVB2_ALIGNMENT_8K 0x000D0000
#define EFI_FVB2_ALIGNMENT_16K 0x000E0000
#define EFI_FVB2_ALIGNMENT_32K 0x000F0000
#define EFI_FVB2_ALIGNMENT_64K 0x00100000
#define EFI_FVB2_ALIGNMENT_128K 0x00110000
#define EFI_FVB2_ALIGNMENT_256K 0x00120000
#define EFI_FVB2_ALIGNMENT_512K 0x00130000
#define EFI_FVB2_ALIGNMENT_1M 0x00140000
#define EFI_FVB2_ALIGNMENT_2M 0x00150000
#define EFI_FVB2_ALIGNMENT_4M 0x00160000
#define EFI_FVB2_ALIGNMENT_8M 0x00170000
#define EFI_FVB2_ALIGNMENT_16M 0x00180000
#define EFI_FVB2_ALIGNMENT_32M 0x00190000
#define EFI_FVB2_ALIGNMENT_64M 0x001A0000
#define EFI_FVB2_ALIGNMENT_128M 0x001B0000
#define EFI_FVB2_ALIGNMENT_256M 0x001C0000
#define EFI_FVB2_ALIGNMENT_512M 0x001D0000
#define EFI_FVB2_ALIGNMENT_1G 0x001E0000
#define EFI_FVB2_ALIGNMENT_2G 0x001F0000
#define EFI_FVB2_WEAK_ALIGNMENT 0x80000000
// Extended firmware volume header
typedef struct {
EFI_GUID FvName;
UINT32 ExtHeaderSize;
} EFI_FIRMWARE_VOLUME_EXT_HEADER;
// Extended header entry
// The extended header entries follow each other and are
// terminated by ExtHeaderType EFI_FV_EXT_TYPE_END
#define EFI_FV_EXT_TYPE_END 0x00
typedef struct {
UINT16 ExtEntrySize;
UINT16 ExtEntryType;
} EFI_FIRMWARE_VOLUME_EXT_ENTRY;
// GUID that maps OEM file types to GUIDs
#define EFI_FV_EXT_TYPE_OEM_TYPE 0x01
typedef struct {
EFI_FIRMWARE_VOLUME_EXT_ENTRY Header;
UINT32 TypeMask;
//EFI_GUID Types[1];
} EFI_FIRMWARE_VOLUME_EXT_HEADER_OEM_TYPE;
#define EFI_FV_EXT_TYPE_GUID_TYPE 0x02
typedef struct {
EFI_FIRMWARE_VOLUME_EXT_ENTRY Header;
EFI_GUID FormatType;
//UINT8 Data[];
} EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE;
// Volume header 16bit checksum calculation routine
extern UINT16 calculateChecksum16(UINT8* buffer, UINT32 bufferSize);
//*****************************************************************************
// EFI FFS File
//*****************************************************************************
// Integrity check
typedef union {
struct {
UINT8 Header;
UINT8 File;
} Checksum;
UINT16 TailReference; // Revision 1
UINT16 Checksum16; // Revision 2
} EFI_FFS_INTEGRITY_CHECK;
// File header
typedef struct {
EFI_GUID Name;
EFI_FFS_INTEGRITY_CHECK IntegrityCheck;
UINT8 Type;
UINT8 Attributes;
UINT8 Size[3];
UINT8 State;
} EFI_FFS_FILE_HEADER;
// Large file header
//typedef struct {
// EFI_GUID Name;
// EFI_FFS_INTEGRITY_CHECK IntegrityCheck;
// UINT8 Type;
// UINT8 Attributes;
// UINT8 Size[3];
// UINT8 State;
// UINT12 ExtendedSize;
//} EFI_FFS_FILE_HEADER2;
// Standart data checksum, used if FFS_ATTRIB_CHECKSUM is clear
#define FFS_FIXED_CHECKSUM 0x5A
#define FFS_FIXED_CHECKSUM2 0xAA
// File types
#define EFI_FV_FILETYPE_ALL 0x00
#define EFI_FV_FILETYPE_RAW 0x01
#define EFI_FV_FILETYPE_FREEFORM 0x02
#define EFI_FV_FILETYPE_SECURITY_CORE 0x03
#define EFI_FV_FILETYPE_PEI_CORE 0x04
#define EFI_FV_FILETYPE_DXE_CORE 0x05
#define EFI_FV_FILETYPE_PEIM 0x06
#define EFI_FV_FILETYPE_DRIVER 0x07
#define EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER 0x08
#define EFI_FV_FILETYPE_APPLICATION 0x09
#define EFI_FV_FILETYPE_SMM 0x0A
#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_OEM_MIN 0xC0
#define EFI_FV_FILETYPE_OEM_MAX 0xDF
#define EFI_FV_FILETYPE_DEBUG_MIN 0xE0
#define EFI_FV_FILETYPE_DEBUG_MAX 0xEF
#define EFI_FV_FILETYPE_PAD 0xF0
#define EFI_FV_FILETYPE_FFS_MIN 0xF0
#define EFI_FV_FILETYPE_FFS_MAX 0xFF
// File attributes
// Revision 1
#define FFS_ATTRIB_TAIL_PRESENT 0x01
#define FFS_ATTRIB_RECOVERY 0x02
//#define FFS_ATTRIB_HEADER_EXTENSION 0x04 //Must be set to zero in Revision 1
#define FFS_ATTRIB_DATA_ALIGNMENT 0x38
#define FFS_ATTRIB_CHECKSUM 0x40
// Revision 2
#define FFS_ATTRIB_LARGE_FILE 0x01
#define FFS_ATTRIB_FIXED 0x04
// FFS alignment table
extern const UINT8 ffsAlignmentTable[];
// File states
#define EFI_FILE_HEADER_CONSTRUCTION 0x01
#define EFI_FILE_HEADER_VALID 0x02
#define EFI_FILE_DATA_VALID 0x04
#define EFI_FILE_MARKED_FOR_UPDATE 0x08
#define EFI_FILE_DELETED 0x10
#define EFI_FILE_HEADER_INVALID 0x20
// Volume top file
const QByteArray EFI_FFS_VOLUME_TOP_FILE_GUID
("\x2E\x06\xA0\x1B\x79\xC7\x82\x45\x85\x66\x33\x6A\xE8\xF7\x8F\x09", 16);
// FFS size convertion routines
extern VOID uint32ToUint24(UINT32 size, UINT8* ffsSize);
extern UINT32 uint24ToUint32(UINT8* ffsSize);
// FFS file 8bit checksum calculation routine
extern UINT8 calculateChecksum8(UINT8* buffer, UINT32 bufferSize);
//*****************************************************************************
// EFI FFS File Section
//*****************************************************************************
// Common section header
typedef struct {
UINT8 Size[3];
UINT8 Type;
} EFI_COMMON_SECTION_HEADER;
// Large file common section header
//typedef struct {
// UINT8 Size[3]; //Must be 0xFFFFFF for this header to be used
// UINT8 Type;
// UINT32 ExtendedSize;
//} EFI_COMMON_SECTION_HEADER2;
// File section types
#define EFI_SECTION_ALL 0x00 // Imposible attribute for file in the FS
// Encapsulation section types
#define EFI_SECTION_COMPRESSION 0x01
#define EFI_SECTION_GUID_DEFINED 0x02
#define EFI_SECTION_DISPOSABLE 0x03
// Leaf section types
#define EFI_SECTION_PE32 0x10
#define EFI_SECTION_PIC 0x11
#define EFI_SECTION_TE 0x12
#define EFI_SECTION_DXE_DEPEX 0x13
#define EFI_SECTION_VERSION 0x14
#define EFI_SECTION_USER_INTERFACE 0x15
#define EFI_SECTION_COMPATIBILITY16 0x16
#define EFI_SECTION_FIRMWARE_VOLUME_IMAGE 0x17
#define EFI_SECTION_FREEFORM_SUBTYPE_GUID 0x18
#define EFI_SECTION_RAW 0x19
#define EFI_SECTION_PEI_DEPEX 0x1B
#define EFI_SECTION_SMM_DEPEX 0x1C
// Compression section
typedef struct {
UINT8 Size[3];
UINT8 Type;
UINT32 UncompressedLength;
UINT8 CompressionType;
} EFI_COMPRESSION_SECTION;
// Compression types
#define EFI_NOT_COMPRESSED 0x00
#define EFI_STANDARD_COMPRESSION 0x01 //Tiano for Revision 2, EFI for Revision 1
#define EFI_CUSTOMIZED_COMPRESSION 0x02 //LZMA for Revision 2 Tiano for Revision 1
//GUID defined section
typedef struct {
UINT8 Size[3];
UINT8 Type;
EFI_GUID SectionDefinitionGuid;
UINT16 DataOffset;
UINT16 Attributes;
} EFI_GUID_DEFINED_SECTION;
// Attributes for GUID defined section
#define EFI_GUIDED_SECTION_PROCESSING_REQUIRED 0x01
#define EFI_GUIDED_SECTION_AUTH_STATUS_VALID 0x02
// Version section
typedef struct {
UINT8 Size[3];
UINT8 Type;
UINT16 BuildNumber;
//CHAR16 VersionString[1];
} EFI_VERSION_SECTION;
// Freeform subtype GUID section
typedef struct {
UINT8 Size[3];
UINT8 Type;
EFI_GUID SubTypeGuid;
} EFI_FREEFORM_SUBTYPE_GUID_SECTION;
// User interface section
typedef struct {
UINT8 Size[3];
UINT8 Type;
//CHAR16 FileNameString[1];
} EFI_USER_INTERFACE_SECTION;
// Other sections
typedef EFI_COMMON_SECTION_HEADER EFI_DISPOSABLE_SECTION;
typedef EFI_COMMON_SECTION_HEADER EFI_RAW_SECTION;
typedef EFI_COMMON_SECTION_HEADER EFI_DXE_DEPEX_SECTION;
typedef EFI_COMMON_SECTION_HEADER EFI_PEI_DEPEX_SECTION;
typedef EFI_COMMON_SECTION_HEADER EFI_SMM_DEPEX_SECTION;
typedef EFI_COMMON_SECTION_HEADER EFI_PE32_SECTION;
typedef EFI_COMMON_SECTION_HEADER EFI_PIC_SECTION;
typedef EFI_COMMON_SECTION_HEADER EFI_TE_SECTION;
typedef EFI_COMMON_SECTION_HEADER EFI_COMPATIBILITY16_SECTION;
typedef EFI_COMMON_SECTION_HEADER EFI_FIRMWARE_VOLUME_IMAGE_SECTION;
// Restore previous packing rules
#pragma pack(pop)
#ifdef __cplusplus
}
#endif
#endif

28
main.cpp Normal file
View file

@ -0,0 +1,28 @@
/* main.cpp
Copyright (c) 2013, 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,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#include <QApplication>
#include <QString>
#include "uefitool.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
UEFITool w;
if (a.arguments().length() > 1)
w.openImageFile(a.arguments().at(1));
w.show();
return a.exec();
}

520
parse.cpp Normal file
View file

@ -0,0 +1,520 @@
/* parse.cpp
Copyright (c) 2013, 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 "parse.h"
// Implementation of GNU memmem function using Boyer-Moore-Horspool algorithm
UINT8* find_pattern(UINT8* string, UINT32 slen, CONST UINT8* pattern, UINT32 plen)
{
UINT32 scan = 0;
UINT32 bad_char_skip[256];
UINT32 last;
if (plen == 0 || !string || !pattern)
return NULL;
for (scan = 0; scan <= 255; scan++)
bad_char_skip[scan] = plen;
last = plen - 1;
for (scan = 0; scan < last; scan++)
bad_char_skip[pattern[scan]] = last - scan;
while (slen >= plen)
{
for (scan = last; string[scan] == pattern[scan]; scan--)
if (scan == 0)
return string;
slen -= bad_char_skip[string[last]];
string += bad_char_skip[string[last]];
}
return NULL;
}
UINT8 write_to_file(UINT8* buffer, CONST size_t size, const char* name, const char* extension)
{
/*char str[_MAX_PATH]; // Buffer for file name construction
FILE* file;
sprintf(str, "%s.%s", name, extension);
file = fopen((const char*) str, "wb");
if (!file) {
printf("Can't create %s file\n", str);
return ERR_FILE_OPEN;
}
if (fwrite(buffer, sizeof(UINT8), size, file) != size) {
printf("Can't write %s file\n", str);
return ERR_FILE_WRITE;
}
fclose(file);*/
return ERR_SUCCESS;
}
UINT8* parse_region(UINT8* buffer, size_t size, CONST BOOLEAN two_flash_chips, const char* region_name, CONST UINT16 region_base, CONST UINT16 region_limit)
{
UINT8 result = ERR_SUCCESS;
UINT8* region = NULL;
size_t region_size = calculate_region_size(region_base, region_limit);
if (!buffer || !size || !region_name || !region_size)
return NULL;
// Check region base to be in buffer
if (region_base >= size)
{
printf("Warning: %s region stored in descriptor is not found\n", region_name);
if (two_flash_chips)
printf("Two flash chips installed, so it could be in another flash chip\n"
"Make a dump from another flash chip and open it to view information about %s region\n", region_name);
else
printf("Error: one flash chip installed, so it is an error caused by damaged or incomplete dump\n");
printf("Warning: absence of %s region assumed\n", region_name);
return NULL;
}
// Check region to be fully present in buffer
else if (region_base + region_size > size)
{
printf("Warning: %s region stored in descriptor overlaps the end of opened file\n", region_name);
if (two_flash_chips)
printf("Two flash chips installed, so it could be in another flash chip\n"
"Make a dump from another flash chip and open it to view information about %s region\n", region_name);
else
printf("Error: One flash chip installed, so it is an error caused by damaged or incomplete dump\n");
printf("Warning: absence of %s region assumed\n", region_name);
return NULL;
}
// Calculate region address
region = calculate_address_16(buffer, region_base);
// Display information about region
printf("%s region found, size: %d (0x%08X)\n", region_name, region_size, region_size);
// Write all regions that has non-zero size to files
result = write_to_file(region, region_size, region_name, "region");
if (result){
printf("Error: Can't write %s region to file\n", region_name);
return NULL;
}
printf("%s region written to file\n", region_name);
return region;
}
UINT8* find_next_volume(UINT8* buffer, size_t buffer_size)
{
UINT8* pointer;
if (!buffer || !buffer_size)
return NULL;
pointer = find_pattern(buffer, buffer_size, FV_SIGNATURE_STR, FV_SIGNATURE_LENGTH);
if (pointer && pointer - FV_SIGNATURE_OFFSET >= buffer)
return pointer - FV_SIGNATURE_OFFSET;
return NULL;
}
UINT8 calculate_checksum_8(UINT8* buffer, size_t buffer_size)
{
UINT8 counter = 0;
while(buffer_size--)
counter += buffer[buffer_size];
return ~counter + 1;
}
UINT16 calculate_checksum_16(UINT8* buffer, size_t buffer_size)
{
UINT16 counter = 0;
while(buffer_size--)
counter += buffer[buffer_size];
return ~counter + 1;
}
// Format GUID to standard readable form
// Assumes str to have at least 37 bytes free
UINT8 format_guid(EFI_GUID* guid, char* str)
{
UINT8* guid1 = (UINT8*) guid;
UINT8* guid2 = guid1 + 4;
UINT8* guid3 = guid1 + 6;
UINT32* data1 = (UINT32*) guid1;
UINT16* data2 = (UINT16*) guid2;
UINT16* data3 = (UINT16*) guid3;
UINT8* data41 = guid1 + 8;
UINT8* data42 = guid1 + 9;
UINT8* data51 = guid1 + 10;
UINT8* data52 = guid1 + 11;
UINT8* data53 = guid1 + 12;
UINT8* data54 = guid1 + 13;
UINT8* data55 = guid1 + 14;
UINT8* data56 = guid1 + 15;
sprintf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", *data1, *data2, *data3, *data41, *data42,
*data51, *data52, *data53, *data54, *data55, *data56);
return ERR_SUCCESS;
}
VOID size_to_filesize(size_t size, UINT8* module_size)
{
module_size[2] = (UINT8) ((size) >> 16);
module_size[1] = (UINT8) ((size) >> 8);
module_size[0] = (UINT8) ((size) );
}
size_t filesize_to_size(UINT8* module_size)
{
return (module_size[2] << 16) +
(module_size[1] << 8) +
module_size[0];
}
UINT8 parse_volume(UINT8* buffer, size_t buffer_size, const char* prefix)
{
EFI_FIRMWARE_VOLUME_HEADER* volume_header;
UINT8* current_file;
char str[_MAX_PATH];
char guid[37]; // FD44820B-F1AB-41C0-AE4E-0C55556EB9BD for example
UINT8 empty_byte;
UINT8 result;
size_t header_size;
size_t file_size;
size_t files_counter = 0;
volume_header = (EFI_FIRMWARE_VOLUME_HEADER*) buffer;
if (volume_header->Signature != FV_SIGNATURE_INT)
return ERR_INVALID_VOLUME;
//!TODO: Check zero vector for code, so it could be a boot volume
// Check filesystem GUID to be known
// Check for FFS1
if (find_pattern((UINT8*)&volume_header->FileSystemGuid, sizeof(EFI_GUID), EFI_FIRMWARE_FILE_SYSTEM_GUID, sizeof(EFI_GUID)) == (UINT8*)&volume_header->FileSystemGuid) {
printf("File system: PI FFS v1\n");
// Check for FFS2
} else if (find_pattern((UINT8*)&volume_header->FileSystemGuid, sizeof(EFI_GUID), EFI_FIRMWARE_FILE_SYSTEM2_GUID, sizeof(EFI_GUID)) == (UINT8*)&volume_header->FileSystemGuid) {
printf("File system: PI FFS v2\n");
// Unknown FFS
} else {
printf("File system: unknown\nWarning: volume can't be parsed\n");
return ERR_UNKNOWN_FFS;
}
// Check attributes
// Determine erase polarity
if (volume_header->Attributes & EFI_FVB_ERASE_POLARITY)
empty_byte = 0xFF;
else
empty_byte = 0x00;
printf("Empty byte: 0x%02X\n", empty_byte);
// Check header checksum by recalculating it
if (!calculate_checksum_16(buffer, volume_header->HeaderLength)) {
printf("Warning: volume header checksum is invalid\nVolume can be inacessible for UEFI routines\n");
}
// Check for presence of extended header, only if header revision is not 1
if (volume_header->Revision > 1 && volume_header->ExtHeaderOffset) {
EFI_FIRMWARE_VOLUME_EXT_HEADER* extended_header;
extended_header = (EFI_FIRMWARE_VOLUME_EXT_HEADER*) (buffer + volume_header->ExtHeaderOffset);
result = format_guid(&extended_header->FvName, guid);
if (result)
return result;
printf("Extended header: present\n"
"Volume GUID: %s", guid);
header_size = volume_header->ExtHeaderOffset + extended_header->ExtHeaderSize;
} else {
printf("Extended header: none\n");
header_size = volume_header->HeaderLength;
}
//!TODO: Check block map to make enough space for the whole volume
// Find and parse all files in current volume
for(current_file = buffer + header_size; current_file && current_file < buffer + volume_header->FvLength - header_size;) {
EFI_FFS_FILE_HEADER* file_header = (EFI_FFS_FILE_HEADER*) current_file;
UINT8* byte;
size_t empty_bytes_counter = 0;
// Check if no more files left
for (byte = current_file; *byte == empty_byte; byte++) {
empty_bytes_counter++;
if(empty_bytes_counter >= sizeof(EFI_FFS_FILE_HEADER))
{
printf("No more files left in current volume\n");
return ERR_SUCCESS;
}
}
result = format_guid(&file_header->Name, guid);
if (result)
return result;
printf("FFS file %s found\n", guid);
// Constructing file name
sprintf(str, "%s.%d.%s", prefix, files_counter, guid);
// Getting file size
file_size = filesize_to_size(file_header->Size);
// Store current volume to file
result = write_to_file(current_file, file_size,
str, "file");
if (result){
printf("Error: Can't write FFS file to file\n");
return result;
}
printf("FFS file %s stored to file\n", guid);
//!TODO: Parse current file
// Parsed
printf("FFS file %s parsed\n", guid);
current_file += ALIGN_8(file_size);
files_counter++;
}
return ERR_SUCCESS;
}
UINT8 parse_bios_space(UINT8* buffer, size_t buffer_size)
{
UINT8* current_pointer = NULL;
UINT8* previous_pointer = NULL;
size_t previous_volume_size = 0;
EFI_FIRMWARE_VOLUME_HEADER* volume_header = NULL;
UINT32 files_counter = 0;
size_t rest_size = 0;
UINT8 result = 0;
char str[_MAX_PATH];
// Search for all firmware volume headers
for (current_pointer = buffer, previous_pointer = NULL; current_pointer && current_pointer - buffer <= buffer_size;) {
rest_size = buffer_size - (current_pointer - buffer);
// Search for next firmware volume
//!TODO: add checks for incomplete file
previous_pointer = current_pointer;
current_pointer = find_next_volume(current_pointer, rest_size);
if (current_pointer) {
// Check for padding between previous and current volumes
if (previous_pointer + previous_volume_size < current_pointer) {
sprintf(str, "%d", files_counter);
result = write_to_file(previous_pointer + previous_volume_size,
current_pointer - previous_pointer - previous_volume_size,
str, "padding");
if (result){
printf("Error: Can't write padding to file\n");
return result;
}
printf("Padding between firmware volumes stored to file\n\n");
files_counter++;
}
volume_header = (EFI_FIRMWARE_VOLUME_HEADER*) current_pointer;
printf("Firmware volume found\n");
// Check if volume overlaps the end if buffer
if (current_pointer + volume_header->FvLength > buffer + buffer_size) {
printf("Error: Volume overlaps the end of input buffer.\n");
return ERR_INVALID_VOLUME;
}
// Constructing volume name
sprintf(str, "%d", files_counter);
// Store current volume to file
result = write_to_file(current_pointer, volume_header->FvLength,
str, "volume");
if (result){
printf("Error: Can't write volume to file\n");
return result;
}
printf("Volume stored to file\n");
// Parse volume
result = parse_volume(current_pointer, volume_header->FvLength, str);
if (result)
return result;
printf("Firmware volume parsed\n\n");
// Move to next volume
current_pointer += volume_header->FvLength;
files_counter++;
}
else {// Previous_pointer was the last one (or there was none at all)
// Check for padding between previous volume and end of buffer
if (previous_pointer + previous_volume_size < buffer + buffer_size) {
char str[256];
sprintf(str, "%d", files_counter);
result = write_to_file(previous_pointer + previous_volume_size,
buffer_size + buffer - previous_pointer,
str, "padding");
if (result){
printf("Error: Can't write padding to file\n");
return result;
}
printf("Padding between last firmware volume and end of buffer stored to file\n\n");
files_counter++;
}
}
}
return ERR_SUCCESS;
}
UINT8 parse_buffer(UINT8* buffer, size_t buffer_size)
{
UINT8* original_buffer = buffer;
size_t original_size = buffer_size;
size_t capsule_header_size = 0;
size_t flash_image_size = 0;
FLASH_DESCRIPTOR_HEADER* descriptor_header = NULL;
UINT8 result = ERR_SUCCESS;
// Check buffer to be valid
if (!buffer || !buffer_size)
return ERR_INVALID_PARAMETER;
// Check buffer for being normal EFI capsule header
if (find_pattern(buffer, sizeof(EFI_GUID), EFI_CAPSULE_GUID, sizeof(EFI_GUID)) == buffer) {
EFI_CAPSULE_HEADER* capsule_header = (EFI_CAPSULE_HEADER*) buffer;
printf("EFI Capsule header found\n"
"Header size: %d (0x%08X)\n"
"Header flags: %08X\n"
"Image size: %d (0x%08X)\n\n",
capsule_header->HeaderSize,
capsule_header->HeaderSize,
capsule_header->Flags,
capsule_header->CapsuleImageSize,
capsule_header->CapsuleImageSize);
capsule_header_size = capsule_header->HeaderSize;
}
// Check buffer for being extended Aptio capsule header
else if (find_pattern(buffer, sizeof(EFI_GUID), APTIO_CAPSULE_GUID, sizeof(EFI_GUID)) == buffer) {
APTIO_CAPSULE_HEADER* aptio_capsule_header = (APTIO_CAPSULE_HEADER*) buffer;
printf("AMI Aptio extended capsule header found\n"
"Header size: %d (0x%08X)\n"
"Header flags: %08X\n"
"Image size: %d (0x%08X)\n\n",
aptio_capsule_header->RomImageOffset,
aptio_capsule_header->RomImageOffset,
aptio_capsule_header->CapsuleHeader.Flags,
aptio_capsule_header->CapsuleHeader.CapsuleImageSize - aptio_capsule_header->RomImageOffset,
aptio_capsule_header->CapsuleHeader.CapsuleImageSize - aptio_capsule_header->RomImageOffset);
//!TODO: add more information about extended headed here
capsule_header_size = aptio_capsule_header->RomImageOffset;
}
// Skip capsule header
buffer += capsule_header_size;
flash_image_size = buffer_size - capsule_header_size;
// Consider buffer to be normal flash image without any headers now
// Check buffer for being Intel flash descriptor
descriptor_header = (FLASH_DESCRIPTOR_HEADER*) buffer;
// Check descriptor signature
if (descriptor_header->Signature == FLASH_DESCRIPTOR_SIGNATURE) {
FLASH_DESCRIPTOR_MAP* descriptor_map;
FLASH_DESCRIPTOR_COMPONENT_SECTION* component_section;
FLASH_DESCRIPTOR_REGION_SECTION* region_section;
FLASH_DESCRIPTOR_MASTER_SECTION* master_section;
// Vector of 16 0xFF for sanity check
CONST UINT8 FFVector[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
// Store the beginning of descriptor as descriptor base address
UINT8* descriptor = buffer;
UINT8* bios_region = NULL;
printf("Intel flash descriptor found\n");
// Check for buffer size to be greater or equal to descriptor region size
if (flash_image_size < FLASH_DESCRIPTOR_SIZE) {
printf("Error: Input file is smaller then mininum descriptor size of 4KB\nAborting\n");
return ERR_INVALID_FLASH_DESCRIPTOR;
}
//Write descriptor to desc.bin
result = write_to_file(descriptor, FLASH_DESCRIPTOR_SIZE, "DESC", "region");
if (result){
printf("Error: Can't write descriptor region to file\nAborting\n");
return result;
}
printf("Descriptor region written to file\n");
// Check FFVector to consist 16 0xFF, as sanity check
if (find_pattern(buffer, 16, FFVector, 16) != buffer)
printf("Warning: Descriptor start vector has something but 0xFF bytes. That's strange\n");
// Skip descriptor header
buffer += sizeof(FLASH_DESCRIPTOR_HEADER);
// Parse descriptor map
descriptor_map = (FLASH_DESCRIPTOR_MAP*) buffer;
component_section = (FLASH_DESCRIPTOR_COMPONENT_SECTION*) calculate_address_8(descriptor, descriptor_map->ComponentBase);
region_section = (FLASH_DESCRIPTOR_REGION_SECTION*) calculate_address_8(descriptor, descriptor_map->RegionBase);
master_section = (FLASH_DESCRIPTOR_MASTER_SECTION*) calculate_address_8(descriptor, descriptor_map->MasterBase);
printf("\nParsing descriptor map\n"
"Flash chips: %d\n"
"Flash regions: %d\n"
"Flash masters: %d\n"
"PCH straps: %d\n"
"PROC straps: %d\n"
"ICC table entries: %d\n",
descriptor_map->NumberOfFlashChips + 1,
descriptor_map->NumberOfRegions + 1,
descriptor_map->NumberOfMasters + 1,
descriptor_map->NumberOfPchStraps,
descriptor_map->NumberOfProcStraps,
descriptor_map->NumberOfIccTableEntries);
printf("Descriptor map parsed\n\n");
// Parse component section
//!TODO: add parsing code
// Parse master section
//!TODO: add parsing code
// Parse region section
printf("Parsing region section\n");
parse_region(descriptor, flash_image_size, descriptor_map->NumberOfFlashChips, "GBE", region_section->GbeBase, region_section->GbeLimit);
parse_region(descriptor, flash_image_size, descriptor_map->NumberOfFlashChips, "ME", region_section->MeBase, region_section->MeLimit);
bios_region = parse_region(descriptor, flash_image_size, descriptor_map->NumberOfFlashChips, "BIOS", region_section->BiosBase, region_section->BiosLimit);
parse_region(descriptor, flash_image_size, descriptor_map->NumberOfFlashChips, "PDR", region_section->PdrBase, region_section->PdrLimit);
printf("Region section parsed\n\n");
// Parsing complete
printf("Descriptor parsing complete\n\n");
// Exiting if no bios region found
if (!bios_region) {
printf("BIOS region not found\nAborting\n");
return ERR_BIOS_REGION_NOT_FOUND;
}
// BIOS region is our buffer now
buffer = bios_region;
buffer_size = calculate_region_size(region_section->BiosBase, region_section->BiosLimit);
}
else {
printf("Intel flash descriptor not found, assuming that input file is BIOS region image\n\n");
}
// We are in the beginning of BIOS space, where firmware volumes are
// Parse BIOS space
result = parse_bios_space(buffer, buffer_size);
if (result)
return result;
return ERR_SUCCESS;
}

28
parse.h Normal file
View file

@ -0,0 +1,28 @@
/* parse.h
Copyright (c) 2013, 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 __PARSE_H__
#define __PARSE_H__
#include <stdio.h>
#include <stdlib.h>
#include "basetypes.h"
#include "ffs.h"
#include "descriptor.h"
//#include "Tiano/TianoCompress.h"
//#include "Tiano/TianoDecompress.h"
//#include "LZMA/LzmaCompress.h"
//#include "LZMA/LzmaDecompress.h"
UINT8 parse_buffer(UINT8* buffer, size_t size);
#endif

155
treeitem.cpp Normal file
View file

@ -0,0 +1,155 @@
/* treeitem.cpp
Copyright (c) 2013, 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,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#include "treeitem.h"
#include "treeitemtypes.h"
TreeItem::TreeItem(const UINT8 type, const UINT8 subtype, const QString & name, const QString & typeName, const QString & subtypeName,
const QString & text, const QString & info, const QByteArray & header, const QByteArray & body, TreeItem *parent)
{
itemType = type;
itemSubtype = subtype;
itemName = name;
itemTypeName = typeName;
itemSubtypeName = subtypeName;
itemText = text;
itemInfo = info;
itemHeader = header;
itemBody = body;
parentItem = parent;
}
TreeItem::~TreeItem()
{
qDeleteAll(childItems);
}
void TreeItem::appendChild(TreeItem *item)
{
childItems.append(item);
}
void TreeItem::removeChild(TreeItem *item)
{
childItems.removeAll(item);
}
TreeItem *TreeItem::child(int row)
{
return childItems.value(row);
}
int TreeItem::childCount() const
{
return childItems.count();
}
int TreeItem::columnCount() const
{
return 4;
}
QString TreeItem::data(int column) const
{
switch(column)
{
case 0: //Object
return itemName;
break;
case 1: //Type
return itemTypeName;
break;
case 2: //Subtype
return itemSubtypeName;
break;
case 3: //Text
return itemText;
break;
default:
return "";
}
}
TreeItem *TreeItem::parent()
{
return parentItem;
}
void TreeItem::setName(const QString &text)
{
itemName = text;
}
void TreeItem::setText(const QString &text)
{
itemText = text;
}
void TreeItem::setTypeName(const QString &text)
{
itemTypeName = text;
}
void TreeItem::setSubtypeName(const QString &text)
{
itemSubtypeName = text;
}
QString TreeItem::info()
{
return itemInfo;
}
void TreeItem::setInfo(const QString &text)
{
itemInfo = text;
}
int TreeItem::row() const
{
if (parentItem)
return parentItem->childItems.indexOf(const_cast<TreeItem*>(this));
return 0;
}
UINT8 TreeItem::type()
{
return itemType;
}
UINT8 TreeItem::subtype()
{
return itemSubtype;
}
QByteArray TreeItem::header()
{
return itemHeader;
}
QByteArray TreeItem::body()
{
return itemBody;
}
bool TreeItem::hasEmptyHeader()
{
return itemHeader.isEmpty();
}
bool TreeItem::hasEmptyBody()
{
return itemBody.isEmpty();
}

68
treeitem.h Normal file
View file

@ -0,0 +1,68 @@
/* treeitem.h
Copyright (c) 2013, 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,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#ifndef __TREEITEM_H__
#define __TREEITEM_H__
#include <QByteArray>
#include <QList>
#include <QString>
#include "basetypes.h"
class TreeItem
{
public:
TreeItem(const UINT8 type, const UINT8 subtype = 0, const QString & name = QString(), const QString & typeName = QString(), const QString & subtypeName = QString(),
const QString & text = QString(), const QString & info = QString(), const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(), TreeItem *parent = 0);
~TreeItem();
void appendChild(TreeItem *item);
void removeChild(TreeItem *item);
TreeItem *child(int row);
int childCount() const;
int columnCount() const;
QString data(int column) const;
int row() const;
TreeItem *parent();
UINT8 type();
UINT8 subtype();
QByteArray header();
QByteArray body();
QString info();
bool hasEmptyHeader();
bool hasEmptyBody();
void setName(const QString &text);
void setText(const QString &text);
void setTypeName(const QString &text);
void setSubtypeName(const QString &text);
void setInfo(const QString &text);
private:
QList<TreeItem*> childItems;
UINT8 itemType;
UINT8 itemSubtype;
QByteArray itemHeader;
QByteArray itemBody;
QString itemName;
QString itemTypeName;
QString itemSubtypeName;
QString itemText;
QString itemInfo;
TreeItem *parentItem;
};
#endif

80
treeitemtypes.h Normal file
View file

@ -0,0 +1,80 @@
/* treeitemtypes.h
Copyright (c) 2013, 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,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#ifndef __TREEITEMTYPES_H__
#define __TREEITEMTYPES_H__
// TreeItem types
enum ItemTypes {
RootItem,
CapsuleItem,
DescriptorItem,
RegionItem,
PaddingItem,
VolumeItem,
FileItem,
SectionItem
};
// Capsule subtypes
enum CapsuleSubtypes {
AptioCapsule,
UefiCapsule
};
// Region subtypes
enum RegionSubtypes {
GbeRegion,
MeRegion,
BiosRegion,
PdrRegion
};
// File subtypes
enum FileSubtypes {
RawFile,
FreeformFile,
SecurityCoreFile,
PeiCoreFile,
DxeCoreFile,
PeiModuleFile,
DxeDriverFile,
CombinedPeiDxeFile,
ApplicationFile,
SmmModuleFile,
VolumeImageFile,
CombinedSmmDxeFile,
SmmCoreFile,
PadFile = 0xF0
};
enum SectionSubtypes {
CompressionSection = 0x01,
GuidDefinedSection,
DisposableSection,
Pe32ImageSection = 0x10,
PicImageSection,
TeImageSection,
DxeDepexSection,
VersionSection,
UserInterfaceSection,
Compatibility16Section,
VolumeImageSection,
FreeformSubtypeGuidSection,
RawSection,
PeiDepexSection = 0x1B,
SmmDepexSection
};
#endif

354
treemodel.cpp Normal file
View file

@ -0,0 +1,354 @@
/* treemodel.cpp
Copyright (c) 2013, 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,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#include "treeitem.h"
#include "treemodel.h"
#include "ffs.h"
#include "descriptor.h"
TreeModel::TreeModel(QObject *parent)
: QAbstractItemModel(parent)
{
rootItem = new TreeItem(ItemTypes::RootItem, 0, tr("Object"), tr("Type"), tr("Subtype"), tr("Text"));
}
TreeModel::~TreeModel()
{
delete rootItem;
}
bool TreeModel::hasEmptyHeader(const QModelIndex& index)
{
if (!index.isValid())
return true;
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item->hasEmptyHeader();
}
bool TreeModel::hasEmptyBody(const QModelIndex& index)
{
if (!index.isValid())
return true;
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item->hasEmptyBody();
}
int TreeModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid())
return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
else
return rootItem->columnCount();
}
QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (role != Qt::DisplayRole && role != Qt::UserRole)
return QVariant();
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
if (role == Qt::DisplayRole)
return item->data(index.column());
else
return item->info();
return QVariant();
}
Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return 0;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return rootItem->data(section);
return QVariant();
}
QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent)
const
{
if (!hasIndex(row, column, parent))
return QModelIndex();
TreeItem *parentItem;
if (!parent.isValid())
parentItem = rootItem;
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());
TreeItem *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
}
QModelIndex TreeModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
TreeItem *parentItem = childItem->parent();
if (parentItem == rootItem)
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
int TreeModel::rowCount(const QModelIndex &parent) const
{
TreeItem *parentItem;
if (parent.column() > 0)
return 0;
if (!parent.isValid())
parentItem = rootItem;
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());
return parentItem->childCount();
}
QModelIndex TreeModel::addItem(UINT8 type, UINT8 subtype, const QByteArray &header, const QByteArray &body, const QModelIndex &parent)
{
TreeItem *parentItem;
int parentColumn = 0;
if (!parent.isValid())
parentItem = rootItem;
else
{
parentItem = static_cast<TreeItem*>(parent.internalPointer());
parentColumn = parent.column();
}
// All information extraction must be here
QString name, typeName, subtypeName, info;
EFI_CAPSULE_HEADER* capsuleHeader;
APTIO_CAPSULE_HEADER* aptioCapsuleHeader;
FLASH_DESCRIPTOR_MAP* descriptorMap;
//FLASH_DESCRIPTOR_COMPONENT_SECTION* componentSection;
//FLASH_DESCRIPTOR_REGION_SECTION* regionSection;
//FLASH_DESCRIPTOR_MASTER_SECTION* masterSection;
EFI_FIRMWARE_VOLUME_HEADER* volumeHeader;
EFI_FFS_FILE_HEADER* fileHeader;
//EFI_COMMON_SECTION_HEADER* sectionHeader;
switch (type)
{
case ItemTypes::RootItem:
// Do not allow to add another root item
return QModelIndex();
break;
case ItemTypes::CapsuleItem:
//typeName = tr("Capsule");
switch (subtype)
{
case CapsuleSubtypes::AptioCapsule:
name = tr("AMI Aptio capsule");
aptioCapsuleHeader = (APTIO_CAPSULE_HEADER*) header.constData();
info = tr("GUID: %1\nHeader size: %2\nFlags: %3\nImage size: %4")
.arg(guidToQString(aptioCapsuleHeader->CapsuleHeader.CapsuleGuid))
.arg(aptioCapsuleHeader->CapsuleHeader.Flags, 8, 16, QChar('0'))
.arg(aptioCapsuleHeader->RomImageOffset, 4, 16, QChar('0'))
.arg(aptioCapsuleHeader->CapsuleHeader.CapsuleImageSize - aptioCapsuleHeader->RomImageOffset, 8, 16, QChar('0'));
//!TODO: more info about Aptio capsule
break;
case CapsuleSubtypes::UefiCapsule:
name = tr("UEFI capsule");
capsuleHeader = (EFI_CAPSULE_HEADER*) header.constData();
info = tr("GUID: %1\nHeader size: %2\nFlags: %3\nImage size: %4")
.arg(guidToQString(capsuleHeader->CapsuleGuid))
.arg(capsuleHeader->Flags, 8, 16, QChar('0'))
.arg(capsuleHeader->HeaderSize, 8, 16, QChar('0'))
.arg(capsuleHeader->CapsuleImageSize, 8, 16, QChar('0'));
break;
default:
name = tr("Unknown capsule");
info = tr("GUID: %1\n").arg(guidToQString(*(EFI_GUID*)header.constData()));
break;
}
break;
case ItemTypes::DescriptorItem:
name = tr("Descriptor");
descriptorMap = (FLASH_DESCRIPTOR_MAP*) body.constData();
info = tr("Flash chips: %1\nRegions: %2\nMasters: %3\nPCH straps:%4\nPROC straps: %5\nICC table entries: %6")
.arg(descriptorMap->NumberOfFlashChips + 1) //
.arg(descriptorMap->NumberOfRegions + 1) // Zero-based numbers in storage
.arg(descriptorMap->NumberOfMasters + 1) //
.arg(descriptorMap->NumberOfPchStraps)
.arg(descriptorMap->NumberOfProcStraps)
.arg(descriptorMap->NumberOfIccTableEntries);
//!TODO: more info about descriptor
break;
case ItemTypes::RegionItem:
typeName = tr("Region");
info = tr("Size: %1").arg(body.size(), 8, 16, QChar('0'));
//!TODO: more info about GbE and ME regions
switch (subtype)
{
case RegionSubtypes::GbeRegion:
name = tr("GbE region");
break;
case RegionSubtypes::MeRegion:
name = tr("ME region");
break;
case RegionSubtypes::BiosRegion:
name = tr("BIOS region");
break;
case RegionSubtypes::PdrRegion:
name = tr("PDR region");
break;
default:
name = tr("Unknown region");
break;
}
break;
case ItemTypes::PaddingItem:
name = tr("Padding");
info = tr("Size: %1").arg(body.size(), 8, 16, QChar('0'));
break;
case ItemTypes::VolumeItem:
typeName = tr("Volume");
// Parse volume header to determine its revision and file system
volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*) header.constData();
name = guidToQString(volumeHeader->FileSystemGuid);
subtypeName = tr("Revision %1").arg(volumeHeader->Revision);
info = tr("Size: %1\nSignature: %2\nAttributes: %3\nHeader size: %4")
.arg(volumeHeader->FvLength, 8, 16, QChar('0'))
.arg(volumeHeader->Signature, 8, 16, QChar('0'))
.arg(volumeHeader->Attributes, 8, 16, QChar('0'))
.arg(volumeHeader->HeaderLength, 4, 16, QChar('0'));
break;
case ItemTypes::FileItem:
typeName = tr("File");
// Parse file header to determine its GUID and type
fileHeader = (EFI_FFS_FILE_HEADER*) header.constData();
name = guidToQString(fileHeader->Name);
subtypeName = fileTypeToQString(subtype);
info = tr("Type: %1\nAttributes: %2\nSize: %3\nState: %4")
.arg(fileHeader->Type, 2, 16, QChar('0'))
.arg(fileHeader->Attributes, 2, 16, QChar('0'))
.arg(uint24ToUint32(fileHeader->Size), 6, 16, QChar('0'))
.arg(fileHeader->State, 2, 16, QChar('0'));
break;
case ItemTypes::SectionItem:
typeName = tr("Section");
name = sectionTypeToQString(subtype) + tr(" section");
info = tr("Size: %1").arg(body.size(), 8, 16, QChar('0'));
//!TODO: add more specific info for all section types with uncommon headers
// Set name of file
if (subtype == SectionSubtypes::UserInterfaceSection)
{
QString text = QString::fromUtf16((const ushort*)body.constData());
setItemText(text, findParentOfType(ItemTypes::FileItem, parent));
}
break;
default:
name = tr("Unknown");
break;
}
emit layoutAboutToBeChanged();
TreeItem *item = new TreeItem(type, subtype, name, typeName, subtypeName, "", info, header, body, parentItem);
parentItem->appendChild(item);
emit layoutChanged();
return createIndex(parentItem->childCount() - 1, parentColumn, item);
}
bool TreeModel::setItemName(const QString &data, const QModelIndex &index)
{
if(!index.isValid())
return false;
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
item->setName(data);
emit dataChanged(index, index);
return true;
}
bool TreeModel::setItemText(const QString &data, const QModelIndex &index)
{
if(!index.isValid())
return false;
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
item->setText(data);
emit dataChanged(index, index);
return true;
}
bool TreeModel::removeItem(const QModelIndex &index)
{
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
item->parent()->removeChild(item);
delete item;
return true;
}
QModelIndex TreeModel::findParentOfType(UINT8 type, const QModelIndex& index)
{
if(!index.isValid())
return QModelIndex();
TreeItem *item;
QModelIndex parent = index;
for(item = static_cast<TreeItem*>(parent.internalPointer());
item != NULL && item != rootItem && item->type() != type;
item = static_cast<TreeItem*>(parent.internalPointer()))
parent = parent.parent();
if (item != NULL && item != rootItem)
return parent;
return QModelIndex();
}
QByteArray TreeModel::header(const QModelIndex& index)
{
if (!index.isValid())
return QByteArray();
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item->header();
}
QByteArray TreeModel::body(const QModelIndex& index)
{
if (!index.isValid())
return QByteArray();
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item->body();
}

60
treemodel.h Normal file
View file

@ -0,0 +1,60 @@
/* treemodel.h
Copyright (c) 2013, 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,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#ifndef __TREEMODEL_H__
#define __TREEMODEL_H__
#include <QAbstractItemModel>
#include <QModelIndex>
#include <QString>
#include <QVariant>
#include "basetypes.h"
#include "treeitemtypes.h"
class TreeItem;
class TreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
TreeModel(QObject *parent = 0);
~TreeModel();
QVariant data(const QModelIndex &index, int role) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const;
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &index) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QModelIndex addItem(UINT8 type, UINT8 subtype = 0, const QByteArray &header = QByteArray(), const QByteArray &body = QByteArray(), const QModelIndex &parent = QModelIndex());
bool removeItem(const QModelIndex &index);
QByteArray header(const QModelIndex& index);
bool hasEmptyHeader(const QModelIndex& index);
QByteArray body(const QModelIndex& index);
bool hasEmptyBody(const QModelIndex& index);
private:
QModelIndex findParentOfType(UINT8 type, const QModelIndex& index);
bool setItemName(const QString &data, const QModelIndex &index);
bool setItemText(const QString &data, const QModelIndex &index);
TreeItem *rootItem;
};
#endif

960
uefitool.cpp Normal file
View file

@ -0,0 +1,960 @@
/* uefitool.cpp
Copyright (c) 2013, 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,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#include "uefitool.h"
#include "ui_uefitool.h"
UEFITool::UEFITool(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::UEFITool)
{
ui->setupUi(this);
treeModel = NULL;
// Signal-slot connections
connect(ui->fromFileButton, SIGNAL(clicked()), this, SLOT(openImageFile()));
connect(ui->exportAllButton, SIGNAL(clicked()), this, SLOT(saveAll()));
connect(ui->exportBodyButton, SIGNAL(clicked()), this, SLOT(saveBody()));
// Enable Drag-and-Drop actions
this->setAcceptDrops(true);
// Initialise non-persistent data
init();
}
UEFITool::~UEFITool()
{
delete ui;
delete treeModel;
}
void UEFITool::init()
{
// Clear UI components
ui->debugEdit->clear();
ui->infoEdit->clear();
ui->exportAllButton->setDisabled(true);
ui->exportBodyButton->setDisabled(true);
// Make new tree model
TreeModel * newModel = new TreeModel(this);
ui->structureTreeView->setModel(newModel);
if (treeModel)
delete treeModel;
treeModel = newModel;
// Show info after selection the item in tree view
connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
this, SLOT(populateUi(const QModelIndex &)));
//connect(ui->structureTreeView, SIGNAL(collapsed(const QModelIndex &)), this, SLOT(resizeTreeViewColums(void)));
connect(ui->structureTreeView, SIGNAL(expanded(const QModelIndex &)), this, SLOT(resizeTreeViewColums(void)));
resizeTreeViewColums();
}
void UEFITool::populateUi(const QModelIndex &current/*, const QModelIndex &previous*/)
{
//!TODO: make widget
currentIndex = current;
ui->infoEdit->setPlainText(current.data(Qt::UserRole).toString());
ui->exportAllButton->setDisabled(treeModel->hasEmptyBody(current) && treeModel->hasEmptyHeader(current));
ui->exportBodyButton->setDisabled(treeModel->hasEmptyHeader(current));
}
void UEFITool::resizeTreeViewColums(/*const QModelIndex &index*/)
{
int count = treeModel->columnCount();
for(int i = 0; i < count; i++)
ui->structureTreeView->resizeColumnToContents(i);
}
void UEFITool::openImageFile()
{
QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file"),".","BIOS image file (*.rom *.bin *.cap *.bio *.fd *.wph *.efi);;All files (*.*)");
openImageFile(path);
}
void UEFITool::openImageFile(QString path)
{
QFileInfo fileInfo = QFileInfo(path);
if (!fileInfo.exists())
{
ui->statusBar->showMessage(tr("Please select existing BIOS image file."));
return;
}
QFile inputFile;
inputFile.setFileName(path);
if (!inputFile.open(QFile::ReadOnly))
{
ui->statusBar->showMessage(tr("Can't open file for reading. Check file permissions."));
return;
}
QByteArray buffer = inputFile.readAll();
inputFile.close();
init();
UINT8 result = parseInputFile(buffer);
if (result)
debug(tr("Opened file can't be parsed as UEFI image (%1)").arg(result));
else
ui->statusBar->showMessage(tr("Opened: %1").arg(fileInfo.fileName()));
resizeTreeViewColums();
}
void UEFITool::saveAll()
{
QString path = QFileDialog::getSaveFileName(this, tr("Save header to binary file"),".","Binary files (*.bin);;All files (*.*)");
QFile outputFile;
outputFile.setFileName(path);
if (!outputFile.open(QFile::WriteOnly))
{
ui->statusBar->showMessage(tr("Can't open file for writing. Check file permissions."));
return;
}
outputFile.write(treeModel->header(currentIndex) + treeModel->body(currentIndex));
outputFile.close();
}
void UEFITool::saveBody()
{
QString path = QFileDialog::getSaveFileName(this, tr("Save body to binary file"),".","Binary files (*.bin);;All files (*.*)");
QFile outputFile;
outputFile.setFileName(path);
if (!outputFile.open(QFile::WriteOnly))
{
ui->statusBar->showMessage(tr("Can't open file for writing. Check file permissions."));
return;
}
outputFile.write(treeModel->body(currentIndex));
outputFile.close();
}
/*void UEFITool::saveImageFile()
{
QString path = QFileDialog::getSaveFileName(this, tr("Save BIOS image file"),".","BIOS image file (*.rom *.bin *.cap *.fd *.fwh);;All files (*.*)");
QFileInfo fileInfo = QFileInfo(path);
if (!fileInfo.exists())
{
ui->statusBar->showMessage(tr("Please select existing BIOS image file."));
return;
}
QFile outputFile;
outputFile.setFileName(path);
if (!outputFile.open(QFile::ReadWrite))
{
ui->statusBar->showMessage(tr("Can't open file for writing. Check file permissions."));
return;
}
}*/
void UEFITool::dragEnterEvent(QDragEnterEvent* event)
{
if (event->mimeData()->hasFormat("text/uri-list"))
event->acceptProposedAction();
}
void UEFITool::dropEvent(QDropEvent* event)
{
QString path = event->mimeData()->urls().at(0).toLocalFile();
openImageFile(path);
}
void UEFITool::debug(const QString & text)
{
//!TODO: log to separate debug window
ui->debugEdit->appendPlainText(text);
}
QModelIndex UEFITool::addTreeItem(UINT8 type, UINT8 subtype,
const QByteArray & header, const QByteArray & body, const QModelIndex & parent)
{
return treeModel->addItem(type, subtype, header, body, parent);
}
UINT8 UEFITool::parseInputFile(const QByteArray & buffer)
{
UINT32 capsuleHeaderSize = 0;
FLASH_DESCRIPTOR_HEADER* descriptorHeader = NULL;
QByteArray flashImage;
QByteArray bios;
QModelIndex index;
// Check buffer for being normal EFI capsule header
if (buffer.startsWith(EFI_CAPSULE_GUID)) {
EFI_CAPSULE_HEADER* capsuleHeader = (EFI_CAPSULE_HEADER*) buffer.constData();
capsuleHeaderSize = capsuleHeader->HeaderSize;
QByteArray header = buffer.left(capsuleHeaderSize);
QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize);
index = addTreeItem(ItemTypes::CapsuleItem, CapsuleSubtypes::UefiCapsule, header, body);
}
// Check buffer for being extended Aptio capsule header
else if (buffer.startsWith(APTIO_CAPSULE_GUID)) {
APTIO_CAPSULE_HEADER* aptioCapsuleHeader = (APTIO_CAPSULE_HEADER*) buffer.constData();
capsuleHeaderSize = aptioCapsuleHeader->RomImageOffset;
QByteArray header = buffer.left(capsuleHeaderSize);
QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize);
index = addTreeItem(ItemTypes::CapsuleItem, CapsuleSubtypes::AptioCapsule, header, body);
}
// Skip capsule header to have flash chip image
flashImage = buffer.right(buffer.size() - capsuleHeaderSize);
// Check buffer for being Intel flash descriptor
descriptorHeader = (FLASH_DESCRIPTOR_HEADER*) flashImage.constData();
// Check descriptor signature
if (descriptorHeader->Signature == FLASH_DESCRIPTOR_SIGNATURE) {
FLASH_DESCRIPTOR_MAP* descriptorMap;
FLASH_DESCRIPTOR_REGION_SECTION* regionSection;
// Store the beginning of descriptor as descriptor base address
UINT8* descriptor = (UINT8*) flashImage.constData();
UINT8* gbeRegion = NULL;
UINT8* meRegion = NULL;
UINT8* biosRegion = NULL;
UINT8* pdrRegion = NULL;
// Check for buffer size to be greater or equal to descriptor region size
if (flashImage.size() < FLASH_DESCRIPTOR_SIZE) {
debug(tr("Input file is smaller then mininum descriptor size of 4KB"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
// Parse descriptor map
descriptorMap = (FLASH_DESCRIPTOR_MAP*) (flashImage.constData() + sizeof(FLASH_DESCRIPTOR_HEADER));
regionSection = (FLASH_DESCRIPTOR_REGION_SECTION*) calculateAddress8(descriptor, descriptorMap->RegionBase);
// Add tree item
QByteArray header = flashImage.left(sizeof(FLASH_DESCRIPTOR_HEADER));
QByteArray body = flashImage.mid(sizeof(FLASH_DESCRIPTOR_HEADER), FLASH_DESCRIPTOR_SIZE - sizeof(FLASH_DESCRIPTOR_HEADER));
index = addTreeItem(ItemTypes::DescriptorItem, 0, header, body, index);
// Parse region section
QModelIndex gbeIndex(index);
QModelIndex meIndex(index);
QModelIndex biosIndex(index);
QModelIndex pdrIndex(index);
gbeRegion = parseRegion(flashImage, RegionSubtypes::GbeRegion, regionSection->GbeBase, regionSection->GbeLimit, gbeIndex);
meRegion = parseRegion(flashImage, RegionSubtypes::MeRegion, regionSection->MeBase, regionSection->MeLimit, meIndex);
biosRegion = parseRegion(flashImage, RegionSubtypes::BiosRegion, regionSection->BiosBase, regionSection->BiosLimit, biosIndex);
pdrRegion = parseRegion(flashImage, RegionSubtypes::PdrRegion, regionSection->PdrBase, regionSection->PdrLimit, pdrIndex);
// Parse complete
//!TODO: show some info about GbE, ME and PDR regions if found
// Exit if no bios region found
if (!biosRegion) {
debug(tr("BIOS region not found"));
return ERR_BIOS_REGION_NOT_FOUND;
}
index = biosIndex;
bios = QByteArray::fromRawData((const char*) biosRegion, calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit));
}
else {
bios = buffer;
}
// We are in the beginning of BIOS space, where firmware volumes are
// Parse BIOS space
return parseBios(bios, index);
}
UINT8* UEFITool::parseRegion(const QByteArray & flashImage, UINT8 regionSubtype, const UINT16 regionBase, const UINT16 regionLimit, QModelIndex & index)
{
// Check for empty region
if (!regionLimit)
return NULL;
// Calculate region size
UINT32 regionSize = calculateRegionSize(regionBase, regionLimit);
// Populate descriptor map
FLASH_DESCRIPTOR_MAP* descriptor_map = (FLASH_DESCRIPTOR_MAP*) flashImage.constData() + sizeof(FLASH_DESCRIPTOR_HEADER);
// Determine presence of 2 flash chips
bool twoChips = descriptor_map->NumberOfFlashChips;
// construct region name
//!TODO: make this to regionTypeToQString(const UINT8 type) in descriptor.cpp
QString regionName;
switch (regionSubtype)
{
case RegionSubtypes::GbeRegion:
regionName = "GbE";
break;
case RegionSubtypes::MeRegion:
regionName = "ME";
break;
case RegionSubtypes::BiosRegion:
regionName = "Bios";
break;
case RegionSubtypes::PdrRegion:
regionName = "PDR";
break;
default:
regionName = "Unknown";
debug(tr("Unknown region type"));
};
// Check region base to be in buffer
if (regionBase * 0x1000 >= flashImage.size())
{
debug(tr("%1 region stored in descriptor not found").arg(regionName));
if (twoChips)
debug(tr("Two flash chips installed, so it could be in another flash chip\n"
"Make a dump from another flash chip and open it to view information about %1 region").arg(regionName));
else
debug(tr("One flash chip installed, so it is an error caused by damaged or incomplete dump"));
debug(tr("Absence of %1 region assumed").arg(regionName));
return NULL;
}
// Check region to be fully present in buffer
else if (regionBase * 0x1000 + regionSize > flashImage.size())
{
debug(tr("%s region stored in descriptor overlaps the end of opened file").arg(regionName));
if (twoChips)
debug(tr("Two flash chips installed, so it could be in another flash chip\n"
"Make a dump from another flash chip and open it to view information about %1 region").arg(regionName));
else
debug(tr("One flash chip installed, so it is an error caused by damaged or incomplete dump"));
debug(tr("Absence of %1 region assumed\n").arg(regionName));
return NULL;
}
// Calculate region address
UINT8* region = calculateAddress16((UINT8*) flashImage.constData(), regionBase);
// Add tree item
QByteArray body = flashImage.mid(regionBase * 0x1000, regionSize);
index = addTreeItem(ItemTypes::RegionItem, regionSubtype, QByteArray(), body, index);
return region;
}
UINT8 UEFITool::parseBios(const QByteArray & bios, QModelIndex & parent)
{
// Search for first volume
INT32 prevVolumeIndex = getNextVolumeIndex(bios);
// No volumes found
if (prevVolumeIndex < 0) {
return ERR_VOLUMES_NOT_FOUND;
}
// First volume is not at the beginning of bios space
if (prevVolumeIndex > 0) {
QByteArray padding = bios.left(prevVolumeIndex);
addTreeItem(ItemTypes::PaddingItem, 0, QByteArray(), padding, parent);
}
// Search for and parse all volumes
INT32 volumeIndex;
UINT32 prevVolumeSize;
for (volumeIndex = prevVolumeIndex, prevVolumeSize = 0;
volumeIndex >= 0;
prevVolumeIndex = volumeIndex, prevVolumeSize = getVolumeSize(bios, volumeIndex), volumeIndex = getNextVolumeIndex(bios, volumeIndex + prevVolumeSize))
{
// Padding between volumes
if (volumeIndex > prevVolumeIndex + prevVolumeSize) {
UINT32 size = volumeIndex - prevVolumeIndex - prevVolumeSize;
QByteArray padding = bios.mid(prevVolumeIndex + prevVolumeSize, size);
addTreeItem(ItemTypes::PaddingItem, 0, QByteArray(), padding, parent);
}
// Populate volume header
EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*) (bios.constData() + volumeIndex);
//Check that volume is fully present in input
if (volumeIndex + volumeHeader->FvLength > bios.size()) {
debug(tr("Volume overlaps the end of input buffer"));
return ERR_INVALID_VOLUME;
}
// Check volume revision and alignment
UINT32 alignment;
if (volumeHeader->Revision == 1) {
// Aquire alignment bits
bool alignmentCap = volumeHeader->Attributes && EFI_FVB_ALIGNMENT_CAP;
bool alignment2 = volumeHeader->Attributes && EFI_FVB_ALIGNMENT_2;
bool alignment4 = volumeHeader->Attributes && EFI_FVB_ALIGNMENT_4;
bool alignment8 = volumeHeader->Attributes && EFI_FVB_ALIGNMENT_8;
bool alignment16 = volumeHeader->Attributes && EFI_FVB_ALIGNMENT_16;
bool alignment32 = volumeHeader->Attributes && EFI_FVB_ALIGNMENT_32;
bool alignment64 = volumeHeader->Attributes && EFI_FVB_ALIGNMENT_64;
bool alignment128 = volumeHeader->Attributes && EFI_FVB_ALIGNMENT_128;
bool alignment256 = volumeHeader->Attributes && EFI_FVB_ALIGNMENT_256;
bool alignment512 = volumeHeader->Attributes && EFI_FVB_ALIGNMENT_512;
bool alignment1k = volumeHeader->Attributes && EFI_FVB_ALIGNMENT_1K;
bool alignment2k = volumeHeader->Attributes && EFI_FVB_ALIGNMENT_2K;
bool alignment4k = volumeHeader->Attributes && EFI_FVB_ALIGNMENT_4K;
bool alignment8k = volumeHeader->Attributes && EFI_FVB_ALIGNMENT_8K;
bool alignment16k = volumeHeader->Attributes && EFI_FVB_ALIGNMENT_16K;
bool alignment32k = volumeHeader->Attributes && EFI_FVB_ALIGNMENT_32K;
bool alignment64k = volumeHeader->Attributes && EFI_FVB_ALIGNMENT_64K;
// Check alignment setup
if (!alignmentCap &&
( alignment2 || alignment4 || alignment8 || alignment16
|| alignment32 || alignment64 || alignment128 || alignment256
|| alignment512 || alignment1k || alignment2k || alignment4k
|| alignment8k || alignment16k || alignment32k || alignment64k))
debug("Incompatible revision 1 volume alignment setup");
// Assume that smaller alignment value consumes greater
alignment = 0x01;
if (alignment2)
alignment = 0x02;
else if (alignment4)
alignment = 0x04;
else if (alignment8)
alignment = 0x08;
else if (alignment16)
alignment = 0x10;
else if (alignment32)
alignment = 0x20;
else if (alignment64)
alignment = 0x40;
else if (alignment128)
alignment = 0x80;
else if (alignment256)
alignment = 0x100;
else if (alignment512)
alignment = 0x200;
else if (alignment1k)
alignment = 0x400;
else if (alignment2k)
alignment = 0x800;
else if (alignment4k)
alignment = 0x1000;
else if (alignment8k)
alignment = 0x2000;
else if (alignment16k)
alignment = 0x4000;
else if (alignment32k)
alignment = 0x8000;
else if (alignment64k)
alignment = 0x10000;
// Check alignment
if (volumeIndex % alignment) {
debug(tr("Unaligned revision 1 volume"));
}
}
else if (volumeHeader->Revision == 2) {
// Aquire alignment
alignment = pow(2, (volumeHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
// Check alignment
if (volumeIndex % alignment) {
debug(tr("Unaligned revision 2 volume"));
}
}
else
debug(tr("Unknown volume revision (%1)").arg(volumeHeader->Revision));
// Check filesystem GUID to be known
// Do not parse volume with unknown FFS, because parsing will fail
bool parseCurrentVolume = true;
// FFS GUID v1
if (QByteArray((const char*) &volumeHeader->FileSystemGuid, sizeof(EFI_GUID)) == EFI_FIRMWARE_FILE_SYSTEM_GUID) {
// Code can be added here
}
// FFS GUID v2
else if (QByteArray((const char*) &volumeHeader->FileSystemGuid, sizeof(EFI_GUID)) == EFI_FIRMWARE_FILE_SYSTEM2_GUID) {
// Code can be added here
}
// Other GUID
else {
//info = info.append(tr("File system: unknown\n"));
debug(tr("Unknown file system (%1)").arg(guidToQString(volumeHeader->FileSystemGuid)));
parseCurrentVolume = false;
}
// Check attributes
// Determine erase polarity
bool erasePolarity = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY;
// Check header checksum by recalculating it
if (!calculateChecksum16((UINT8*) volumeHeader, volumeHeader->HeaderLength)) {
debug(tr("Volume header checksum is invalid"));
}
// Check for presence of extended header, only if header revision is not 1
UINT32 headerSize;
if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) {
EFI_FIRMWARE_VOLUME_EXT_HEADER* extendedHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER*) ((UINT8*) volumeHeader + volumeHeader->ExtHeaderOffset);
headerSize = volumeHeader->ExtHeaderOffset + extendedHeader->ExtHeaderSize;
} else {
headerSize = volumeHeader->HeaderLength;
}
// Adding tree item
QByteArray header = bios.mid(volumeIndex, headerSize);
QByteArray body = bios.mid(volumeIndex + headerSize, volumeHeader->FvLength - headerSize);
QModelIndex index = addTreeItem(ItemTypes::VolumeItem, 0, header, body, parent);
// Parse volume
if (parseCurrentVolume) {
UINT32 result = parseVolume(bios.mid(volumeIndex + headerSize, volumeHeader->FvLength - headerSize), headerSize, volumeHeader->Revision, erasePolarity, index);
if (result)
debug(tr("Volume parsing failed (%1)").arg(result));
}
}
return ERR_SUCCESS;
}
INT32 UEFITool::getNextVolumeIndex(const QByteArray & bios, INT32 volumeIndex)
{
if (volumeIndex < 0)
return -1;
INT32 nextIndex = bios.indexOf(EFI_FV_SIGNATURE, volumeIndex);
if (nextIndex < EFI_FV_SIGNATURE_OFFSET) {
return -1;
}
return nextIndex - EFI_FV_SIGNATURE_OFFSET;
}
UINT32 UEFITool::getVolumeSize(const QByteArray & bios, INT32 volumeIndex)
{
// Populate volume header
EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*) (bios.constData() + volumeIndex);
// Check volume signature
if (QByteArray((const char*) &volumeHeader->Signature, sizeof(volumeHeader->Signature)) != EFI_FV_SIGNATURE)
return 0;
return volumeHeader->FvLength;
}
UINT8 UEFITool::parseVolume(const QByteArray & volume, UINT32 volumeBase, UINT8 revision, bool erasePolarity, QModelIndex & parent)
{
// Construct empty byte based on erasePolarity value
// Native char type is used because QByteArray.count() takes it
char empty = erasePolarity ? '\xFF' : '\x00';
// Search for and parse all files
INT32 fileIndex = 0;
while (fileIndex >= 0) {
EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*) (volume.constData() + fileIndex);
QByteArray file = volume.mid(fileIndex, uint24ToUint32(fileHeader->Size));
QByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER));
// We are at empty space in the end of volume
if (header.count(empty) == header.size()) {
QByteArray body = volume.right(volume.size() - fileIndex);
addTreeItem(ItemTypes::PaddingItem, 0, QByteArray(), body, parent);
break;
}
// Check header checksum
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((UINT8*) tempFileHeader, sizeof(EFI_FFS_FILE_HEADER) - 1);
if (fileHeader->IntegrityCheck.Checksum.Header != calculated)
{
debug(tr("%1: stored header checksum %2 differs from calculated %3")
.arg(guidToQString(fileHeader->Name))
.arg(fileHeader->IntegrityCheck.Checksum.Header, 2, 16, QChar('0'))
.arg(calculated, 2, 16, QChar('0')));
}
// Check data checksum, if no tail was found
// 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(revision == 1 && fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT)
bufferSize -= sizeof(UINT16);
calculated = calculateChecksum8((UINT8*)(file.constData() + sizeof(EFI_FFS_FILE_HEADER)), bufferSize);
if (fileHeader->IntegrityCheck.Checksum.File != calculated) {
debug(tr("%1: stored data checksum %2 differs from calculated %3")
.arg(guidToQString(fileHeader->Name))
.arg(fileHeader->IntegrityCheck.Checksum.File, 2, 16, QChar('0'))
.arg(calculated, 2, 16, QChar('0')));
}
}
// Data checksum must be one of predefined values
else {
if (fileHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM &&fileHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM2) {
debug(tr("%1: stored data checksum %2 differs from standard value")
.arg(guidToQString(fileHeader->Name))
.arg(fileHeader->IntegrityCheck.Checksum.File, 2, 16, QChar('0')));
}
}
// Check file alignment
UINT8 alignmentPower = ffsAlignmentTable[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3];
UINT32 alignment = pow(2, alignmentPower);
if ((volumeBase + fileIndex + sizeof(EFI_FFS_FILE_HEADER)) % alignment) {
debug(tr("%1: unaligned file").arg(guidToQString(fileHeader->Name)));
}
// Get file body
QByteArray body = file.right(file.size() - sizeof(EFI_FFS_FILE_HEADER));
// For files in Revision 1 volumes, check for file tail presence
if (revision == 1 && fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT)
{
//Check file tail;
UINT16* tail = (UINT16*) body.right(sizeof(UINT16)).constData();
if (!fileHeader->IntegrityCheck.TailReference == *tail)
debug(tr("%1: file tail value %2 is not a bitwise not of %3 stored in file header")
.arg(guidToQString(fileHeader->Name))
.arg(*tail, 4, 16, QChar('0'))
.arg(fileHeader->IntegrityCheck.TailReference, 4, 16, QChar('0')));
// Remove tail from file body
body = body.left(body.size() - sizeof(UINT16));
}
// Parse current file by default
bool parseCurrentFile = true;
// Raw files can hide volumes inside them
// So try to parse them as bios space
bool parseAsBios = false;
// Check file type
//!TODO: add more file specific checks
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_PAD:
parseCurrentFile = false;
break;
default:
parseCurrentFile = false;
debug(tr("Unknown file type (%1)").arg(fileHeader->Type, 2, 16, QChar('0')));
};
// Check for empty file
if (body.count(empty) == body.size())
{
// No need to parse empty files
parseCurrentFile = false;
}
// Add tree item
QModelIndex index = addTreeItem(ItemTypes::FileItem, fileHeader->Type, header, body, parent);
// Parse file
if (parseCurrentFile) {
if (parseAsBios) {
UINT32 result = parseBios(body, index);
if (result && result != ERR_VOLUMES_NOT_FOUND)
debug(tr("Parse file as BIOS failed (%1)").arg(result));
}
else {
UINT32 result = parseFile(body, revision, erasePolarity, index);
if (result)
debug(tr("Parse file as FFS failed (%1)").arg(result));
}
}
// Move to next file
fileIndex += file.size();
fileIndex = ALIGN8(fileIndex);
// Exit from loop if no files left
if (fileIndex >= volume.size())
fileIndex = -1;
}
return ERR_SUCCESS;
}
UINT8 UEFITool::parseFile(const QByteArray & file, UINT8 revision, bool erasePolarity, QModelIndex & parent)
{
// Search for and parse all sections
INT32 sectionIndex = 0;
while(sectionIndex >= 0)
{
EFI_COMMON_SECTION_HEADER* sectionHeader = (EFI_COMMON_SECTION_HEADER*) (file.constData() + sectionIndex);
UINT32 sectionSize = uint24ToUint32(sectionHeader->Size);
// This declarations must be here because of the nature of switch statement
EFI_COMPRESSION_SECTION* compressedSectionHeader;
EFI_GUID_DEFINED_SECTION* guidDefinedSectionHeader;
QByteArray header;
QByteArray body;
UINT32 decompressedSize;
UINT32 scratchSize;
UINT8* decompressed;
UINT8* scratch;
VOID* data;
UINT32 dataSize;
QModelIndex index;
UINT32 result;
bool lzmaHeaderFound;
switch (sectionHeader->Type)
{
// Encapsulated sections
case EFI_SECTION_COMPRESSION:
compressedSectionHeader = (EFI_COMPRESSION_SECTION*) sectionHeader;
header = file.mid(sectionIndex, sizeof(EFI_COMPRESSION_SECTION));
// Try to decompress this section
switch (compressedSectionHeader->CompressionType)
{
case EFI_NOT_COMPRESSED:
body = file.mid(sectionIndex + sizeof(EFI_COMPRESSION_SECTION), compressedSectionHeader->UncompressedLength);
index = addTreeItem(ItemTypes::SectionItem, SectionSubtypes::CompressionSection, header, body, parent);
// Parse stored file
result = parseFile(body, revision, erasePolarity, index);
if (result)
debug(tr("Stored section can not be parsed as file (%1)").arg(result));
break;
case EFI_STANDARD_COMPRESSION:
//Must be Tiano for all revisions, needs checking
body = file.mid(sectionIndex + sizeof(EFI_COMPRESSION_SECTION), sectionSize - sizeof(EFI_COMPRESSION_SECTION));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
// Get buffer sizes
data = (VOID*) (file.constData() + sectionIndex + sizeof(EFI_COMPRESSION_SECTION));
dataSize = uint24ToUint32(sectionHeader->Size) - sizeof(EFI_COMPRESSION_SECTION);
if (TianoGetInfo(data, dataSize, &decompressedSize, &scratchSize) != ERR_SUCCESS
|| decompressedSize != compressedSectionHeader->UncompressedLength)
debug(tr("TianoGetInfo failed"));
else {
decompressed = new UINT8[decompressedSize];
scratch = new UINT8[scratchSize];
// Decompress section data
if (TianoDecompress(data, dataSize, decompressed, decompressedSize, scratch, scratchSize) != ERR_SUCCESS)
debug(tr("TianoDecompress failed"));
else
{
body = QByteArray::fromRawData((const char*) decompressed, decompressedSize);
// Parse stored file
result = parseFile(body, revision, erasePolarity, index);
if (result)
debug(tr("Compressed section with Tiano compression can not be parsed as file (%1)").arg(result));
}
delete[] decompressed;
delete[] scratch;
}
break;
case EFI_CUSTOMIZED_COMPRESSION:
body = file.mid(sectionIndex + sizeof(EFI_COMPRESSION_SECTION), sectionSize - sizeof(EFI_COMPRESSION_SECTION));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
// Get buffer sizes
data = (VOID*) (file.constData() + sectionIndex + sizeof(EFI_COMPRESSION_SECTION));
dataSize = uint24ToUint32(sectionHeader->Size) - sizeof(EFI_COMPRESSION_SECTION);
if (LzmaGetInfo(data, dataSize, &decompressedSize) != ERR_SUCCESS
|| decompressedSize != compressedSectionHeader->UncompressedLength)
{
// Shitty file with some data between COMPRESSED_SECTION_HEADER and LZMA_HEADER
// Search for LZMA header in body
// Header structure: UINT8 LzmaProperties | UINT32 DictionarySize | UINT64 DecompressedSize
// We can't determine first two fiels here, but Decompressed size is known, so search for it
INT32 lzmaHeaderIndex = body.indexOf(QByteArray((const char*)&compressedSectionHeader->UncompressedLength,
sizeof(compressedSectionHeader->UncompressedLength)).append('\x00').append('\x00').append('\x00').append('\x00'));
lzmaHeaderIndex -= LZMA_PROPS_SIZE;
// LZMA header not found
if (lzmaHeaderIndex < 0)
{
lzmaHeaderFound = false;
debug(tr("Lzma header not found"));
}
// LZMA header found
else if (lzmaHeaderIndex) {
data = (VOID*) (file.constData() + sectionIndex + sizeof(EFI_COMPRESSION_SECTION) + lzmaHeaderIndex);
dataSize = uint24ToUint32(sectionHeader->Size) - sizeof(EFI_COMPRESSION_SECTION) - lzmaHeaderIndex;
// Get buffer sizes again
if (LzmaGetInfo(data, dataSize, &decompressedSize) != ERR_SUCCESS
|| decompressedSize != compressedSectionHeader->UncompressedLength)
{
debug(tr("LzmaGetInfo failed on LZMA header"));
lzmaHeaderFound = false;
}
else
debug(tr("Padding of size %1 between CompressedSectionHeader and LzmaHeader")
.arg(lzmaHeaderIndex));
}
lzmaHeaderFound = true;
}
else
lzmaHeaderFound = true;
// Decompress if header is found
if (lzmaHeaderFound) {
decompressed = new UINT8[decompressedSize];
// Decompress section data
if (LzmaDecompress(data, dataSize, decompressed) != ERR_SUCCESS)
debug(tr("LzmaDecompress failed"));
else
{
body = QByteArray::fromRawData((const char*) decompressed, decompressedSize);
// Parse stored file
result = parseFile(body, revision, erasePolarity, index);
if (result)
debug(tr("Compressed section with LZMA compression can not be parsed as file (%1)").arg(result));
}
delete[] decompressed;
}
break;
default:
body = file.mid(sectionIndex + sizeof(EFI_COMPRESSION_SECTION), sectionSize - sizeof(EFI_COMPRESSION_SECTION));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
debug(tr("Compressed section with unknown compression type found (%1)").arg(compressedSectionHeader->CompressionType));
}
break;
case EFI_SECTION_GUID_DEFINED:
header = file.mid(sectionIndex, sizeof(EFI_GUID_DEFINED_SECTION));
body = file.mid(sectionIndex + sizeof(EFI_GUID_DEFINED_SECTION), sectionSize - sizeof(EFI_GUID_DEFINED_SECTION));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
// Parse section body as file
guidDefinedSectionHeader = (EFI_GUID_DEFINED_SECTION*) (header.constData());
body = file.mid(sectionIndex + guidDefinedSectionHeader->DataOffset, sectionSize - guidDefinedSectionHeader->DataOffset);
result = parseFile(body, revision, erasePolarity, index);
if (result)
debug(tr("GUID defined section body can not be parsed as file (%1)").arg(result));
break;
case EFI_SECTION_DISPOSABLE:
header = file.mid(sectionIndex, sizeof(EFI_DISPOSABLE_SECTION));
body = file.mid(sectionIndex + sizeof(EFI_DISPOSABLE_SECTION), sectionSize - sizeof(EFI_DISPOSABLE_SECTION));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
break;
// Leaf sections
case EFI_SECTION_PE32:
header = file.mid(sectionIndex, sizeof(EFI_PE32_SECTION));
body = file.mid(sectionIndex + sizeof(EFI_PE32_SECTION), sectionSize - sizeof(EFI_PE32_SECTION));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
break;
case EFI_SECTION_PIC:
header = file.mid(sectionIndex, sizeof(EFI_PIC_SECTION));
body = file.mid(sectionIndex + sizeof(EFI_PIC_SECTION), sectionSize - sizeof(EFI_PIC_SECTION));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
break;
case EFI_SECTION_TE:
header = file.mid(sectionIndex, sizeof(EFI_TE_SECTION));
body = file.mid(sectionIndex + sizeof(EFI_TE_SECTION), sectionSize - sizeof(EFI_TE_SECTION));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
break;
case EFI_SECTION_VERSION:
header = file.mid(sectionIndex, sizeof(EFI_VERSION_SECTION));
body = file.mid(sectionIndex + sizeof(EFI_VERSION_SECTION), sectionSize - sizeof(EFI_VERSION_SECTION));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
break;
case EFI_SECTION_USER_INTERFACE:
header = file.mid(sectionIndex, sizeof(EFI_USER_INTERFACE_SECTION));
body = file.mid(sectionIndex + sizeof(EFI_USER_INTERFACE_SECTION), sectionSize - sizeof(EFI_USER_INTERFACE_SECTION));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
break;
case EFI_SECTION_COMPATIBILITY16:
header = file.mid(sectionIndex, sizeof(EFI_COMPATIBILITY16_SECTION));
body = file.mid(sectionIndex + sizeof(EFI_COMPATIBILITY16_SECTION), sectionSize - sizeof(EFI_COMPATIBILITY16_SECTION));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
break;
case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
header = file.mid(sectionIndex, sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION));
body = file.mid(sectionIndex + sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION), sectionSize - sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
// Parse section body as BIOS space
result = parseBios(body, index);
if (result && result != ERR_VOLUMES_NOT_FOUND)
debug(tr("Firmware volume image can not be parsed (%1)").arg(result));
break;
case EFI_SECTION_FREEFORM_SUBTYPE_GUID:
header = file.mid(sectionIndex, sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION));
body = file.mid(sectionIndex + sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION), sectionSize - sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
break;
case EFI_SECTION_RAW:
header = file.mid(sectionIndex, sizeof(EFI_RAW_SECTION));
body = file.mid(sectionIndex + sizeof(EFI_RAW_SECTION), sectionSize - sizeof(EFI_RAW_SECTION));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
// Parse section body as BIOS space
result = parseBios(body, index);
if (result && result != ERR_VOLUMES_NOT_FOUND)
debug(tr("Raw section can not be parsed as BIOS (%1)").arg(result));
break;
break;
case EFI_SECTION_DXE_DEPEX:
header = file.mid(sectionIndex, sizeof(EFI_DXE_DEPEX_SECTION));
body = file.mid(sectionIndex + sizeof(EFI_DXE_DEPEX_SECTION), sectionSize - sizeof(EFI_DXE_DEPEX_SECTION));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
break;
case EFI_SECTION_PEI_DEPEX:
header = file.mid(sectionIndex, sizeof(EFI_PEI_DEPEX_SECTION));
body = file.mid(sectionIndex + sizeof(EFI_PEI_DEPEX_SECTION), sectionSize - sizeof(EFI_PEI_DEPEX_SECTION));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
break;
case EFI_SECTION_SMM_DEPEX:
header = file.mid(sectionIndex, sizeof(EFI_SMM_DEPEX_SECTION));
body = file.mid(sectionIndex + sizeof(EFI_SMM_DEPEX_SECTION), sectionSize - sizeof(EFI_SMM_DEPEX_SECTION));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
break;
default:
debug(tr("Section with unknown type (%1)").arg(sectionHeader->Type, 2, 16, QChar('0')));
header = file.mid(sectionIndex, sizeof(EFI_COMMON_SECTION_HEADER));
body = file.mid(sectionIndex + sizeof(EFI_COMMON_SECTION_HEADER), sectionSize - sizeof(EFI_COMMON_SECTION_HEADER));
index = addTreeItem(ItemTypes::SectionItem, sectionHeader->Type, header, body, parent);
}
// Move to next section
sectionIndex += uint24ToUint32(sectionHeader->Size);
sectionIndex = ALIGN4(sectionIndex);
// Exit from loop if no sections left
if (sectionIndex >= file.size())
sectionIndex = -1;
}
return ERR_SUCCESS;
}

84
uefitool.h Normal file
View file

@ -0,0 +1,84 @@
/* uefitool.h
Copyright (c) 2013, 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,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#ifndef __UEFITOOL_H__
#define __UEFITOOL_H__
#include <QMainWindow>
#include <QByteArray>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QFile>
#include <QFileDialog>
#include <QFileInfo>
#include <QMessageBox>
#include <QMimeData>
#include <QString>
#include <QUrl>
#include <math.h>
#include "treemodel.h"
#include "basetypes.h"
#include "descriptor.h"
#include "ffs.h"
#include "Tiano\EfiTianoCompress.h"
#include "Tiano\EfiTianoDecompress.h"
#include "LZMA\LzmaCompress.h"
#include "LZMA\LzmaDecompress.h"
namespace Ui {
class UEFITool;
}
class UEFITool : public QMainWindow
{
Q_OBJECT
public:
explicit UEFITool(QWidget *parent = 0);
~UEFITool();
void openImageFile(QString path);
private slots:
void init();
void openImageFile();
//void saveImageFile();
void populateUi(const QModelIndex &current/*, const QModelIndex &previous*/);
void resizeTreeViewColums(/*const QModelIndex &index*/);
void saveAll();
void saveBody();
private:
Ui::UEFITool * ui;
TreeModel * treeModel;
QModelIndex currentIndex;
void debug(const QString & text);
void dragEnterEvent(QDragEnterEvent* event);
void dropEvent(QDropEvent* event);
QModelIndex addTreeItem(UINT8 type, UINT8 subtype, const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(),
const QModelIndex & parent = QModelIndex());
UINT8 parseInputFile(const QByteArray & buffer);
UINT8* parseRegion(const QByteArray & flashImage, UINT8 regionSubtype, const UINT16 regionBase, const UINT16 regionLimit, QModelIndex & index);
UINT8 parseBios(const QByteArray & bios, QModelIndex & parent = QModelIndex());
INT32 getNextVolumeIndex(const QByteArray & bios, INT32 volumeIndex = 0);
UINT32 getVolumeSize(const QByteArray & bios, INT32 volumeIndex);
UINT8 parseVolume(const QByteArray & volume, UINT32 volumeBase, UINT8 revision, bool erasePolarity, QModelIndex & parent = QModelIndex());
UINT8 parseFile(const QByteArray & file, UINT8 revision, bool erasePolarity, QModelIndex & parent = QModelIndex());
};
#endif

BIN
uefitool.icns Normal file

Binary file not shown.

BIN
uefitool.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

34
uefitool.pro Normal file
View file

@ -0,0 +1,34 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = UEFITool
TEMPLATE = app
SOURCES += main.cpp \
uefitool.cpp \
descriptor.cpp \
ffs.cpp \
treeitem.cpp \
treemodel.cpp \
LZMA/LzmaCompress.c \
LZMA/LzmaDecompress.c \
LZMA/Sdk/C/LzFind.c \
LZMA/Sdk/C/LzmaDec.c \
LZMA/Sdk/C/LzmaEnc.c \
Tiano/EfiTianoDecompress.c \
Tiano/EfiCompress.c \
Tiano/TianoCompress.c
HEADERS += uefitool.h \
basetypes.h \
descriptor.h \
ffs.h \
treeitem.h \
treemodel.h \
LZMA/LzmaCompress.h \
LZMA/LzmaDecompress.h \
Tiano/EfiTianoDecompress.h \
Tiano/EfiTianoCompress.h
FORMS += uefitool.ui
RC_FILE = uefitool.rc
ICON = uefitool.icns

1
uefitool.rc Normal file
View file

@ -0,0 +1 @@
IDI_ICON1 ICON DISCARDABLE "uefitool.ico"

211
uefitool.ui Normal file
View file

@ -0,0 +1,211 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>UEFITool</class>
<widget class="QMainWindow" name="UEFITool">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>900</width>
<height>600</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="windowTitle">
<string>UEFITool 0.2.0</string>
</property>
<widget class="QWidget" name="centralWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<widget class="QGroupBox" name="structureGroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Structure</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QTreeView" name="structureTreeView">
<property name="font">
<font>
<family>Consolas</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="indentation">
<number>10</number>
</property>
<property name="headerHidden">
<bool>false</bool>
</property>
<attribute name="headerCascadingSectionResizes">
<bool>true</bool>
</attribute>
<attribute name="headerDefaultSectionSize">
<number>200</number>
</attribute>
<attribute name="headerStretchLastSection">
<bool>true</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QGroupBox" name="infoGroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>216</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>Information</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPlainTextEdit" name="infoEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>Consolas</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="undoRedoEnabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="centerOnScroll">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="exportAllButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Export...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="exportBodyButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Export without header...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QGroupBox" name="debugGroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Debug</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPlainTextEdit" name="debugEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>100</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>50</height>
</size>
</property>
<property name="font">
<font>
<family>Consolas</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="undoRedoEnabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="centerOnScroll">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QPushButton" name="fromFileButton">
<property name="text">
<string>Open BIOS image file...</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>