mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-07-30 07:44:13 +02:00
Bundle LZMA SDK for .edz extraction; drop 7z CLI dependency (M3)
Replaces the QProcess->7z shim with the public-domain LZMA SDK (23.01) 7-Zip reader, vendored under sources/import/edz/lzma/ (decode-only subset). New edzsevenzip.cpp wraps SzArEx_Open/SzArEx_Extract and writes entries via Qt, so EdzArchive no longer needs an external 7-Zip at runtime. Enables the C language in CMake for the vendored sources. Verified: the bundled decoder extracts all three ifm sample .edz and the generated elements still match the Python oracle exactly (byte-correct decode), with no 7z on the path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -22,7 +22,7 @@ project(qelectrotech
|
|||||||
VERSION 0.100.1
|
VERSION 0.100.1
|
||||||
DESCRIPTION "QET is a CAD/CAE editor focusing on schematics drawing features."
|
DESCRIPTION "QET is a CAD/CAE editor focusing on schematics drawing features."
|
||||||
HOMEPAGE_URL "https://qelectrotech.org/"
|
HOMEPAGE_URL "https://qelectrotech.org/"
|
||||||
LANGUAGES CXX)
|
LANGUAGES C CXX)
|
||||||
|
|
||||||
include(cmake/copyright_message.cmake)
|
include(cmake/copyright_message.cmake)
|
||||||
|
|
||||||
|
|||||||
@@ -115,6 +115,26 @@ set(QET_SRC_FILES
|
|||||||
${QET_DIR}/sources/import/edz/edzelementbuilder.h
|
${QET_DIR}/sources/import/edz/edzelementbuilder.h
|
||||||
${QET_DIR}/sources/import/edz/edzimporter.cpp
|
${QET_DIR}/sources/import/edz/edzimporter.cpp
|
||||||
${QET_DIR}/sources/import/edz/edzimporter.h
|
${QET_DIR}/sources/import/edz/edzimporter.h
|
||||||
|
${QET_DIR}/sources/import/edz/edzsevenzip.cpp
|
||||||
|
${QET_DIR}/sources/import/edz/edzsevenzip.h
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/7zAlloc.c
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/7zArcIn.c
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/7zBuf.c
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/7zCrc.c
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/7zCrcOpt.c
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/7zDec.c
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/7zFile.c
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/7zStream.c
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/Bcj2.c
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/Bra.c
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/Bra86.c
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/BraIA64.c
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/CpuArch.c
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/Delta.c
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/Lzma2Dec.c
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/LzmaDec.c
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/Ppmd7.c
|
||||||
|
${QET_DIR}/sources/import/edz/lzma/Ppmd7Dec.c
|
||||||
${QET_DIR}/sources/borderproperties.cpp
|
${QET_DIR}/sources/borderproperties.cpp
|
||||||
${QET_DIR}/sources/borderproperties.h
|
${QET_DIR}/sources/borderproperties.h
|
||||||
${QET_DIR}/sources/bordertitleblock.cpp
|
${QET_DIR}/sources/bordertitleblock.cpp
|
||||||
|
|||||||
@@ -17,11 +17,11 @@
|
|||||||
*/
|
*/
|
||||||
#include "edzarchive.h"
|
#include "edzarchive.h"
|
||||||
|
|
||||||
|
#include "edzsevenzip.h"
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QProcess>
|
|
||||||
#include <QStandardPaths>
|
|
||||||
#include <QTemporaryDir>
|
#include <QTemporaryDir>
|
||||||
|
|
||||||
EdzArchive::EdzArchive() = default;
|
EdzArchive::EdzArchive() = default;
|
||||||
@@ -48,7 +48,7 @@ bool EdzArchive::extract(const QString &edz_path)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!extractWithSevenZipCli(fi.absoluteFilePath(), m_dir->path())) {
|
if (!sevenZipExtract(fi.absoluteFilePath(), m_dir->path(), m_error)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,74 +81,3 @@ QString EdzArchive::errorString() const
|
|||||||
{
|
{
|
||||||
return m_error;
|
return m_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
M0 backend: run a 7-Zip command-line tool to extract the archive.
|
|
||||||
Placeholder for a bundled decompressor in a later milestone.
|
|
||||||
*/
|
|
||||||
bool EdzArchive::extractWithSevenZipCli(const QString &edz_path,
|
|
||||||
const QString &dest)
|
|
||||||
{
|
|
||||||
const QString exe = findSevenZip();
|
|
||||||
if (exe.isEmpty()) {
|
|
||||||
m_error = QStringLiteral(
|
|
||||||
"7-Zip not found. A .edz is a 7z archive; install 7-Zip or "
|
|
||||||
"put 7z on PATH.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QProcess proc;
|
|
||||||
proc.start(exe, QStringList{QStringLiteral("x"), edz_path,
|
|
||||||
QStringLiteral("-o%1").arg(dest),
|
|
||||||
QStringLiteral("-y")});
|
|
||||||
if (!proc.waitForStarted()) {
|
|
||||||
m_error = QStringLiteral("Could not start 7-Zip: %1").arg(exe);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
proc.waitForFinished(-1);
|
|
||||||
|
|
||||||
if (proc.exitStatus() != QProcess::NormalExit || proc.exitCode() != 0) {
|
|
||||||
QString detail;
|
|
||||||
const QString out = QString::fromLocal8Bit(proc.readAllStandardOutput());
|
|
||||||
for (const QString &line : out.split('\n')) {
|
|
||||||
const QString t = line.trimmed();
|
|
||||||
if (t.startsWith(QStringLiteral("ERROR"))
|
|
||||||
|| t.startsWith(QStringLiteral("Cannot"))
|
|
||||||
|| t.startsWith(QStringLiteral("Can't"))) {
|
|
||||||
detail += (detail.isEmpty() ? QString() : QStringLiteral(" ")) + t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (detail.isEmpty()) {
|
|
||||||
detail = QStringLiteral("7-Zip exit code %1").arg(proc.exitCode());
|
|
||||||
}
|
|
||||||
m_error = QStringLiteral("7-Zip could not extract the archive: %1")
|
|
||||||
.arg(detail);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Locate a 7-Zip executable: PATH first, then the usual install locations. */
|
|
||||||
QString EdzArchive::findSevenZip()
|
|
||||||
{
|
|
||||||
for (const QString &name : {QStringLiteral("7z"), QStringLiteral("7za"),
|
|
||||||
QStringLiteral("7zr")}) {
|
|
||||||
const QString found = QStandardPaths::findExecutable(name);
|
|
||||||
if (!found.isEmpty()) {
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const QStringList candidates {
|
|
||||||
QStringLiteral("C:/Program Files/7-Zip/7z.exe"),
|
|
||||||
QStringLiteral("C:/Program Files (x86)/7-Zip/7z.exe"),
|
|
||||||
QStringLiteral("/usr/bin/7z"),
|
|
||||||
QStringLiteral("/usr/local/bin/7z"),
|
|
||||||
QStringLiteral("/opt/homebrew/bin/7z"),
|
|
||||||
};
|
|
||||||
for (const QString &c : candidates) {
|
|
||||||
if (QFileInfo::exists(c)) {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -30,10 +30,8 @@ class QTemporaryDir;
|
|||||||
macro, a product image and metadata. EdzArchive unpacks it so the rest of the
|
macro, a product image and metadata. EdzArchive unpacks it so the rest of the
|
||||||
import pipeline can read the (portable) part.xml.
|
import pipeline can read the (portable) part.xml.
|
||||||
|
|
||||||
The extraction backend sits behind a single private method so it can be
|
Extraction uses the bundled (public-domain) LZMA SDK 7-Zip reader, so no
|
||||||
swapped without touching callers: this M0 spike shells out to a 7-Zip CLI via
|
external 7-Zip is required at runtime (see edzsevenzip).
|
||||||
QProcess; a later milestone replaces that with a bundled decompressor so no
|
|
||||||
external tool is required at runtime.
|
|
||||||
|
|
||||||
The extracted tree lives in a QTemporaryDir owned by this object and is
|
The extracted tree lives in a QTemporaryDir owned by this object and is
|
||||||
removed when the EdzArchive is destroyed.
|
removed when the EdzArchive is destroyed.
|
||||||
@@ -51,10 +49,6 @@ class EdzArchive
|
|||||||
QString errorString() const;
|
QString errorString() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool extractWithSevenZipCli(const QString &edz_path,
|
|
||||||
const QString &dest);
|
|
||||||
static QString findSevenZip();
|
|
||||||
|
|
||||||
QScopedPointer<QTemporaryDir> m_dir;
|
QScopedPointer<QTemporaryDir> m_dir;
|
||||||
QString m_error;
|
QString m_error;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2006 The QElectroTech Team
|
||||||
|
This file is part of QElectroTech.
|
||||||
|
|
||||||
|
QElectroTech is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
QElectroTech is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "edzsevenzip.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// Bundled public-domain LZMA SDK 7-Zip reader (decode only). The headers
|
||||||
|
// self-guard with EXTERN_C_BEGIN, so they are included directly from C++.
|
||||||
|
#include "lzma/7z.h"
|
||||||
|
#include "lzma/7zAlloc.h"
|
||||||
|
#include "lzma/7zCrc.h"
|
||||||
|
#include "lzma/7zFile.h"
|
||||||
|
#include "lzma/7zTypes.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const size_t kInputBufSize = (size_t)1 << 18;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool sevenZipExtract(const QString &archivePath, const QString &destDir,
|
||||||
|
QString &error)
|
||||||
|
{
|
||||||
|
error.clear();
|
||||||
|
|
||||||
|
ISzAlloc allocImp = { SzAlloc, SzFree };
|
||||||
|
ISzAlloc allocTempImp = { SzAllocTemp, SzFreeTemp };
|
||||||
|
|
||||||
|
CFileInStream archiveStream;
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (InFile_OpenW(&archiveStream.file,
|
||||||
|
reinterpret_cast<const wchar_t *>(archivePath.utf16())) != 0)
|
||||||
|
#else
|
||||||
|
const QByteArray apath = QFile::encodeName(archivePath);
|
||||||
|
if (InFile_Open(&archiveStream.file, apath.constData()) != 0)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
error = QStringLiteral("Cannot open archive: %1").arg(archivePath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileInStream_CreateVTable(&archiveStream);
|
||||||
|
archiveStream.wres = 0;
|
||||||
|
|
||||||
|
CLookToRead2 lookStream;
|
||||||
|
LookToRead2_CreateVTable(&lookStream, False);
|
||||||
|
lookStream.buf = nullptr;
|
||||||
|
|
||||||
|
SRes res = SZ_OK;
|
||||||
|
lookStream.buf = static_cast<Byte *>(ISzAlloc_Alloc(&allocImp, kInputBufSize));
|
||||||
|
if (!lookStream.buf) {
|
||||||
|
res = SZ_ERROR_MEM;
|
||||||
|
} else {
|
||||||
|
lookStream.bufSize = kInputBufSize;
|
||||||
|
lookStream.realStream = &archiveStream.vt;
|
||||||
|
LookToRead2_INIT(&lookStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
CrcGenerateTable();
|
||||||
|
|
||||||
|
CSzArEx db;
|
||||||
|
SzArEx_Init(&db);
|
||||||
|
|
||||||
|
if (res == SZ_OK) {
|
||||||
|
res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok = (res == SZ_OK);
|
||||||
|
if (ok) {
|
||||||
|
const QDir dest(destDir);
|
||||||
|
// Cache shared across entries of the same solid block (see SzArEx_Extract).
|
||||||
|
UInt32 blockIndex = 0xFFFFFFFF;
|
||||||
|
Byte *outBuffer = nullptr;
|
||||||
|
size_t outBufferSize = 0;
|
||||||
|
std::vector<UInt16> name;
|
||||||
|
|
||||||
|
for (UInt32 i = 0; i < db.NumFiles && res == SZ_OK; ++i) {
|
||||||
|
const BoolInt is_dir = SzArEx_IsDir(&db, i);
|
||||||
|
|
||||||
|
const size_t len = SzArEx_GetFileNameUtf16(&db, i, nullptr);
|
||||||
|
name.resize(len ? len : 1);
|
||||||
|
SzArEx_GetFileNameUtf16(&db, i, name.data());
|
||||||
|
QString rel = QString::fromUtf16(
|
||||||
|
reinterpret_cast<const char16_t *>(name.data()));
|
||||||
|
rel.replace(QLatin1Char('\\'), QLatin1Char('/'));
|
||||||
|
if (rel.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_dir) {
|
||||||
|
dest.mkpath(rel);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString out_path = dest.filePath(rel);
|
||||||
|
dest.mkpath(QFileInfo(out_path).path());
|
||||||
|
|
||||||
|
size_t offset = 0, outSizeProcessed = 0;
|
||||||
|
res = SzArEx_Extract(&db, &lookStream.vt, i, &blockIndex,
|
||||||
|
&outBuffer, &outBufferSize,
|
||||||
|
&offset, &outSizeProcessed,
|
||||||
|
&allocImp, &allocTempImp);
|
||||||
|
if (res != SZ_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile f(out_path);
|
||||||
|
if (!f.open(QIODevice::WriteOnly)) {
|
||||||
|
error = QStringLiteral("Cannot write %1").arg(out_path);
|
||||||
|
res = SZ_ERROR_FAIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const qint64 want = static_cast<qint64>(outSizeProcessed);
|
||||||
|
if (f.write(reinterpret_cast<const char *>(outBuffer + offset),
|
||||||
|
want) != want) {
|
||||||
|
error = QStringLiteral("Short write to %1").arg(out_path);
|
||||||
|
res = SZ_ERROR_FAIL;
|
||||||
|
f.close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
ISzAlloc_Free(&allocImp, outBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
SzArEx_Free(&db, &allocImp);
|
||||||
|
ISzAlloc_Free(&allocImp, lookStream.buf);
|
||||||
|
File_Close(&archiveStream.file);
|
||||||
|
|
||||||
|
if (res != SZ_OK) {
|
||||||
|
if (error.isEmpty()) {
|
||||||
|
error = QStringLiteral("7z decode failed (code %1)")
|
||||||
|
.arg(static_cast<int>(res));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2006 The QElectroTech Team
|
||||||
|
This file is part of QElectroTech.
|
||||||
|
|
||||||
|
QElectroTech is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
QElectroTech is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef EDZSEVENZIP_H
|
||||||
|
#define EDZSEVENZIP_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
/**
|
||||||
|
Extract every entry of the 7-Zip archive at @a archivePath into @a destDir,
|
||||||
|
using the bundled (public-domain) LZMA SDK — no external 7-Zip needed.
|
||||||
|
@return true on success; on failure @a error explains why.
|
||||||
|
*/
|
||||||
|
bool sevenZipExtract(const QString &archivePath, const QString &destDir,
|
||||||
|
QString &error);
|
||||||
|
|
||||||
|
#endif // EDZSEVENZIP_H
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
/* 7z.h -- 7z interface
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_7Z_H
|
||||||
|
#define ZIP7_INC_7Z_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
#define k7zStartHeaderSize 0x20
|
||||||
|
#define k7zSignatureSize 6
|
||||||
|
|
||||||
|
extern const Byte k7zSignature[k7zSignatureSize];
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const Byte *Data;
|
||||||
|
size_t Size;
|
||||||
|
} CSzData;
|
||||||
|
|
||||||
|
/* CSzCoderInfo & CSzFolder support only default methods */
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
size_t PropsOffset;
|
||||||
|
UInt32 MethodID;
|
||||||
|
Byte NumStreams;
|
||||||
|
Byte PropsSize;
|
||||||
|
} CSzCoderInfo;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UInt32 InIndex;
|
||||||
|
UInt32 OutIndex;
|
||||||
|
} CSzBond;
|
||||||
|
|
||||||
|
#define SZ_NUM_CODERS_IN_FOLDER_MAX 4
|
||||||
|
#define SZ_NUM_BONDS_IN_FOLDER_MAX 3
|
||||||
|
#define SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX 4
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UInt32 NumCoders;
|
||||||
|
UInt32 NumBonds;
|
||||||
|
UInt32 NumPackStreams;
|
||||||
|
UInt32 UnpackStream;
|
||||||
|
UInt32 PackStreams[SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX];
|
||||||
|
CSzBond Bonds[SZ_NUM_BONDS_IN_FOLDER_MAX];
|
||||||
|
CSzCoderInfo Coders[SZ_NUM_CODERS_IN_FOLDER_MAX];
|
||||||
|
} CSzFolder;
|
||||||
|
|
||||||
|
|
||||||
|
SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UInt32 Low;
|
||||||
|
UInt32 High;
|
||||||
|
} CNtfsFileTime;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Byte *Defs; /* MSB 0 bit numbering */
|
||||||
|
UInt32 *Vals;
|
||||||
|
} CSzBitUi32s;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Byte *Defs; /* MSB 0 bit numbering */
|
||||||
|
// UInt64 *Vals;
|
||||||
|
CNtfsFileTime *Vals;
|
||||||
|
} CSzBitUi64s;
|
||||||
|
|
||||||
|
#define SzBitArray_Check(p, i) (((p)[(i) >> 3] & (0x80 >> ((i) & 7))) != 0)
|
||||||
|
|
||||||
|
#define SzBitWithVals_Check(p, i) ((p)->Defs && ((p)->Defs[(i) >> 3] & (0x80 >> ((i) & 7))) != 0)
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UInt32 NumPackStreams;
|
||||||
|
UInt32 NumFolders;
|
||||||
|
|
||||||
|
UInt64 *PackPositions; // NumPackStreams + 1
|
||||||
|
CSzBitUi32s FolderCRCs; // NumFolders
|
||||||
|
|
||||||
|
size_t *FoCodersOffsets; // NumFolders + 1
|
||||||
|
UInt32 *FoStartPackStreamIndex; // NumFolders + 1
|
||||||
|
UInt32 *FoToCoderUnpackSizes; // NumFolders + 1
|
||||||
|
Byte *FoToMainUnpackSizeIndex; // NumFolders
|
||||||
|
UInt64 *CoderUnpackSizes; // for all coders in all folders
|
||||||
|
|
||||||
|
Byte *CodersData;
|
||||||
|
|
||||||
|
UInt64 RangeLimit;
|
||||||
|
} CSzAr;
|
||||||
|
|
||||||
|
UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex);
|
||||||
|
|
||||||
|
SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
|
||||||
|
ILookInStreamPtr stream, UInt64 startPos,
|
||||||
|
Byte *outBuffer, size_t outSize,
|
||||||
|
ISzAllocPtr allocMain);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
CSzAr db;
|
||||||
|
|
||||||
|
UInt64 startPosAfterHeader;
|
||||||
|
UInt64 dataPos;
|
||||||
|
|
||||||
|
UInt32 NumFiles;
|
||||||
|
|
||||||
|
UInt64 *UnpackPositions; // NumFiles + 1
|
||||||
|
// Byte *IsEmptyFiles;
|
||||||
|
Byte *IsDirs;
|
||||||
|
CSzBitUi32s CRCs;
|
||||||
|
|
||||||
|
CSzBitUi32s Attribs;
|
||||||
|
// CSzBitUi32s Parents;
|
||||||
|
CSzBitUi64s MTime;
|
||||||
|
CSzBitUi64s CTime;
|
||||||
|
|
||||||
|
UInt32 *FolderToFile; // NumFolders + 1
|
||||||
|
UInt32 *FileToFolder; // NumFiles
|
||||||
|
|
||||||
|
size_t *FileNameOffsets; /* in 2-byte steps */
|
||||||
|
Byte *FileNames; /* UTF-16-LE */
|
||||||
|
} CSzArEx;
|
||||||
|
|
||||||
|
#define SzArEx_IsDir(p, i) (SzBitArray_Check((p)->IsDirs, i))
|
||||||
|
|
||||||
|
#define SzArEx_GetFileSize(p, i) ((p)->UnpackPositions[(i) + 1] - (p)->UnpackPositions[i])
|
||||||
|
|
||||||
|
void SzArEx_Init(CSzArEx *p);
|
||||||
|
void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc);
|
||||||
|
UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder);
|
||||||
|
int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if dest == NULL, the return value specifies the required size of the buffer,
|
||||||
|
in 16-bit characters, including the null-terminating character.
|
||||||
|
if dest != NULL, the return value specifies the number of 16-bit characters that
|
||||||
|
are written to the dest, including the null-terminating character. */
|
||||||
|
|
||||||
|
size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
|
||||||
|
|
||||||
|
/*
|
||||||
|
size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex);
|
||||||
|
UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
SzArEx_Extract extracts file from archive
|
||||||
|
|
||||||
|
*outBuffer must be 0 before first call for each new archive.
|
||||||
|
|
||||||
|
Extracting cache:
|
||||||
|
If you need to decompress more than one file, you can send
|
||||||
|
these values from previous call:
|
||||||
|
*blockIndex,
|
||||||
|
*outBuffer,
|
||||||
|
*outBufferSize
|
||||||
|
You can consider "*outBuffer" as cache of solid block. If your archive is solid,
|
||||||
|
it will increase decompression speed.
|
||||||
|
|
||||||
|
If you use external function, you can declare these 3 cache variables
|
||||||
|
(blockIndex, outBuffer, outBufferSize) as static in that external function.
|
||||||
|
|
||||||
|
Free *outBuffer and set *outBuffer to 0, if you want to flush cache.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SRes SzArEx_Extract(
|
||||||
|
const CSzArEx *db,
|
||||||
|
ILookInStreamPtr inStream,
|
||||||
|
UInt32 fileIndex, /* index of file */
|
||||||
|
UInt32 *blockIndex, /* index of solid block */
|
||||||
|
Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
|
||||||
|
size_t *outBufferSize, /* buffer size for output buffer */
|
||||||
|
size_t *offset, /* offset of stream for required file in *outBuffer */
|
||||||
|
size_t *outSizeProcessed, /* size of file in *outBuffer */
|
||||||
|
ISzAllocPtr allocMain,
|
||||||
|
ISzAllocPtr allocTemp);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
SzArEx_Open Errors:
|
||||||
|
SZ_ERROR_NO_ARCHIVE
|
||||||
|
SZ_ERROR_ARCHIVE
|
||||||
|
SZ_ERROR_UNSUPPORTED
|
||||||
|
SZ_ERROR_MEM
|
||||||
|
SZ_ERROR_CRC
|
||||||
|
SZ_ERROR_INPUT_EOF
|
||||||
|
SZ_ERROR_FAIL
|
||||||
|
*/
|
||||||
|
|
||||||
|
SRes SzArEx_Open(CSzArEx *p, ILookInStreamPtr inStream,
|
||||||
|
ISzAllocPtr allocMain, ISzAllocPtr allocTemp);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
/* 7zAlloc.c -- Allocation functions for 7z processing
|
||||||
|
2023-03-04 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#include "Precomp.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "7zAlloc.h"
|
||||||
|
|
||||||
|
/* #define SZ_ALLOC_DEBUG */
|
||||||
|
/* use SZ_ALLOC_DEBUG to debug alloc/free operations */
|
||||||
|
|
||||||
|
#ifdef SZ_ALLOC_DEBUG
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "7zWindows.h"
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
static int g_allocCount = 0;
|
||||||
|
static int g_allocCountTemp = 0;
|
||||||
|
|
||||||
|
static void Print_Alloc(const char *s, size_t size, int *counter)
|
||||||
|
{
|
||||||
|
const unsigned size2 = (unsigned)size;
|
||||||
|
fprintf(stderr, "\n%s count = %10d : %10u bytes; ", s, *counter, size2);
|
||||||
|
(*counter)++;
|
||||||
|
}
|
||||||
|
static void Print_Free(const char *s, int *counter)
|
||||||
|
{
|
||||||
|
(*counter)--;
|
||||||
|
fprintf(stderr, "\n%s count = %10d", s, *counter);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *SzAlloc(ISzAllocPtr p, size_t size)
|
||||||
|
{
|
||||||
|
UNUSED_VAR(p)
|
||||||
|
if (size == 0)
|
||||||
|
return 0;
|
||||||
|
#ifdef SZ_ALLOC_DEBUG
|
||||||
|
Print_Alloc("Alloc", size, &g_allocCount);
|
||||||
|
#endif
|
||||||
|
return malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SzFree(ISzAllocPtr p, void *address)
|
||||||
|
{
|
||||||
|
UNUSED_VAR(p)
|
||||||
|
#ifdef SZ_ALLOC_DEBUG
|
||||||
|
if (address)
|
||||||
|
Print_Free("Free ", &g_allocCount);
|
||||||
|
#endif
|
||||||
|
free(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *SzAllocTemp(ISzAllocPtr p, size_t size)
|
||||||
|
{
|
||||||
|
UNUSED_VAR(p)
|
||||||
|
if (size == 0)
|
||||||
|
return 0;
|
||||||
|
#ifdef SZ_ALLOC_DEBUG
|
||||||
|
Print_Alloc("Alloc_temp", size, &g_allocCountTemp);
|
||||||
|
/*
|
||||||
|
#ifdef _WIN32
|
||||||
|
return HeapAlloc(GetProcessHeap(), 0, size);
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
return malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SzFreeTemp(ISzAllocPtr p, void *address)
|
||||||
|
{
|
||||||
|
UNUSED_VAR(p)
|
||||||
|
#ifdef SZ_ALLOC_DEBUG
|
||||||
|
if (address)
|
||||||
|
Print_Free("Free_temp ", &g_allocCountTemp);
|
||||||
|
/*
|
||||||
|
#ifdef _WIN32
|
||||||
|
HeapFree(GetProcessHeap(), 0, address);
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
free(address);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/* 7zAlloc.h -- Allocation functions
|
||||||
|
2023-03-04 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_7Z_ALLOC_H
|
||||||
|
#define ZIP7_INC_7Z_ALLOC_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
void *SzAlloc(ISzAllocPtr p, size_t size);
|
||||||
|
void SzFree(ISzAllocPtr p, void *address);
|
||||||
|
|
||||||
|
void *SzAllocTemp(ISzAllocPtr p, size_t size);
|
||||||
|
void SzFreeTemp(ISzAllocPtr p, void *address);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,36 @@
|
|||||||
|
/* 7zBuf.c -- Byte Buffer
|
||||||
|
2017-04-03 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#include "Precomp.h"
|
||||||
|
|
||||||
|
#include "7zBuf.h"
|
||||||
|
|
||||||
|
void Buf_Init(CBuf *p)
|
||||||
|
{
|
||||||
|
p->data = 0;
|
||||||
|
p->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc)
|
||||||
|
{
|
||||||
|
p->size = 0;
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
p->data = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
p->data = (Byte *)ISzAlloc_Alloc(alloc, size);
|
||||||
|
if (p->data)
|
||||||
|
{
|
||||||
|
p->size = size;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Buf_Free(CBuf *p, ISzAllocPtr alloc)
|
||||||
|
{
|
||||||
|
ISzAlloc_Free(alloc, p->data);
|
||||||
|
p->data = 0;
|
||||||
|
p->size = 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/* 7zBuf.h -- Byte Buffer
|
||||||
|
2023-03-04 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_7Z_BUF_H
|
||||||
|
#define ZIP7_INC_7Z_BUF_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Byte *data;
|
||||||
|
size_t size;
|
||||||
|
} CBuf;
|
||||||
|
|
||||||
|
void Buf_Init(CBuf *p);
|
||||||
|
int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc);
|
||||||
|
void Buf_Free(CBuf *p, ISzAllocPtr alloc);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Byte *data;
|
||||||
|
size_t size;
|
||||||
|
size_t pos;
|
||||||
|
} CDynBuf;
|
||||||
|
|
||||||
|
void DynBuf_Construct(CDynBuf *p);
|
||||||
|
void DynBuf_SeekToBeg(CDynBuf *p);
|
||||||
|
int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc);
|
||||||
|
void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,340 @@
|
|||||||
|
/* 7zCrc.c -- CRC32 calculation and init
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#include "Precomp.h"
|
||||||
|
|
||||||
|
#include "7zCrc.h"
|
||||||
|
#include "CpuArch.h"
|
||||||
|
|
||||||
|
#define kCrcPoly 0xEDB88320
|
||||||
|
|
||||||
|
#ifdef MY_CPU_LE
|
||||||
|
#define CRC_NUM_TABLES 8
|
||||||
|
#else
|
||||||
|
#define CRC_NUM_TABLES 9
|
||||||
|
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MY_CPU_BE
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
extern
|
||||||
|
CRC_FUNC g_CrcUpdateT4;
|
||||||
|
CRC_FUNC g_CrcUpdateT4;
|
||||||
|
*/
|
||||||
|
extern
|
||||||
|
CRC_FUNC g_CrcUpdateT8;
|
||||||
|
CRC_FUNC g_CrcUpdateT8;
|
||||||
|
extern
|
||||||
|
CRC_FUNC g_CrcUpdateT0_32;
|
||||||
|
CRC_FUNC g_CrcUpdateT0_32;
|
||||||
|
extern
|
||||||
|
CRC_FUNC g_CrcUpdateT0_64;
|
||||||
|
CRC_FUNC g_CrcUpdateT0_64;
|
||||||
|
extern
|
||||||
|
CRC_FUNC g_CrcUpdate;
|
||||||
|
CRC_FUNC g_CrcUpdate;
|
||||||
|
|
||||||
|
UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
|
||||||
|
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdate(UInt32 v, const void *data, size_t size)
|
||||||
|
{
|
||||||
|
return g_CrcUpdate(v, data, size, g_CrcTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size)
|
||||||
|
{
|
||||||
|
return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CRC_NUM_TABLES < 4 \
|
||||||
|
|| (CRC_NUM_TABLES == 4 && defined(MY_CPU_BE)) \
|
||||||
|
|| (!defined(MY_CPU_LE) && !defined(MY_CPU_BE))
|
||||||
|
#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||||
|
{
|
||||||
|
const Byte *p = (const Byte *)data;
|
||||||
|
const Byte *pEnd = p + size;
|
||||||
|
for (; p != pEnd; p++)
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ---------- hardware CRC ---------- */
|
||||||
|
|
||||||
|
#ifdef MY_CPU_LE
|
||||||
|
|
||||||
|
#if defined(MY_CPU_ARM_OR_ARM64)
|
||||||
|
|
||||||
|
// #pragma message("ARM*")
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#if defined(MY_CPU_ARM64)
|
||||||
|
#if (_MSC_VER >= 1910)
|
||||||
|
#ifndef __clang__
|
||||||
|
#define USE_ARM64_CRC
|
||||||
|
#include <intrin.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#elif (defined(__clang__) && (__clang_major__ >= 3)) \
|
||||||
|
|| (defined(__GNUC__) && (__GNUC__ > 4))
|
||||||
|
#if !defined(__ARM_FEATURE_CRC32)
|
||||||
|
#define __ARM_FEATURE_CRC32 1
|
||||||
|
#if defined(__clang__)
|
||||||
|
#if defined(MY_CPU_ARM64)
|
||||||
|
#define ATTRIB_CRC __attribute__((__target__("crc")))
|
||||||
|
#else
|
||||||
|
#define ATTRIB_CRC __attribute__((__target__("armv8-a,crc")))
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#if defined(MY_CPU_ARM64)
|
||||||
|
#define ATTRIB_CRC __attribute__((__target__("+crc")))
|
||||||
|
#else
|
||||||
|
#define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc")))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if defined(__ARM_FEATURE_CRC32)
|
||||||
|
#define USE_ARM64_CRC
|
||||||
|
#include <arm_acle.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// no hardware CRC
|
||||||
|
|
||||||
|
// #define USE_CRC_EMU
|
||||||
|
|
||||||
|
#ifdef USE_CRC_EMU
|
||||||
|
|
||||||
|
#pragma message("ARM64 CRC emulation")
|
||||||
|
|
||||||
|
Z7_FORCE_INLINE
|
||||||
|
UInt32 __crc32b(UInt32 v, UInt32 data)
|
||||||
|
{
|
||||||
|
const UInt32 *table = g_CrcTable;
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, (Byte)data);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
Z7_FORCE_INLINE
|
||||||
|
UInt32 __crc32w(UInt32 v, UInt32 data)
|
||||||
|
{
|
||||||
|
const UInt32 *table = g_CrcTable;
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
Z7_FORCE_INLINE
|
||||||
|
UInt32 __crc32d(UInt32 v, UInt64 data)
|
||||||
|
{
|
||||||
|
const UInt32 *table = g_CrcTable;
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // USE_CRC_EMU
|
||||||
|
|
||||||
|
#endif // defined(MY_CPU_ARM64) && defined(MY_CPU_LE)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(USE_ARM64_CRC) || defined(USE_CRC_EMU)
|
||||||
|
|
||||||
|
#define T0_32_UNROLL_BYTES (4 * 4)
|
||||||
|
#define T0_64_UNROLL_BYTES (4 * 8)
|
||||||
|
|
||||||
|
#ifndef ATTRIB_CRC
|
||||||
|
#define ATTRIB_CRC
|
||||||
|
#endif
|
||||||
|
// #pragma message("USE ARM HW CRC")
|
||||||
|
|
||||||
|
ATTRIB_CRC
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdateT0_32(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||||
|
ATTRIB_CRC
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdateT0_32(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||||
|
{
|
||||||
|
const Byte *p = (const Byte *)data;
|
||||||
|
UNUSED_VAR(table);
|
||||||
|
|
||||||
|
for (; size != 0 && ((unsigned)(ptrdiff_t)p & (T0_32_UNROLL_BYTES - 1)) != 0; size--)
|
||||||
|
v = __crc32b(v, *p++);
|
||||||
|
|
||||||
|
if (size >= T0_32_UNROLL_BYTES)
|
||||||
|
{
|
||||||
|
const Byte *lim = p + size;
|
||||||
|
size &= (T0_32_UNROLL_BYTES - 1);
|
||||||
|
lim -= size;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
v = __crc32w(v, *(const UInt32 *)(const void *)(p));
|
||||||
|
v = __crc32w(v, *(const UInt32 *)(const void *)(p + 4)); p += 2 * 4;
|
||||||
|
v = __crc32w(v, *(const UInt32 *)(const void *)(p));
|
||||||
|
v = __crc32w(v, *(const UInt32 *)(const void *)(p + 4)); p += 2 * 4;
|
||||||
|
}
|
||||||
|
while (p != lim);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; size != 0; size--)
|
||||||
|
v = __crc32b(v, *p++);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
ATTRIB_CRC
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdateT0_64(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||||
|
ATTRIB_CRC
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdateT0_64(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||||
|
{
|
||||||
|
const Byte *p = (const Byte *)data;
|
||||||
|
UNUSED_VAR(table);
|
||||||
|
|
||||||
|
for (; size != 0 && ((unsigned)(ptrdiff_t)p & (T0_64_UNROLL_BYTES - 1)) != 0; size--)
|
||||||
|
v = __crc32b(v, *p++);
|
||||||
|
|
||||||
|
if (size >= T0_64_UNROLL_BYTES)
|
||||||
|
{
|
||||||
|
const Byte *lim = p + size;
|
||||||
|
size &= (T0_64_UNROLL_BYTES - 1);
|
||||||
|
lim -= size;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
v = __crc32d(v, *(const UInt64 *)(const void *)(p));
|
||||||
|
v = __crc32d(v, *(const UInt64 *)(const void *)(p + 8)); p += 2 * 8;
|
||||||
|
v = __crc32d(v, *(const UInt64 *)(const void *)(p));
|
||||||
|
v = __crc32d(v, *(const UInt64 *)(const void *)(p + 8)); p += 2 * 8;
|
||||||
|
}
|
||||||
|
while (p != lim);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; size != 0; size--)
|
||||||
|
v = __crc32b(v, *p++);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef T0_32_UNROLL_BYTES
|
||||||
|
#undef T0_64_UNROLL_BYTES
|
||||||
|
|
||||||
|
#endif // defined(USE_ARM64_CRC) || defined(USE_CRC_EMU)
|
||||||
|
|
||||||
|
#endif // MY_CPU_LE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Z7_FASTCALL CrcGenerateTable(void)
|
||||||
|
{
|
||||||
|
UInt32 i;
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
UInt32 r = i;
|
||||||
|
unsigned j;
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1)));
|
||||||
|
g_CrcTable[i] = r;
|
||||||
|
}
|
||||||
|
for (i = 256; i < 256 * CRC_NUM_TABLES; i++)
|
||||||
|
{
|
||||||
|
const UInt32 r = g_CrcTable[(size_t)i - 256];
|
||||||
|
g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CRC_NUM_TABLES < 4
|
||||||
|
g_CrcUpdate = CrcUpdateT1;
|
||||||
|
#elif defined(MY_CPU_LE)
|
||||||
|
// g_CrcUpdateT4 = CrcUpdateT4;
|
||||||
|
#if CRC_NUM_TABLES < 8
|
||||||
|
g_CrcUpdate = CrcUpdateT4;
|
||||||
|
#else // CRC_NUM_TABLES >= 8
|
||||||
|
g_CrcUpdateT8 = CrcUpdateT8;
|
||||||
|
/*
|
||||||
|
#ifdef MY_CPU_X86_OR_AMD64
|
||||||
|
if (!CPU_Is_InOrder())
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
g_CrcUpdate = CrcUpdateT8;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
#ifndef MY_CPU_BE
|
||||||
|
UInt32 k = 0x01020304;
|
||||||
|
const Byte *p = (const Byte *)&k;
|
||||||
|
if (p[0] == 4 && p[1] == 3)
|
||||||
|
{
|
||||||
|
#if CRC_NUM_TABLES < 8
|
||||||
|
// g_CrcUpdateT4 = CrcUpdateT4;
|
||||||
|
g_CrcUpdate = CrcUpdateT4;
|
||||||
|
#else // CRC_NUM_TABLES >= 8
|
||||||
|
g_CrcUpdateT8 = CrcUpdateT8;
|
||||||
|
g_CrcUpdate = CrcUpdateT8;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (p[0] != 1 || p[1] != 2)
|
||||||
|
g_CrcUpdate = CrcUpdateT1;
|
||||||
|
else
|
||||||
|
#endif // MY_CPU_BE
|
||||||
|
{
|
||||||
|
for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--)
|
||||||
|
{
|
||||||
|
const UInt32 x = g_CrcTable[(size_t)i - 256];
|
||||||
|
g_CrcTable[i] = Z7_BSWAP32(x);
|
||||||
|
}
|
||||||
|
#if CRC_NUM_TABLES <= 4
|
||||||
|
g_CrcUpdate = CrcUpdateT1;
|
||||||
|
#elif CRC_NUM_TABLES <= 8
|
||||||
|
// g_CrcUpdateT4 = CrcUpdateT1_BeT4;
|
||||||
|
g_CrcUpdate = CrcUpdateT1_BeT4;
|
||||||
|
#else // CRC_NUM_TABLES > 8
|
||||||
|
g_CrcUpdateT8 = CrcUpdateT1_BeT8;
|
||||||
|
g_CrcUpdate = CrcUpdateT1_BeT8;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // CRC_NUM_TABLES < 4
|
||||||
|
|
||||||
|
#ifdef MY_CPU_LE
|
||||||
|
#ifdef USE_ARM64_CRC
|
||||||
|
if (CPU_IsSupported_CRC32())
|
||||||
|
{
|
||||||
|
g_CrcUpdateT0_32 = CrcUpdateT0_32;
|
||||||
|
g_CrcUpdateT0_64 = CrcUpdateT0_64;
|
||||||
|
g_CrcUpdate =
|
||||||
|
#if defined(MY_CPU_ARM)
|
||||||
|
CrcUpdateT0_32;
|
||||||
|
#else
|
||||||
|
CrcUpdateT0_64;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_CRC_EMU
|
||||||
|
g_CrcUpdateT0_32 = CrcUpdateT0_32;
|
||||||
|
g_CrcUpdateT0_64 = CrcUpdateT0_64;
|
||||||
|
g_CrcUpdate = CrcUpdateT0_64;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef kCrcPoly
|
||||||
|
#undef CRC64_NUM_TABLES
|
||||||
|
#undef CRC_UPDATE_BYTE_2
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/* 7zCrc.h -- CRC32 calculation
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_7Z_CRC_H
|
||||||
|
#define ZIP7_INC_7Z_CRC_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
extern UInt32 g_CrcTable[];
|
||||||
|
|
||||||
|
/* Call CrcGenerateTable one time before other CRC functions */
|
||||||
|
void Z7_FASTCALL CrcGenerateTable(void);
|
||||||
|
|
||||||
|
#define CRC_INIT_VAL 0xFFFFFFFF
|
||||||
|
#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL)
|
||||||
|
#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||||
|
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdate(UInt32 crc, const void *data, size_t size);
|
||||||
|
UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size);
|
||||||
|
|
||||||
|
typedef UInt32 (Z7_FASTCALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/* 7zCrcOpt.c -- CRC32 calculation
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#include "Precomp.h"
|
||||||
|
|
||||||
|
#include "CpuArch.h"
|
||||||
|
|
||||||
|
#ifndef MY_CPU_BE
|
||||||
|
|
||||||
|
#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||||
|
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||||
|
{
|
||||||
|
const Byte *p = (const Byte *)data;
|
||||||
|
for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||||
|
for (; size >= 4; size -= 4, p += 4)
|
||||||
|
{
|
||||||
|
v ^= *(const UInt32 *)(const void *)p;
|
||||||
|
v =
|
||||||
|
(table + 0x300)[((v ) & 0xFF)]
|
||||||
|
^ (table + 0x200)[((v >> 8) & 0xFF)]
|
||||||
|
^ (table + 0x100)[((v >> 16) & 0xFF)]
|
||||||
|
^ (table + 0x000)[((v >> 24))];
|
||||||
|
}
|
||||||
|
for (; size > 0; size--, p++)
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||||
|
{
|
||||||
|
const Byte *p = (const Byte *)data;
|
||||||
|
for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++)
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||||
|
for (; size >= 8; size -= 8, p += 8)
|
||||||
|
{
|
||||||
|
UInt32 d;
|
||||||
|
v ^= *(const UInt32 *)(const void *)p;
|
||||||
|
v =
|
||||||
|
(table + 0x700)[((v ) & 0xFF)]
|
||||||
|
^ (table + 0x600)[((v >> 8) & 0xFF)]
|
||||||
|
^ (table + 0x500)[((v >> 16) & 0xFF)]
|
||||||
|
^ (table + 0x400)[((v >> 24))];
|
||||||
|
d = *((const UInt32 *)(const void *)p + 1);
|
||||||
|
v ^=
|
||||||
|
(table + 0x300)[((d ) & 0xFF)]
|
||||||
|
^ (table + 0x200)[((d >> 8) & 0xFF)]
|
||||||
|
^ (table + 0x100)[((d >> 16) & 0xFF)]
|
||||||
|
^ (table + 0x000)[((d >> 24))];
|
||||||
|
}
|
||||||
|
for (; size > 0; size--, p++)
|
||||||
|
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MY_CPU_LE
|
||||||
|
|
||||||
|
#define CRC_UINT32_SWAP(v) Z7_BSWAP32(v)
|
||||||
|
|
||||||
|
#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[(((crc) >> 24) ^ (b))] ^ ((crc) << 8))
|
||||||
|
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||||
|
{
|
||||||
|
const Byte *p = (const Byte *)data;
|
||||||
|
table += 0x100;
|
||||||
|
v = CRC_UINT32_SWAP(v);
|
||||||
|
for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
|
||||||
|
v = CRC_UPDATE_BYTE_2_BE(v, *p);
|
||||||
|
for (; size >= 4; size -= 4, p += 4)
|
||||||
|
{
|
||||||
|
v ^= *(const UInt32 *)(const void *)p;
|
||||||
|
v =
|
||||||
|
(table + 0x000)[((v ) & 0xFF)]
|
||||||
|
^ (table + 0x100)[((v >> 8) & 0xFF)]
|
||||||
|
^ (table + 0x200)[((v >> 16) & 0xFF)]
|
||||||
|
^ (table + 0x300)[((v >> 24))];
|
||||||
|
}
|
||||||
|
for (; size > 0; size--, p++)
|
||||||
|
v = CRC_UPDATE_BYTE_2_BE(v, *p);
|
||||||
|
return CRC_UINT32_SWAP(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt32 Z7_FASTCALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||||
|
{
|
||||||
|
const Byte *p = (const Byte *)data;
|
||||||
|
table += 0x100;
|
||||||
|
v = CRC_UINT32_SWAP(v);
|
||||||
|
for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++)
|
||||||
|
v = CRC_UPDATE_BYTE_2_BE(v, *p);
|
||||||
|
for (; size >= 8; size -= 8, p += 8)
|
||||||
|
{
|
||||||
|
UInt32 d;
|
||||||
|
v ^= *(const UInt32 *)(const void *)p;
|
||||||
|
v =
|
||||||
|
(table + 0x400)[((v ) & 0xFF)]
|
||||||
|
^ (table + 0x500)[((v >> 8) & 0xFF)]
|
||||||
|
^ (table + 0x600)[((v >> 16) & 0xFF)]
|
||||||
|
^ (table + 0x700)[((v >> 24))];
|
||||||
|
d = *((const UInt32 *)(const void *)p + 1);
|
||||||
|
v ^=
|
||||||
|
(table + 0x000)[((d ) & 0xFF)]
|
||||||
|
^ (table + 0x100)[((d >> 8) & 0xFF)]
|
||||||
|
^ (table + 0x200)[((d >> 16) & 0xFF)]
|
||||||
|
^ (table + 0x300)[((d >> 24))];
|
||||||
|
}
|
||||||
|
for (; size > 0; size--, p++)
|
||||||
|
v = CRC_UPDATE_BYTE_2_BE(v, *p);
|
||||||
|
return CRC_UINT32_SWAP(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,648 @@
|
|||||||
|
/* 7zDec.c -- Decoding from 7z folder
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#include "Precomp.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* #define Z7_PPMD_SUPPORT */
|
||||||
|
|
||||||
|
#include "7z.h"
|
||||||
|
#include "7zCrc.h"
|
||||||
|
|
||||||
|
#include "Bcj2.h"
|
||||||
|
#include "Bra.h"
|
||||||
|
#include "CpuArch.h"
|
||||||
|
#include "Delta.h"
|
||||||
|
#include "LzmaDec.h"
|
||||||
|
#include "Lzma2Dec.h"
|
||||||
|
#ifdef Z7_PPMD_SUPPORT
|
||||||
|
#include "Ppmd7.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define k_Copy 0
|
||||||
|
#ifndef Z7_NO_METHOD_LZMA2
|
||||||
|
#define k_LZMA2 0x21
|
||||||
|
#endif
|
||||||
|
#define k_LZMA 0x30101
|
||||||
|
#define k_BCJ2 0x303011B
|
||||||
|
|
||||||
|
#if !defined(Z7_NO_METHODS_FILTERS)
|
||||||
|
#define Z7_USE_BRANCH_FILTER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(Z7_NO_METHODS_FILTERS) || \
|
||||||
|
defined(Z7_USE_NATIVE_BRANCH_FILTER) && defined(MY_CPU_ARM64)
|
||||||
|
#define Z7_USE_FILTER_ARM64
|
||||||
|
#ifndef Z7_USE_BRANCH_FILTER
|
||||||
|
#define Z7_USE_BRANCH_FILTER
|
||||||
|
#endif
|
||||||
|
#define k_ARM64 0xa
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(Z7_NO_METHODS_FILTERS) || \
|
||||||
|
defined(Z7_USE_NATIVE_BRANCH_FILTER) && defined(MY_CPU_ARMT)
|
||||||
|
#define Z7_USE_FILTER_ARMT
|
||||||
|
#ifndef Z7_USE_BRANCH_FILTER
|
||||||
|
#define Z7_USE_BRANCH_FILTER
|
||||||
|
#endif
|
||||||
|
#define k_ARMT 0x3030701
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef Z7_NO_METHODS_FILTERS
|
||||||
|
#define k_Delta 3
|
||||||
|
#define k_BCJ 0x3030103
|
||||||
|
#define k_PPC 0x3030205
|
||||||
|
#define k_IA64 0x3030401
|
||||||
|
#define k_ARM 0x3030501
|
||||||
|
#define k_SPARC 0x3030805
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Z7_PPMD_SUPPORT
|
||||||
|
|
||||||
|
#define k_PPMD 0x30401
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
IByteIn vt;
|
||||||
|
const Byte *cur;
|
||||||
|
const Byte *end;
|
||||||
|
const Byte *begin;
|
||||||
|
UInt64 processed;
|
||||||
|
BoolInt extra;
|
||||||
|
SRes res;
|
||||||
|
ILookInStreamPtr inStream;
|
||||||
|
} CByteInToLook;
|
||||||
|
|
||||||
|
static Byte ReadByte(IByteInPtr pp)
|
||||||
|
{
|
||||||
|
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CByteInToLook)
|
||||||
|
if (p->cur != p->end)
|
||||||
|
return *p->cur++;
|
||||||
|
if (p->res == SZ_OK)
|
||||||
|
{
|
||||||
|
size_t size = (size_t)(p->cur - p->begin);
|
||||||
|
p->processed += size;
|
||||||
|
p->res = ILookInStream_Skip(p->inStream, size);
|
||||||
|
size = (1 << 25);
|
||||||
|
p->res = ILookInStream_Look(p->inStream, (const void **)&p->begin, &size);
|
||||||
|
p->cur = p->begin;
|
||||||
|
p->end = p->begin + size;
|
||||||
|
if (size != 0)
|
||||||
|
return *p->cur++;
|
||||||
|
}
|
||||||
|
p->extra = True;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
|
||||||
|
Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
|
||||||
|
{
|
||||||
|
CPpmd7 ppmd;
|
||||||
|
CByteInToLook s;
|
||||||
|
SRes res = SZ_OK;
|
||||||
|
|
||||||
|
s.vt.Read = ReadByte;
|
||||||
|
s.inStream = inStream;
|
||||||
|
s.begin = s.end = s.cur = NULL;
|
||||||
|
s.extra = False;
|
||||||
|
s.res = SZ_OK;
|
||||||
|
s.processed = 0;
|
||||||
|
|
||||||
|
if (propsSize != 5)
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
|
||||||
|
{
|
||||||
|
unsigned order = props[0];
|
||||||
|
UInt32 memSize = GetUi32(props + 1);
|
||||||
|
if (order < PPMD7_MIN_ORDER ||
|
||||||
|
order > PPMD7_MAX_ORDER ||
|
||||||
|
memSize < PPMD7_MIN_MEM_SIZE ||
|
||||||
|
memSize > PPMD7_MAX_MEM_SIZE)
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
Ppmd7_Construct(&ppmd);
|
||||||
|
if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
|
||||||
|
return SZ_ERROR_MEM;
|
||||||
|
Ppmd7_Init(&ppmd, order);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ppmd.rc.dec.Stream = &s.vt;
|
||||||
|
if (!Ppmd7z_RangeDec_Init(&ppmd.rc.dec))
|
||||||
|
res = SZ_ERROR_DATA;
|
||||||
|
else if (!s.extra)
|
||||||
|
{
|
||||||
|
Byte *buf = outBuffer;
|
||||||
|
const Byte *lim = buf + outSize;
|
||||||
|
for (; buf != lim; buf++)
|
||||||
|
{
|
||||||
|
int sym = Ppmd7z_DecodeSymbol(&ppmd);
|
||||||
|
if (s.extra || sym < 0)
|
||||||
|
break;
|
||||||
|
*buf = (Byte)sym;
|
||||||
|
}
|
||||||
|
if (buf != lim)
|
||||||
|
res = SZ_ERROR_DATA;
|
||||||
|
else if (!Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec))
|
||||||
|
{
|
||||||
|
/* if (Ppmd7z_DecodeSymbol(&ppmd) != PPMD7_SYM_END || !Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) */
|
||||||
|
res = SZ_ERROR_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (s.extra)
|
||||||
|
res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
|
||||||
|
else if (s.processed + (size_t)(s.cur - s.begin) != inSize)
|
||||||
|
res = SZ_ERROR_DATA;
|
||||||
|
}
|
||||||
|
Ppmd7_Free(&ppmd, allocMain);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
|
||||||
|
Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
|
||||||
|
{
|
||||||
|
CLzmaDec state;
|
||||||
|
SRes res = SZ_OK;
|
||||||
|
|
||||||
|
LzmaDec_CONSTRUCT(&state)
|
||||||
|
RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain))
|
||||||
|
state.dic = outBuffer;
|
||||||
|
state.dicBufSize = outSize;
|
||||||
|
LzmaDec_Init(&state);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const void *inBuf = NULL;
|
||||||
|
size_t lookahead = (1 << 18);
|
||||||
|
if (lookahead > inSize)
|
||||||
|
lookahead = (size_t)inSize;
|
||||||
|
res = ILookInStream_Look(inStream, &inBuf, &lookahead);
|
||||||
|
if (res != SZ_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
{
|
||||||
|
SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
|
||||||
|
ELzmaStatus status;
|
||||||
|
res = LzmaDec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
|
||||||
|
lookahead -= inProcessed;
|
||||||
|
inSize -= inProcessed;
|
||||||
|
if (res != SZ_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (status == LZMA_STATUS_FINISHED_WITH_MARK)
|
||||||
|
{
|
||||||
|
if (outSize != state.dicPos || inSize != 0)
|
||||||
|
res = SZ_ERROR_DATA;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (inProcessed == 0 && dicPos == state.dicPos)
|
||||||
|
{
|
||||||
|
res = SZ_ERROR_DATA;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = ILookInStream_Skip(inStream, inProcessed);
|
||||||
|
if (res != SZ_OK)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LzmaDec_FreeProbs(&state, allocMain);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef Z7_NO_METHOD_LZMA2
|
||||||
|
|
||||||
|
static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
|
||||||
|
Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
|
||||||
|
{
|
||||||
|
CLzma2Dec state;
|
||||||
|
SRes res = SZ_OK;
|
||||||
|
|
||||||
|
Lzma2Dec_CONSTRUCT(&state)
|
||||||
|
if (propsSize != 1)
|
||||||
|
return SZ_ERROR_DATA;
|
||||||
|
RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain))
|
||||||
|
state.decoder.dic = outBuffer;
|
||||||
|
state.decoder.dicBufSize = outSize;
|
||||||
|
Lzma2Dec_Init(&state);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const void *inBuf = NULL;
|
||||||
|
size_t lookahead = (1 << 18);
|
||||||
|
if (lookahead > inSize)
|
||||||
|
lookahead = (size_t)inSize;
|
||||||
|
res = ILookInStream_Look(inStream, &inBuf, &lookahead);
|
||||||
|
if (res != SZ_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
{
|
||||||
|
SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
|
||||||
|
ELzmaStatus status;
|
||||||
|
res = Lzma2Dec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
|
||||||
|
lookahead -= inProcessed;
|
||||||
|
inSize -= inProcessed;
|
||||||
|
if (res != SZ_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (status == LZMA_STATUS_FINISHED_WITH_MARK)
|
||||||
|
{
|
||||||
|
if (outSize != state.decoder.dicPos || inSize != 0)
|
||||||
|
res = SZ_ERROR_DATA;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inProcessed == 0 && dicPos == state.decoder.dicPos)
|
||||||
|
{
|
||||||
|
res = SZ_ERROR_DATA;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = ILookInStream_Skip(inStream, inProcessed);
|
||||||
|
if (res != SZ_OK)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Lzma2Dec_FreeProbs(&state, allocMain);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static SRes SzDecodeCopy(UInt64 inSize, ILookInStreamPtr inStream, Byte *outBuffer)
|
||||||
|
{
|
||||||
|
while (inSize > 0)
|
||||||
|
{
|
||||||
|
const void *inBuf;
|
||||||
|
size_t curSize = (1 << 18);
|
||||||
|
if (curSize > inSize)
|
||||||
|
curSize = (size_t)inSize;
|
||||||
|
RINOK(ILookInStream_Look(inStream, &inBuf, &curSize))
|
||||||
|
if (curSize == 0)
|
||||||
|
return SZ_ERROR_INPUT_EOF;
|
||||||
|
memcpy(outBuffer, inBuf, curSize);
|
||||||
|
outBuffer += curSize;
|
||||||
|
inSize -= curSize;
|
||||||
|
RINOK(ILookInStream_Skip(inStream, curSize))
|
||||||
|
}
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BoolInt IS_MAIN_METHOD(UInt32 m)
|
||||||
|
{
|
||||||
|
switch (m)
|
||||||
|
{
|
||||||
|
case k_Copy:
|
||||||
|
case k_LZMA:
|
||||||
|
#ifndef Z7_NO_METHOD_LZMA2
|
||||||
|
case k_LZMA2:
|
||||||
|
#endif
|
||||||
|
#ifdef Z7_PPMD_SUPPORT
|
||||||
|
case k_PPMD:
|
||||||
|
#endif
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BoolInt IS_SUPPORTED_CODER(const CSzCoderInfo *c)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
c->NumStreams == 1
|
||||||
|
/* && c->MethodID <= (UInt32)0xFFFFFFFF */
|
||||||
|
&& IS_MAIN_METHOD((UInt32)c->MethodID);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4)
|
||||||
|
|
||||||
|
static SRes CheckSupportedFolder(const CSzFolder *f)
|
||||||
|
{
|
||||||
|
if (f->NumCoders < 1 || f->NumCoders > 4)
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
if (!IS_SUPPORTED_CODER(&f->Coders[0]))
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
if (f->NumCoders == 1)
|
||||||
|
{
|
||||||
|
if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0)
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(Z7_USE_BRANCH_FILTER)
|
||||||
|
|
||||||
|
if (f->NumCoders == 2)
|
||||||
|
{
|
||||||
|
const CSzCoderInfo *c = &f->Coders[1];
|
||||||
|
if (
|
||||||
|
/* c->MethodID > (UInt32)0xFFFFFFFF || */
|
||||||
|
c->NumStreams != 1
|
||||||
|
|| f->NumPackStreams != 1
|
||||||
|
|| f->PackStreams[0] != 0
|
||||||
|
|| f->NumBonds != 1
|
||||||
|
|| f->Bonds[0].InIndex != 1
|
||||||
|
|| f->Bonds[0].OutIndex != 0)
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
switch ((UInt32)c->MethodID)
|
||||||
|
{
|
||||||
|
#if !defined(Z7_NO_METHODS_FILTERS)
|
||||||
|
case k_Delta:
|
||||||
|
case k_BCJ:
|
||||||
|
case k_PPC:
|
||||||
|
case k_IA64:
|
||||||
|
case k_SPARC:
|
||||||
|
case k_ARM:
|
||||||
|
#endif
|
||||||
|
#ifdef Z7_USE_FILTER_ARM64
|
||||||
|
case k_ARM64:
|
||||||
|
#endif
|
||||||
|
#ifdef Z7_USE_FILTER_ARMT
|
||||||
|
case k_ARMT:
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
if (f->NumCoders == 4)
|
||||||
|
{
|
||||||
|
if (!IS_SUPPORTED_CODER(&f->Coders[1])
|
||||||
|
|| !IS_SUPPORTED_CODER(&f->Coders[2])
|
||||||
|
|| !IS_BCJ2(&f->Coders[3]))
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
if (f->NumPackStreams != 4
|
||||||
|
|| f->PackStreams[0] != 2
|
||||||
|
|| f->PackStreams[1] != 6
|
||||||
|
|| f->PackStreams[2] != 1
|
||||||
|
|| f->PackStreams[3] != 0
|
||||||
|
|| f->NumBonds != 3
|
||||||
|
|| f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0
|
||||||
|
|| f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1
|
||||||
|
|| f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2)
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static SRes SzFolder_Decode2(const CSzFolder *folder,
|
||||||
|
const Byte *propsData,
|
||||||
|
const UInt64 *unpackSizes,
|
||||||
|
const UInt64 *packPositions,
|
||||||
|
ILookInStreamPtr inStream, UInt64 startPos,
|
||||||
|
Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain,
|
||||||
|
Byte *tempBuf[])
|
||||||
|
{
|
||||||
|
UInt32 ci;
|
||||||
|
SizeT tempSizes[3] = { 0, 0, 0};
|
||||||
|
SizeT tempSize3 = 0;
|
||||||
|
Byte *tempBuf3 = 0;
|
||||||
|
|
||||||
|
RINOK(CheckSupportedFolder(folder))
|
||||||
|
|
||||||
|
for (ci = 0; ci < folder->NumCoders; ci++)
|
||||||
|
{
|
||||||
|
const CSzCoderInfo *coder = &folder->Coders[ci];
|
||||||
|
|
||||||
|
if (IS_MAIN_METHOD((UInt32)coder->MethodID))
|
||||||
|
{
|
||||||
|
UInt32 si = 0;
|
||||||
|
UInt64 offset;
|
||||||
|
UInt64 inSize;
|
||||||
|
Byte *outBufCur = outBuffer;
|
||||||
|
SizeT outSizeCur = outSize;
|
||||||
|
if (folder->NumCoders == 4)
|
||||||
|
{
|
||||||
|
const UInt32 indices[] = { 3, 2, 0 };
|
||||||
|
const UInt64 unpackSize = unpackSizes[ci];
|
||||||
|
si = indices[ci];
|
||||||
|
if (ci < 2)
|
||||||
|
{
|
||||||
|
Byte *temp;
|
||||||
|
outSizeCur = (SizeT)unpackSize;
|
||||||
|
if (outSizeCur != unpackSize)
|
||||||
|
return SZ_ERROR_MEM;
|
||||||
|
temp = (Byte *)ISzAlloc_Alloc(allocMain, outSizeCur);
|
||||||
|
if (!temp && outSizeCur != 0)
|
||||||
|
return SZ_ERROR_MEM;
|
||||||
|
outBufCur = tempBuf[1 - ci] = temp;
|
||||||
|
tempSizes[1 - ci] = outSizeCur;
|
||||||
|
}
|
||||||
|
else if (ci == 2)
|
||||||
|
{
|
||||||
|
if (unpackSize > outSize) /* check it */
|
||||||
|
return SZ_ERROR_PARAM;
|
||||||
|
tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
|
||||||
|
tempSize3 = outSizeCur = (SizeT)unpackSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
offset = packPositions[si];
|
||||||
|
inSize = packPositions[(size_t)si + 1] - offset;
|
||||||
|
RINOK(LookInStream_SeekTo(inStream, startPos + offset))
|
||||||
|
|
||||||
|
if (coder->MethodID == k_Copy)
|
||||||
|
{
|
||||||
|
if (inSize != outSizeCur) /* check it */
|
||||||
|
return SZ_ERROR_DATA;
|
||||||
|
RINOK(SzDecodeCopy(inSize, inStream, outBufCur))
|
||||||
|
}
|
||||||
|
else if (coder->MethodID == k_LZMA)
|
||||||
|
{
|
||||||
|
RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain))
|
||||||
|
}
|
||||||
|
#ifndef Z7_NO_METHOD_LZMA2
|
||||||
|
else if (coder->MethodID == k_LZMA2)
|
||||||
|
{
|
||||||
|
RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain))
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef Z7_PPMD_SUPPORT
|
||||||
|
else if (coder->MethodID == k_PPMD)
|
||||||
|
{
|
||||||
|
RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain))
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
else if (coder->MethodID == k_BCJ2)
|
||||||
|
{
|
||||||
|
const UInt64 offset = packPositions[1];
|
||||||
|
const UInt64 s3Size = packPositions[2] - offset;
|
||||||
|
|
||||||
|
if (ci != 3)
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
|
||||||
|
tempSizes[2] = (SizeT)s3Size;
|
||||||
|
if (tempSizes[2] != s3Size)
|
||||||
|
return SZ_ERROR_MEM;
|
||||||
|
tempBuf[2] = (Byte *)ISzAlloc_Alloc(allocMain, tempSizes[2]);
|
||||||
|
if (!tempBuf[2] && tempSizes[2] != 0)
|
||||||
|
return SZ_ERROR_MEM;
|
||||||
|
|
||||||
|
RINOK(LookInStream_SeekTo(inStream, startPos + offset))
|
||||||
|
RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2]))
|
||||||
|
|
||||||
|
if ((tempSizes[0] & 3) != 0 ||
|
||||||
|
(tempSizes[1] & 3) != 0 ||
|
||||||
|
tempSize3 + tempSizes[0] + tempSizes[1] != outSize)
|
||||||
|
return SZ_ERROR_DATA;
|
||||||
|
|
||||||
|
{
|
||||||
|
CBcj2Dec p;
|
||||||
|
|
||||||
|
p.bufs[0] = tempBuf3; p.lims[0] = tempBuf3 + tempSize3;
|
||||||
|
p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0];
|
||||||
|
p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1];
|
||||||
|
p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2];
|
||||||
|
|
||||||
|
p.dest = outBuffer;
|
||||||
|
p.destLim = outBuffer + outSize;
|
||||||
|
|
||||||
|
Bcj2Dec_Init(&p);
|
||||||
|
RINOK(Bcj2Dec_Decode(&p))
|
||||||
|
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
if (p.bufs[i] != p.lims[i])
|
||||||
|
return SZ_ERROR_DATA;
|
||||||
|
if (p.dest != p.destLim || !Bcj2Dec_IsMaybeFinished(&p))
|
||||||
|
return SZ_ERROR_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if defined(Z7_USE_BRANCH_FILTER)
|
||||||
|
else if (ci == 1)
|
||||||
|
{
|
||||||
|
#if !defined(Z7_NO_METHODS_FILTERS)
|
||||||
|
if (coder->MethodID == k_Delta)
|
||||||
|
{
|
||||||
|
if (coder->PropsSize != 1)
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
{
|
||||||
|
Byte state[DELTA_STATE_SIZE];
|
||||||
|
Delta_Init(state);
|
||||||
|
Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Z7_USE_FILTER_ARM64
|
||||||
|
if (coder->MethodID == k_ARM64)
|
||||||
|
{
|
||||||
|
UInt32 pc = 0;
|
||||||
|
if (coder->PropsSize == 4)
|
||||||
|
pc = GetUi32(propsData + coder->PropsOffset);
|
||||||
|
else if (coder->PropsSize != 0)
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
z7_BranchConv_ARM64_Dec(outBuffer, outSize, pc);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(Z7_NO_METHODS_FILTERS) || defined(Z7_USE_FILTER_ARMT)
|
||||||
|
{
|
||||||
|
if (coder->PropsSize != 0)
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
#define CASE_BRA_CONV(isa) case k_ ## isa: Z7_BRANCH_CONV_DEC(isa)(outBuffer, outSize, 0); break; // pc = 0;
|
||||||
|
switch (coder->MethodID)
|
||||||
|
{
|
||||||
|
#if !defined(Z7_NO_METHODS_FILTERS)
|
||||||
|
case k_BCJ:
|
||||||
|
{
|
||||||
|
UInt32 state = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL;
|
||||||
|
z7_BranchConvSt_X86_Dec(outBuffer, outSize, 0, &state); // pc = 0
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CASE_BRA_CONV(PPC)
|
||||||
|
CASE_BRA_CONV(IA64)
|
||||||
|
CASE_BRA_CONV(SPARC)
|
||||||
|
CASE_BRA_CONV(ARM)
|
||||||
|
#endif
|
||||||
|
#if !defined(Z7_NO_METHODS_FILTERS) || defined(Z7_USE_FILTER_ARMT)
|
||||||
|
CASE_BRA_CONV(ARMT)
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // (c == 1)
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
|
||||||
|
ILookInStreamPtr inStream, UInt64 startPos,
|
||||||
|
Byte *outBuffer, size_t outSize,
|
||||||
|
ISzAllocPtr allocMain)
|
||||||
|
{
|
||||||
|
SRes res;
|
||||||
|
CSzFolder folder;
|
||||||
|
CSzData sd;
|
||||||
|
|
||||||
|
const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex];
|
||||||
|
sd.Data = data;
|
||||||
|
sd.Size = p->FoCodersOffsets[(size_t)folderIndex + 1] - p->FoCodersOffsets[folderIndex];
|
||||||
|
|
||||||
|
res = SzGetNextFolderItem(&folder, &sd);
|
||||||
|
|
||||||
|
if (res != SZ_OK)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
if (sd.Size != 0
|
||||||
|
|| folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex]
|
||||||
|
|| outSize != SzAr_GetFolderUnpackSize(p, folderIndex))
|
||||||
|
return SZ_ERROR_FAIL;
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
Byte *tempBuf[3] = { 0, 0, 0};
|
||||||
|
|
||||||
|
res = SzFolder_Decode2(&folder, data,
|
||||||
|
&p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]],
|
||||||
|
p->PackPositions + p->FoStartPackStreamIndex[folderIndex],
|
||||||
|
inStream, startPos,
|
||||||
|
outBuffer, (SizeT)outSize, allocMain, tempBuf);
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
ISzAlloc_Free(allocMain, tempBuf[i]);
|
||||||
|
|
||||||
|
if (res == SZ_OK)
|
||||||
|
if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex))
|
||||||
|
if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex])
|
||||||
|
res = SZ_ERROR_CRC;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,443 @@
|
|||||||
|
/* 7zFile.c -- File IO
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#include "Precomp.h"
|
||||||
|
|
||||||
|
#include "7zFile.h"
|
||||||
|
|
||||||
|
#ifndef USE_WINDOWS_FILE
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#ifndef USE_FOPEN
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <io.h>
|
||||||
|
typedef int ssize_t;
|
||||||
|
typedef int off_t;
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/*
|
||||||
|
ReadFile and WriteFile functions in Windows have BUG:
|
||||||
|
If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
|
||||||
|
from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
|
||||||
|
(Insufficient system resources exist to complete the requested service).
|
||||||
|
Probably in some version of Windows there are problems with other sizes:
|
||||||
|
for 32 MB (maybe also for 16 MB).
|
||||||
|
And message can be "Network connection was lost"
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define kChunkSizeMax (1 << 22)
|
||||||
|
|
||||||
|
void File_Construct(CSzFile *p)
|
||||||
|
{
|
||||||
|
#ifdef USE_WINDOWS_FILE
|
||||||
|
p->handle = INVALID_HANDLE_VALUE;
|
||||||
|
#elif defined(USE_FOPEN)
|
||||||
|
p->file = NULL;
|
||||||
|
#else
|
||||||
|
p->fd = -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
|
||||||
|
|
||||||
|
static WRes File_Open(CSzFile *p, const char *name, int writeMode)
|
||||||
|
{
|
||||||
|
#ifdef USE_WINDOWS_FILE
|
||||||
|
|
||||||
|
p->handle = CreateFileA(name,
|
||||||
|
writeMode ? GENERIC_WRITE : GENERIC_READ,
|
||||||
|
FILE_SHARE_READ, NULL,
|
||||||
|
writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
|
||||||
|
|
||||||
|
#elif defined(USE_FOPEN)
|
||||||
|
|
||||||
|
p->file = fopen(name, writeMode ? "wb+" : "rb");
|
||||||
|
return (p->file != 0) ? 0 :
|
||||||
|
#ifdef UNDER_CE
|
||||||
|
2; /* ENOENT */
|
||||||
|
#else
|
||||||
|
errno;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
int flags = (writeMode ? (O_CREAT | O_EXCL | O_WRONLY) : O_RDONLY);
|
||||||
|
#ifdef O_BINARY
|
||||||
|
flags |= O_BINARY;
|
||||||
|
#endif
|
||||||
|
p->fd = open(name, flags, 0666);
|
||||||
|
return (p->fd != -1) ? 0 : errno;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); }
|
||||||
|
|
||||||
|
WRes OutFile_Open(CSzFile *p, const char *name)
|
||||||
|
{
|
||||||
|
#if defined(USE_WINDOWS_FILE) || defined(USE_FOPEN)
|
||||||
|
return File_Open(p, name, 1);
|
||||||
|
#else
|
||||||
|
p->fd = creat(name, 0666);
|
||||||
|
return (p->fd != -1) ? 0 : errno;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef USE_WINDOWS_FILE
|
||||||
|
static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode)
|
||||||
|
{
|
||||||
|
p->handle = CreateFileW(name,
|
||||||
|
writeMode ? GENERIC_WRITE : GENERIC_READ,
|
||||||
|
FILE_SHARE_READ, NULL,
|
||||||
|
writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
|
||||||
|
}
|
||||||
|
WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); }
|
||||||
|
WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
WRes File_Close(CSzFile *p)
|
||||||
|
{
|
||||||
|
#ifdef USE_WINDOWS_FILE
|
||||||
|
|
||||||
|
if (p->handle != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
if (!CloseHandle(p->handle))
|
||||||
|
return GetLastError();
|
||||||
|
p->handle = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(USE_FOPEN)
|
||||||
|
|
||||||
|
if (p->file != NULL)
|
||||||
|
{
|
||||||
|
int res = fclose(p->file);
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
if (res == EOF)
|
||||||
|
return errno;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
p->file = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
if (p->fd != -1)
|
||||||
|
{
|
||||||
|
if (close(p->fd) != 0)
|
||||||
|
return errno;
|
||||||
|
p->fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WRes File_Read(CSzFile *p, void *data, size_t *size)
|
||||||
|
{
|
||||||
|
size_t originalSize = *size;
|
||||||
|
*size = 0;
|
||||||
|
if (originalSize == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#ifdef USE_WINDOWS_FILE
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
|
||||||
|
DWORD processed = 0;
|
||||||
|
const BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL);
|
||||||
|
data = (void *)((Byte *)data + processed);
|
||||||
|
originalSize -= processed;
|
||||||
|
*size += processed;
|
||||||
|
if (!res)
|
||||||
|
return GetLastError();
|
||||||
|
// debug : we can break here for partial reading mode
|
||||||
|
if (processed == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (originalSize > 0);
|
||||||
|
|
||||||
|
#elif defined(USE_FOPEN)
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
|
||||||
|
const size_t processed = fread(data, 1, curSize, p->file);
|
||||||
|
data = (void *)((Byte *)data + (size_t)processed);
|
||||||
|
originalSize -= processed;
|
||||||
|
*size += processed;
|
||||||
|
if (processed != curSize)
|
||||||
|
return ferror(p->file);
|
||||||
|
// debug : we can break here for partial reading mode
|
||||||
|
if (processed == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (originalSize > 0);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
|
||||||
|
const ssize_t processed = read(p->fd, data, curSize);
|
||||||
|
if (processed == -1)
|
||||||
|
return errno;
|
||||||
|
if (processed == 0)
|
||||||
|
break;
|
||||||
|
data = (void *)((Byte *)data + (size_t)processed);
|
||||||
|
originalSize -= (size_t)processed;
|
||||||
|
*size += (size_t)processed;
|
||||||
|
// debug : we can break here for partial reading mode
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
while (originalSize > 0);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WRes File_Write(CSzFile *p, const void *data, size_t *size)
|
||||||
|
{
|
||||||
|
size_t originalSize = *size;
|
||||||
|
*size = 0;
|
||||||
|
if (originalSize == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#ifdef USE_WINDOWS_FILE
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
|
||||||
|
DWORD processed = 0;
|
||||||
|
const BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL);
|
||||||
|
data = (const void *)((const Byte *)data + processed);
|
||||||
|
originalSize -= processed;
|
||||||
|
*size += processed;
|
||||||
|
if (!res)
|
||||||
|
return GetLastError();
|
||||||
|
if (processed == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (originalSize > 0);
|
||||||
|
|
||||||
|
#elif defined(USE_FOPEN)
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
|
||||||
|
const size_t processed = fwrite(data, 1, curSize, p->file);
|
||||||
|
data = (void *)((Byte *)data + (size_t)processed);
|
||||||
|
originalSize -= processed;
|
||||||
|
*size += processed;
|
||||||
|
if (processed != curSize)
|
||||||
|
return ferror(p->file);
|
||||||
|
if (processed == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (originalSize > 0);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
|
||||||
|
const ssize_t processed = write(p->fd, data, curSize);
|
||||||
|
if (processed == -1)
|
||||||
|
return errno;
|
||||||
|
if (processed == 0)
|
||||||
|
break;
|
||||||
|
data = (const void *)((const Byte *)data + (size_t)processed);
|
||||||
|
originalSize -= (size_t)processed;
|
||||||
|
*size += (size_t)processed;
|
||||||
|
}
|
||||||
|
while (originalSize > 0);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin)
|
||||||
|
{
|
||||||
|
#ifdef USE_WINDOWS_FILE
|
||||||
|
|
||||||
|
DWORD moveMethod;
|
||||||
|
UInt32 low = (UInt32)*pos;
|
||||||
|
LONG high = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */
|
||||||
|
// (int) to eliminate clang warning
|
||||||
|
switch ((int)origin)
|
||||||
|
{
|
||||||
|
case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break;
|
||||||
|
case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break;
|
||||||
|
case SZ_SEEK_END: moveMethod = FILE_END; break;
|
||||||
|
default: return ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
low = SetFilePointer(p->handle, (LONG)low, &high, moveMethod);
|
||||||
|
if (low == (UInt32)0xFFFFFFFF)
|
||||||
|
{
|
||||||
|
WRes res = GetLastError();
|
||||||
|
if (res != NO_ERROR)
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
*pos = ((Int64)high << 32) | low;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
int moveMethod; // = origin;
|
||||||
|
|
||||||
|
switch ((int)origin)
|
||||||
|
{
|
||||||
|
case SZ_SEEK_SET: moveMethod = SEEK_SET; break;
|
||||||
|
case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break;
|
||||||
|
case SZ_SEEK_END: moveMethod = SEEK_END; break;
|
||||||
|
default: return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(USE_FOPEN)
|
||||||
|
{
|
||||||
|
int res = fseek(p->file, (long)*pos, moveMethod);
|
||||||
|
if (res == -1)
|
||||||
|
return errno;
|
||||||
|
*pos = ftell(p->file);
|
||||||
|
if (*pos == -1)
|
||||||
|
return errno;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
off_t res = lseek(p->fd, (off_t)*pos, moveMethod);
|
||||||
|
if (res == -1)
|
||||||
|
return errno;
|
||||||
|
*pos = res;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // USE_FOPEN
|
||||||
|
#endif // USE_WINDOWS_FILE
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WRes File_GetLength(CSzFile *p, UInt64 *length)
|
||||||
|
{
|
||||||
|
#ifdef USE_WINDOWS_FILE
|
||||||
|
|
||||||
|
DWORD sizeHigh;
|
||||||
|
DWORD sizeLow = GetFileSize(p->handle, &sizeHigh);
|
||||||
|
if (sizeLow == 0xFFFFFFFF)
|
||||||
|
{
|
||||||
|
DWORD res = GetLastError();
|
||||||
|
if (res != NO_ERROR)
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
*length = (((UInt64)sizeHigh) << 32) + sizeLow;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#elif defined(USE_FOPEN)
|
||||||
|
|
||||||
|
long pos = ftell(p->file);
|
||||||
|
int res = fseek(p->file, 0, SEEK_END);
|
||||||
|
*length = ftell(p->file);
|
||||||
|
fseek(p->file, pos, SEEK_SET);
|
||||||
|
return res;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
off_t pos;
|
||||||
|
*length = 0;
|
||||||
|
pos = lseek(p->fd, 0, SEEK_CUR);
|
||||||
|
if (pos != -1)
|
||||||
|
{
|
||||||
|
const off_t len2 = lseek(p->fd, 0, SEEK_END);
|
||||||
|
const off_t res2 = lseek(p->fd, pos, SEEK_SET);
|
||||||
|
if (len2 != -1)
|
||||||
|
{
|
||||||
|
*length = (UInt64)len2;
|
||||||
|
if (res2 != -1)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------- FileSeqInStream ---------- */
|
||||||
|
|
||||||
|
static SRes FileSeqInStream_Read(ISeqInStreamPtr pp, void *buf, size_t *size)
|
||||||
|
{
|
||||||
|
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileSeqInStream)
|
||||||
|
const WRes wres = File_Read(&p->file, buf, size);
|
||||||
|
p->wres = wres;
|
||||||
|
return (wres == 0) ? SZ_OK : SZ_ERROR_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSeqInStream_CreateVTable(CFileSeqInStream *p)
|
||||||
|
{
|
||||||
|
p->vt.Read = FileSeqInStream_Read;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------- FileInStream ---------- */
|
||||||
|
|
||||||
|
static SRes FileInStream_Read(ISeekInStreamPtr pp, void *buf, size_t *size)
|
||||||
|
{
|
||||||
|
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileInStream)
|
||||||
|
const WRes wres = File_Read(&p->file, buf, size);
|
||||||
|
p->wres = wres;
|
||||||
|
return (wres == 0) ? SZ_OK : SZ_ERROR_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SRes FileInStream_Seek(ISeekInStreamPtr pp, Int64 *pos, ESzSeek origin)
|
||||||
|
{
|
||||||
|
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileInStream)
|
||||||
|
const WRes wres = File_Seek(&p->file, pos, origin);
|
||||||
|
p->wres = wres;
|
||||||
|
return (wres == 0) ? SZ_OK : SZ_ERROR_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileInStream_CreateVTable(CFileInStream *p)
|
||||||
|
{
|
||||||
|
p->vt.Read = FileInStream_Read;
|
||||||
|
p->vt.Seek = FileInStream_Seek;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------- FileOutStream ---------- */
|
||||||
|
|
||||||
|
static size_t FileOutStream_Write(ISeqOutStreamPtr pp, const void *data, size_t size)
|
||||||
|
{
|
||||||
|
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileOutStream)
|
||||||
|
const WRes wres = File_Write(&p->file, data, &size);
|
||||||
|
p->wres = wres;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileOutStream_CreateVTable(CFileOutStream *p)
|
||||||
|
{
|
||||||
|
p->vt.Write = FileOutStream_Write;
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
/* 7zFile.h -- File IO
|
||||||
|
2023-03-05 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_FILE_H
|
||||||
|
#define ZIP7_INC_FILE_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define USE_WINDOWS_FILE
|
||||||
|
// #include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_WINDOWS_FILE
|
||||||
|
#include "7zWindows.h"
|
||||||
|
|
||||||
|
#else
|
||||||
|
// note: USE_FOPEN mode is limited to 32-bit file size
|
||||||
|
// #define USE_FOPEN
|
||||||
|
// #include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
/* ---------- File ---------- */
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
#ifdef USE_WINDOWS_FILE
|
||||||
|
HANDLE handle;
|
||||||
|
#elif defined(USE_FOPEN)
|
||||||
|
FILE *file;
|
||||||
|
#else
|
||||||
|
int fd;
|
||||||
|
#endif
|
||||||
|
} CSzFile;
|
||||||
|
|
||||||
|
void File_Construct(CSzFile *p);
|
||||||
|
#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
|
||||||
|
WRes InFile_Open(CSzFile *p, const char *name);
|
||||||
|
WRes OutFile_Open(CSzFile *p, const char *name);
|
||||||
|
#endif
|
||||||
|
#ifdef USE_WINDOWS_FILE
|
||||||
|
WRes InFile_OpenW(CSzFile *p, const WCHAR *name);
|
||||||
|
WRes OutFile_OpenW(CSzFile *p, const WCHAR *name);
|
||||||
|
#endif
|
||||||
|
WRes File_Close(CSzFile *p);
|
||||||
|
|
||||||
|
/* reads max(*size, remain file's size) bytes */
|
||||||
|
WRes File_Read(CSzFile *p, void *data, size_t *size);
|
||||||
|
|
||||||
|
/* writes *size bytes */
|
||||||
|
WRes File_Write(CSzFile *p, const void *data, size_t *size);
|
||||||
|
|
||||||
|
WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin);
|
||||||
|
WRes File_GetLength(CSzFile *p, UInt64 *length);
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------- FileInStream ---------- */
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ISeqInStream vt;
|
||||||
|
CSzFile file;
|
||||||
|
WRes wres;
|
||||||
|
} CFileSeqInStream;
|
||||||
|
|
||||||
|
void FileSeqInStream_CreateVTable(CFileSeqInStream *p);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ISeekInStream vt;
|
||||||
|
CSzFile file;
|
||||||
|
WRes wres;
|
||||||
|
} CFileInStream;
|
||||||
|
|
||||||
|
void FileInStream_CreateVTable(CFileInStream *p);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ISeqOutStream vt;
|
||||||
|
CSzFile file;
|
||||||
|
WRes wres;
|
||||||
|
} CFileOutStream;
|
||||||
|
|
||||||
|
void FileOutStream_CreateVTable(CFileOutStream *p);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
/* 7zStream.c -- 7z Stream functions
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#include "Precomp.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
|
||||||
|
SRes SeqInStream_ReadMax(ISeqInStreamPtr stream, void *buf, size_t *processedSize)
|
||||||
|
{
|
||||||
|
size_t size = *processedSize;
|
||||||
|
*processedSize = 0;
|
||||||
|
while (size != 0)
|
||||||
|
{
|
||||||
|
size_t cur = size;
|
||||||
|
const SRes res = ISeqInStream_Read(stream, buf, &cur);
|
||||||
|
*processedSize += cur;
|
||||||
|
buf = (void *)((Byte *)buf + cur);
|
||||||
|
size -= cur;
|
||||||
|
if (res != SZ_OK)
|
||||||
|
return res;
|
||||||
|
if (cur == 0)
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
SRes SeqInStream_Read2(ISeqInStreamPtr stream, void *buf, size_t size, SRes errorType)
|
||||||
|
{
|
||||||
|
while (size != 0)
|
||||||
|
{
|
||||||
|
size_t processed = size;
|
||||||
|
RINOK(ISeqInStream_Read(stream, buf, &processed))
|
||||||
|
if (processed == 0)
|
||||||
|
return errorType;
|
||||||
|
buf = (void *)((Byte *)buf + processed);
|
||||||
|
size -= processed;
|
||||||
|
}
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
SRes SeqInStream_Read(ISeqInStreamPtr stream, void *buf, size_t size)
|
||||||
|
{
|
||||||
|
return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
SRes SeqInStream_ReadByte(ISeqInStreamPtr stream, Byte *buf)
|
||||||
|
{
|
||||||
|
size_t processed = 1;
|
||||||
|
RINOK(ISeqInStream_Read(stream, buf, &processed))
|
||||||
|
return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SRes LookInStream_SeekTo(ILookInStreamPtr stream, UInt64 offset)
|
||||||
|
{
|
||||||
|
Int64 t = (Int64)offset;
|
||||||
|
return ILookInStream_Seek(stream, &t, SZ_SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
SRes LookInStream_LookRead(ILookInStreamPtr stream, void *buf, size_t *size)
|
||||||
|
{
|
||||||
|
const void *lookBuf;
|
||||||
|
if (*size == 0)
|
||||||
|
return SZ_OK;
|
||||||
|
RINOK(ILookInStream_Look(stream, &lookBuf, size))
|
||||||
|
memcpy(buf, lookBuf, *size);
|
||||||
|
return ILookInStream_Skip(stream, *size);
|
||||||
|
}
|
||||||
|
|
||||||
|
SRes LookInStream_Read2(ILookInStreamPtr stream, void *buf, size_t size, SRes errorType)
|
||||||
|
{
|
||||||
|
while (size != 0)
|
||||||
|
{
|
||||||
|
size_t processed = size;
|
||||||
|
RINOK(ILookInStream_Read(stream, buf, &processed))
|
||||||
|
if (processed == 0)
|
||||||
|
return errorType;
|
||||||
|
buf = (void *)((Byte *)buf + processed);
|
||||||
|
size -= processed;
|
||||||
|
}
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
SRes LookInStream_Read(ILookInStreamPtr stream, void *buf, size_t size)
|
||||||
|
{
|
||||||
|
return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define GET_LookToRead2 Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CLookToRead2)
|
||||||
|
|
||||||
|
static SRes LookToRead2_Look_Lookahead(ILookInStreamPtr pp, const void **buf, size_t *size)
|
||||||
|
{
|
||||||
|
SRes res = SZ_OK;
|
||||||
|
GET_LookToRead2
|
||||||
|
size_t size2 = p->size - p->pos;
|
||||||
|
if (size2 == 0 && *size != 0)
|
||||||
|
{
|
||||||
|
p->pos = 0;
|
||||||
|
p->size = 0;
|
||||||
|
size2 = p->bufSize;
|
||||||
|
res = ISeekInStream_Read(p->realStream, p->buf, &size2);
|
||||||
|
p->size = size2;
|
||||||
|
}
|
||||||
|
if (*size > size2)
|
||||||
|
*size = size2;
|
||||||
|
*buf = p->buf + p->pos;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SRes LookToRead2_Look_Exact(ILookInStreamPtr pp, const void **buf, size_t *size)
|
||||||
|
{
|
||||||
|
SRes res = SZ_OK;
|
||||||
|
GET_LookToRead2
|
||||||
|
size_t size2 = p->size - p->pos;
|
||||||
|
if (size2 == 0 && *size != 0)
|
||||||
|
{
|
||||||
|
p->pos = 0;
|
||||||
|
p->size = 0;
|
||||||
|
if (*size > p->bufSize)
|
||||||
|
*size = p->bufSize;
|
||||||
|
res = ISeekInStream_Read(p->realStream, p->buf, size);
|
||||||
|
size2 = p->size = *size;
|
||||||
|
}
|
||||||
|
if (*size > size2)
|
||||||
|
*size = size2;
|
||||||
|
*buf = p->buf + p->pos;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SRes LookToRead2_Skip(ILookInStreamPtr pp, size_t offset)
|
||||||
|
{
|
||||||
|
GET_LookToRead2
|
||||||
|
p->pos += offset;
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SRes LookToRead2_Read(ILookInStreamPtr pp, void *buf, size_t *size)
|
||||||
|
{
|
||||||
|
GET_LookToRead2
|
||||||
|
size_t rem = p->size - p->pos;
|
||||||
|
if (rem == 0)
|
||||||
|
return ISeekInStream_Read(p->realStream, buf, size);
|
||||||
|
if (rem > *size)
|
||||||
|
rem = *size;
|
||||||
|
memcpy(buf, p->buf + p->pos, rem);
|
||||||
|
p->pos += rem;
|
||||||
|
*size = rem;
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SRes LookToRead2_Seek(ILookInStreamPtr pp, Int64 *pos, ESzSeek origin)
|
||||||
|
{
|
||||||
|
GET_LookToRead2
|
||||||
|
p->pos = p->size = 0;
|
||||||
|
return ISeekInStream_Seek(p->realStream, pos, origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead)
|
||||||
|
{
|
||||||
|
p->vt.Look = lookahead ?
|
||||||
|
LookToRead2_Look_Lookahead :
|
||||||
|
LookToRead2_Look_Exact;
|
||||||
|
p->vt.Skip = LookToRead2_Skip;
|
||||||
|
p->vt.Read = LookToRead2_Read;
|
||||||
|
p->vt.Seek = LookToRead2_Seek;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static SRes SecToLook_Read(ISeqInStreamPtr pp, void *buf, size_t *size)
|
||||||
|
{
|
||||||
|
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSecToLook)
|
||||||
|
return LookInStream_LookRead(p->realStream, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SecToLook_CreateVTable(CSecToLook *p)
|
||||||
|
{
|
||||||
|
p->vt.Read = SecToLook_Read;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SRes SecToRead_Read(ISeqInStreamPtr pp, void *buf, size_t *size)
|
||||||
|
{
|
||||||
|
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSecToRead)
|
||||||
|
return ILookInStream_Read(p->realStream, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SecToRead_CreateVTable(CSecToRead *p)
|
||||||
|
{
|
||||||
|
p->vt.Read = SecToRead_Read;
|
||||||
|
}
|
||||||
@@ -0,0 +1,597 @@
|
|||||||
|
/* 7zTypes.h -- Basic types
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_7Z_TYPES_H
|
||||||
|
#define ZIP7_7Z_TYPES_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* #include <windows.h> */
|
||||||
|
#else
|
||||||
|
#include <errno.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#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 _MSC_VER
|
||||||
|
#if _MSC_VER > 1200
|
||||||
|
#define MY_ALIGN(n) __declspec(align(n))
|
||||||
|
#else
|
||||||
|
#define MY_ALIGN(n)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
// C11/C++11:
|
||||||
|
#include <stdalign.h>
|
||||||
|
#define MY_ALIGN(n) alignas(n)
|
||||||
|
*/
|
||||||
|
#define MY_ALIGN(n) __attribute__ ((aligned(n)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
/* typedef DWORD WRes; */
|
||||||
|
typedef unsigned WRes;
|
||||||
|
#define MY_SRes_HRESULT_FROM_WRes(x) HRESULT_FROM_WIN32(x)
|
||||||
|
|
||||||
|
// #define MY_HRES_ERROR_INTERNAL_ERROR MY_SRes_HRESULT_FROM_WRes(ERROR_INTERNAL_ERROR)
|
||||||
|
|
||||||
|
#else // _WIN32
|
||||||
|
|
||||||
|
// #define ENV_HAVE_LSTAT
|
||||||
|
typedef int WRes;
|
||||||
|
|
||||||
|
// (FACILITY_ERRNO = 0x800) is 7zip's FACILITY constant to represent (errno) errors in HRESULT
|
||||||
|
#define MY_FACILITY_ERRNO 0x800
|
||||||
|
#define MY_FACILITY_WIN32 7
|
||||||
|
#define MY_FACILITY_WRes MY_FACILITY_ERRNO
|
||||||
|
|
||||||
|
#define MY_HRESULT_FROM_errno_CONST_ERROR(x) ((HRESULT)( \
|
||||||
|
( (HRESULT)(x) & 0x0000FFFF) \
|
||||||
|
| (MY_FACILITY_WRes << 16) \
|
||||||
|
| (HRESULT)0x80000000 ))
|
||||||
|
|
||||||
|
#define MY_SRes_HRESULT_FROM_WRes(x) \
|
||||||
|
((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : MY_HRESULT_FROM_errno_CONST_ERROR(x))
|
||||||
|
|
||||||
|
// we call macro HRESULT_FROM_WIN32 for system errors (WRes) that are (errno)
|
||||||
|
#define HRESULT_FROM_WIN32(x) MY_SRes_HRESULT_FROM_WRes(x)
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define ERROR_FILE_NOT_FOUND 2L
|
||||||
|
#define ERROR_ACCESS_DENIED 5L
|
||||||
|
#define ERROR_NO_MORE_FILES 18L
|
||||||
|
#define ERROR_LOCK_VIOLATION 33L
|
||||||
|
#define ERROR_FILE_EXISTS 80L
|
||||||
|
#define ERROR_DISK_FULL 112L
|
||||||
|
#define ERROR_NEGATIVE_SEEK 131L
|
||||||
|
#define ERROR_ALREADY_EXISTS 183L
|
||||||
|
#define ERROR_DIRECTORY 267L
|
||||||
|
#define ERROR_TOO_MANY_POSTS 298L
|
||||||
|
|
||||||
|
#define ERROR_INTERNAL_ERROR 1359L
|
||||||
|
#define ERROR_INVALID_REPARSE_DATA 4392L
|
||||||
|
#define ERROR_REPARSE_TAG_INVALID 4393L
|
||||||
|
#define ERROR_REPARSE_TAG_MISMATCH 4394L
|
||||||
|
*/
|
||||||
|
|
||||||
|
// we use errno equivalents for some WIN32 errors:
|
||||||
|
|
||||||
|
#define ERROR_INVALID_PARAMETER EINVAL
|
||||||
|
#define ERROR_INVALID_FUNCTION EINVAL
|
||||||
|
#define ERROR_ALREADY_EXISTS EEXIST
|
||||||
|
#define ERROR_FILE_EXISTS EEXIST
|
||||||
|
#define ERROR_PATH_NOT_FOUND ENOENT
|
||||||
|
#define ERROR_FILE_NOT_FOUND ENOENT
|
||||||
|
#define ERROR_DISK_FULL ENOSPC
|
||||||
|
// #define ERROR_INVALID_HANDLE EBADF
|
||||||
|
|
||||||
|
// we use FACILITY_WIN32 for errors that has no errno equivalent
|
||||||
|
// Too many posts were made to a semaphore.
|
||||||
|
#define ERROR_TOO_MANY_POSTS ((HRESULT)0x8007012AL)
|
||||||
|
#define ERROR_INVALID_REPARSE_DATA ((HRESULT)0x80071128L)
|
||||||
|
#define ERROR_REPARSE_TAG_INVALID ((HRESULT)0x80071129L)
|
||||||
|
|
||||||
|
// if (MY_FACILITY_WRes != FACILITY_WIN32),
|
||||||
|
// we use FACILITY_WIN32 for COM errors:
|
||||||
|
#define E_OUTOFMEMORY ((HRESULT)0x8007000EL)
|
||||||
|
#define E_INVALIDARG ((HRESULT)0x80070057L)
|
||||||
|
#define MY_E_ERROR_NEGATIVE_SEEK ((HRESULT)0x80070083L)
|
||||||
|
|
||||||
|
/*
|
||||||
|
// we can use FACILITY_ERRNO for some COM errors, that have errno equivalents:
|
||||||
|
#define E_OUTOFMEMORY MY_HRESULT_FROM_errno_CONST_ERROR(ENOMEM)
|
||||||
|
#define E_INVALIDARG MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL)
|
||||||
|
#define MY_E_ERROR_NEGATIVE_SEEK MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define TEXT(quote) quote
|
||||||
|
|
||||||
|
#define FILE_ATTRIBUTE_READONLY 0x0001
|
||||||
|
#define FILE_ATTRIBUTE_HIDDEN 0x0002
|
||||||
|
#define FILE_ATTRIBUTE_SYSTEM 0x0004
|
||||||
|
#define FILE_ATTRIBUTE_DIRECTORY 0x0010
|
||||||
|
#define FILE_ATTRIBUTE_ARCHIVE 0x0020
|
||||||
|
#define FILE_ATTRIBUTE_DEVICE 0x0040
|
||||||
|
#define FILE_ATTRIBUTE_NORMAL 0x0080
|
||||||
|
#define FILE_ATTRIBUTE_TEMPORARY 0x0100
|
||||||
|
#define FILE_ATTRIBUTE_SPARSE_FILE 0x0200
|
||||||
|
#define FILE_ATTRIBUTE_REPARSE_POINT 0x0400
|
||||||
|
#define FILE_ATTRIBUTE_COMPRESSED 0x0800
|
||||||
|
#define FILE_ATTRIBUTE_OFFLINE 0x1000
|
||||||
|
#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x2000
|
||||||
|
#define FILE_ATTRIBUTE_ENCRYPTED 0x4000
|
||||||
|
|
||||||
|
#define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000 /* trick for Unix */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef RINOK
|
||||||
|
#define RINOK(x) { const int _result_ = (x); if (_result_ != 0) return _result_; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RINOK_WRes
|
||||||
|
#define RINOK_WRes(x) { const WRes _result_ = (x); if (_result_ != 0) return _result_; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef unsigned char Byte;
|
||||||
|
typedef short Int16;
|
||||||
|
typedef unsigned short UInt16;
|
||||||
|
|
||||||
|
#ifdef Z7_DECL_Int32_AS_long
|
||||||
|
typedef long Int32;
|
||||||
|
typedef unsigned long UInt32;
|
||||||
|
#else
|
||||||
|
typedef int Int32;
|
||||||
|
typedef unsigned int UInt32;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
|
||||||
|
typedef int INT;
|
||||||
|
typedef Int32 INT32;
|
||||||
|
typedef unsigned int UINT;
|
||||||
|
typedef UInt32 UINT32;
|
||||||
|
typedef INT32 LONG; // LONG, ULONG and DWORD must be 32-bit for _WIN32 compatibility
|
||||||
|
typedef UINT32 ULONG;
|
||||||
|
|
||||||
|
#undef DWORD
|
||||||
|
typedef UINT32 DWORD;
|
||||||
|
|
||||||
|
#define VOID void
|
||||||
|
|
||||||
|
#define HRESULT LONG
|
||||||
|
|
||||||
|
typedef void *LPVOID;
|
||||||
|
// typedef void VOID;
|
||||||
|
// typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
|
||||||
|
// gcc / clang on Unix : sizeof(long==sizeof(void*) in 32 or 64 bits)
|
||||||
|
typedef long INT_PTR;
|
||||||
|
typedef unsigned long UINT_PTR;
|
||||||
|
typedef long LONG_PTR;
|
||||||
|
typedef unsigned long DWORD_PTR;
|
||||||
|
|
||||||
|
typedef size_t SIZE_T;
|
||||||
|
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
|
||||||
|
#define MY_HRES_ERROR_INTERNAL_ERROR ((HRESULT)0x8007054FL)
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef Z7_DECL_Int64_AS_long
|
||||||
|
|
||||||
|
typedef long Int64;
|
||||||
|
typedef unsigned long UInt64;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#if (defined(_MSC_VER) || defined(__BORLANDC__)) && !defined(__clang__)
|
||||||
|
typedef __int64 Int64;
|
||||||
|
typedef unsigned __int64 UInt64;
|
||||||
|
#else
|
||||||
|
#if defined(__clang__) || defined(__GNUC__)
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef int64_t Int64;
|
||||||
|
typedef uint64_t UInt64;
|
||||||
|
#else
|
||||||
|
typedef long long int Int64;
|
||||||
|
typedef unsigned long long int UInt64;
|
||||||
|
// #define UINT64_CONST(n) n ## ULL
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define UINT64_CONST(n) n
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef Z7_DECL_SizeT_AS_unsigned_int
|
||||||
|
typedef unsigned int SizeT;
|
||||||
|
#else
|
||||||
|
typedef size_t SizeT;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
#if (defined(_MSC_VER) && _MSC_VER <= 1200)
|
||||||
|
typedef size_t MY_uintptr_t;
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef uintptr_t MY_uintptr_t;
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef int BoolInt;
|
||||||
|
/* typedef BoolInt Bool; */
|
||||||
|
#define True 1
|
||||||
|
#define False 0
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define Z7_STDCALL __stdcall
|
||||||
|
#else
|
||||||
|
#define Z7_STDCALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
#if _MSC_VER >= 1300
|
||||||
|
#define Z7_NO_INLINE __declspec(noinline)
|
||||||
|
#else
|
||||||
|
#define Z7_NO_INLINE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define Z7_FORCE_INLINE __forceinline
|
||||||
|
|
||||||
|
#define Z7_CDECL __cdecl
|
||||||
|
#define Z7_FASTCALL __fastcall
|
||||||
|
|
||||||
|
#else // _MSC_VER
|
||||||
|
|
||||||
|
#if (defined(__GNUC__) && (__GNUC__ >= 4)) \
|
||||||
|
|| (defined(__clang__) && (__clang_major__ >= 4)) \
|
||||||
|
|| defined(__INTEL_COMPILER) \
|
||||||
|
|| defined(__xlC__)
|
||||||
|
#define Z7_NO_INLINE __attribute__((noinline))
|
||||||
|
#define Z7_FORCE_INLINE __attribute__((always_inline)) inline
|
||||||
|
#else
|
||||||
|
#define Z7_NO_INLINE
|
||||||
|
#define Z7_FORCE_INLINE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define Z7_CDECL
|
||||||
|
|
||||||
|
#if defined(_M_IX86) \
|
||||||
|
|| defined(__i386__)
|
||||||
|
// #define Z7_FASTCALL __attribute__((fastcall))
|
||||||
|
// #define Z7_FASTCALL __attribute__((cdecl))
|
||||||
|
#define Z7_FASTCALL
|
||||||
|
#elif defined(MY_CPU_AMD64)
|
||||||
|
// #define Z7_FASTCALL __attribute__((ms_abi))
|
||||||
|
#define Z7_FASTCALL
|
||||||
|
#else
|
||||||
|
#define Z7_FASTCALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
|
||||||
|
/* The following interfaces use first parameter as pointer to structure */
|
||||||
|
|
||||||
|
// #define Z7_C_IFACE_CONST_QUAL
|
||||||
|
#define Z7_C_IFACE_CONST_QUAL const
|
||||||
|
|
||||||
|
#define Z7_C_IFACE_DECL(a) \
|
||||||
|
struct a ## _; \
|
||||||
|
typedef Z7_C_IFACE_CONST_QUAL struct a ## _ * a ## Ptr; \
|
||||||
|
typedef struct a ## _ a; \
|
||||||
|
struct a ## _
|
||||||
|
|
||||||
|
|
||||||
|
Z7_C_IFACE_DECL (IByteIn)
|
||||||
|
{
|
||||||
|
Byte (*Read)(IByteInPtr p); /* reads one byte, returns 0 in case of EOF or error */
|
||||||
|
};
|
||||||
|
#define IByteIn_Read(p) (p)->Read(p)
|
||||||
|
|
||||||
|
|
||||||
|
Z7_C_IFACE_DECL (IByteOut)
|
||||||
|
{
|
||||||
|
void (*Write)(IByteOutPtr p, Byte b);
|
||||||
|
};
|
||||||
|
#define IByteOut_Write(p, b) (p)->Write(p, b)
|
||||||
|
|
||||||
|
|
||||||
|
Z7_C_IFACE_DECL (ISeqInStream)
|
||||||
|
{
|
||||||
|
SRes (*Read)(ISeqInStreamPtr p, void *buf, size_t *size);
|
||||||
|
/* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
|
||||||
|
(output(*size) < input(*size)) is allowed */
|
||||||
|
};
|
||||||
|
#define ISeqInStream_Read(p, buf, size) (p)->Read(p, buf, size)
|
||||||
|
|
||||||
|
/* try to read as much as avail in stream and limited by (*processedSize) */
|
||||||
|
SRes SeqInStream_ReadMax(ISeqInStreamPtr stream, void *buf, size_t *processedSize);
|
||||||
|
/* it can return SZ_ERROR_INPUT_EOF */
|
||||||
|
// SRes SeqInStream_Read(ISeqInStreamPtr stream, void *buf, size_t size);
|
||||||
|
// SRes SeqInStream_Read2(ISeqInStreamPtr stream, void *buf, size_t size, SRes errorType);
|
||||||
|
SRes SeqInStream_ReadByte(ISeqInStreamPtr stream, Byte *buf);
|
||||||
|
|
||||||
|
|
||||||
|
Z7_C_IFACE_DECL (ISeqOutStream)
|
||||||
|
{
|
||||||
|
size_t (*Write)(ISeqOutStreamPtr p, const void *buf, size_t size);
|
||||||
|
/* Returns: result - the number of actually written bytes.
|
||||||
|
(result < size) means error */
|
||||||
|
};
|
||||||
|
#define ISeqOutStream_Write(p, buf, size) (p)->Write(p, buf, size)
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SZ_SEEK_SET = 0,
|
||||||
|
SZ_SEEK_CUR = 1,
|
||||||
|
SZ_SEEK_END = 2
|
||||||
|
} ESzSeek;
|
||||||
|
|
||||||
|
|
||||||
|
Z7_C_IFACE_DECL (ISeekInStream)
|
||||||
|
{
|
||||||
|
SRes (*Read)(ISeekInStreamPtr p, void *buf, size_t *size); /* same as ISeqInStream::Read */
|
||||||
|
SRes (*Seek)(ISeekInStreamPtr p, Int64 *pos, ESzSeek origin);
|
||||||
|
};
|
||||||
|
#define ISeekInStream_Read(p, buf, size) (p)->Read(p, buf, size)
|
||||||
|
#define ISeekInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin)
|
||||||
|
|
||||||
|
|
||||||
|
Z7_C_IFACE_DECL (ILookInStream)
|
||||||
|
{
|
||||||
|
SRes (*Look)(ILookInStreamPtr 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)(ILookInStreamPtr p, size_t offset);
|
||||||
|
/* offset must be <= output(*size) of Look */
|
||||||
|
SRes (*Read)(ILookInStreamPtr p, void *buf, size_t *size);
|
||||||
|
/* reads directly (without buffer). It's same as ISeqInStream::Read */
|
||||||
|
SRes (*Seek)(ILookInStreamPtr p, Int64 *pos, ESzSeek origin);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ILookInStream_Look(p, buf, size) (p)->Look(p, buf, size)
|
||||||
|
#define ILookInStream_Skip(p, offset) (p)->Skip(p, offset)
|
||||||
|
#define ILookInStream_Read(p, buf, size) (p)->Read(p, buf, size)
|
||||||
|
#define ILookInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin)
|
||||||
|
|
||||||
|
|
||||||
|
SRes LookInStream_LookRead(ILookInStreamPtr stream, void *buf, size_t *size);
|
||||||
|
SRes LookInStream_SeekTo(ILookInStreamPtr stream, UInt64 offset);
|
||||||
|
|
||||||
|
/* reads via ILookInStream::Read */
|
||||||
|
SRes LookInStream_Read2(ILookInStreamPtr stream, void *buf, size_t size, SRes errorType);
|
||||||
|
SRes LookInStream_Read(ILookInStreamPtr stream, void *buf, size_t size);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ILookInStream vt;
|
||||||
|
ISeekInStreamPtr realStream;
|
||||||
|
|
||||||
|
size_t pos;
|
||||||
|
size_t size; /* it's data size */
|
||||||
|
|
||||||
|
/* the following variables must be set outside */
|
||||||
|
Byte *buf;
|
||||||
|
size_t bufSize;
|
||||||
|
} CLookToRead2;
|
||||||
|
|
||||||
|
void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead);
|
||||||
|
|
||||||
|
#define LookToRead2_INIT(p) { (p)->pos = (p)->size = 0; }
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ISeqInStream vt;
|
||||||
|
ILookInStreamPtr realStream;
|
||||||
|
} CSecToLook;
|
||||||
|
|
||||||
|
void SecToLook_CreateVTable(CSecToLook *p);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ISeqInStream vt;
|
||||||
|
ILookInStreamPtr realStream;
|
||||||
|
} CSecToRead;
|
||||||
|
|
||||||
|
void SecToRead_CreateVTable(CSecToRead *p);
|
||||||
|
|
||||||
|
|
||||||
|
Z7_C_IFACE_DECL (ICompressProgress)
|
||||||
|
{
|
||||||
|
SRes (*Progress)(ICompressProgressPtr p, UInt64 inSize, UInt64 outSize);
|
||||||
|
/* Returns: result. (result != SZ_OK) means break.
|
||||||
|
Value (UInt64)(Int64)-1 for size means unknown value. */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ICompressProgress_Progress(p, inSize, outSize) (p)->Progress(p, inSize, outSize)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct ISzAlloc ISzAlloc;
|
||||||
|
typedef const ISzAlloc * ISzAllocPtr;
|
||||||
|
|
||||||
|
struct ISzAlloc
|
||||||
|
{
|
||||||
|
void *(*Alloc)(ISzAllocPtr p, size_t size);
|
||||||
|
void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ISzAlloc_Alloc(p, size) (p)->Alloc(p, size)
|
||||||
|
#define ISzAlloc_Free(p, a) (p)->Free(p, a)
|
||||||
|
|
||||||
|
/* deprecated */
|
||||||
|
#define IAlloc_Alloc(p, size) ISzAlloc_Alloc(p, size)
|
||||||
|
#define IAlloc_Free(p, a) ISzAlloc_Free(p, a)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MY_offsetof
|
||||||
|
#ifdef offsetof
|
||||||
|
#define MY_offsetof(type, m) offsetof(type, m)
|
||||||
|
/*
|
||||||
|
#define MY_offsetof(type, m) FIELD_OFFSET(type, m)
|
||||||
|
*/
|
||||||
|
#else
|
||||||
|
#define MY_offsetof(type, m) ((size_t)&(((type *)0)->m))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef Z7_container_of
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define Z7_container_of(ptr, type, m) container_of(ptr, type, m)
|
||||||
|
#define Z7_container_of(ptr, type, m) CONTAINING_RECORD(ptr, type, m)
|
||||||
|
#define Z7_container_of(ptr, type, m) ((type *)((char *)(ptr) - offsetof(type, m)))
|
||||||
|
#define Z7_container_of(ptr, type, m) (&((type *)0)->m == (ptr), ((type *)(((char *)(ptr)) - MY_offsetof(type, m))))
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
GCC shows warning: "perhaps the 'offsetof' macro was used incorrectly"
|
||||||
|
GCC 3.4.4 : classes with constructor
|
||||||
|
GCC 4.8.1 : classes with non-public variable members"
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define Z7_container_of(ptr, type, m) \
|
||||||
|
((type *)(void *)((char *)(void *) \
|
||||||
|
(1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m)))
|
||||||
|
|
||||||
|
#define Z7_container_of_CONST(ptr, type, m) \
|
||||||
|
((const type *)(const void *)((const char *)(const void *) \
|
||||||
|
(1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m)))
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define Z7_container_of_NON_CONST_FROM_CONST(ptr, type, m) \
|
||||||
|
((type *)(void *)(const void *)((const char *)(const void *) \
|
||||||
|
(1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m)))
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) ((type *)(void *)(ptr))
|
||||||
|
|
||||||
|
// #define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m)
|
||||||
|
#define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_container_of(ptr, type, m)
|
||||||
|
// #define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_container_of_NON_CONST_FROM_CONST(ptr, type, m)
|
||||||
|
|
||||||
|
#define Z7_CONTAINER_FROM_VTBL_CONST(ptr, type, m) Z7_container_of_CONST(ptr, type, m)
|
||||||
|
|
||||||
|
#define Z7_CONTAINER_FROM_VTBL_CLS(ptr, type, m) Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m)
|
||||||
|
/*
|
||||||
|
#define Z7_CONTAINER_FROM_VTBL_CLS(ptr, type, m) Z7_CONTAINER_FROM_VTBL(ptr, type, m)
|
||||||
|
*/
|
||||||
|
#if defined (__clang__) || defined(__GNUC__)
|
||||||
|
#define Z7_DIAGNOSCTIC_IGNORE_BEGIN_CAST_QUAL \
|
||||||
|
_Pragma("GCC diagnostic push") \
|
||||||
|
_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
|
||||||
|
#define Z7_DIAGNOSCTIC_IGNORE_END_CAST_QUAL \
|
||||||
|
_Pragma("GCC diagnostic pop")
|
||||||
|
#else
|
||||||
|
#define Z7_DIAGNOSCTIC_IGNORE_BEGIN_CAST_QUAL
|
||||||
|
#define Z7_DIAGNOSCTIC_IGNORE_END_CAST_QUAL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR(ptr, type, m, p) \
|
||||||
|
Z7_DIAGNOSCTIC_IGNORE_BEGIN_CAST_QUAL \
|
||||||
|
type *p = Z7_CONTAINER_FROM_VTBL(ptr, type, m); \
|
||||||
|
Z7_DIAGNOSCTIC_IGNORE_END_CAST_QUAL
|
||||||
|
|
||||||
|
#define Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(type) \
|
||||||
|
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR(pp, type, vt, p)
|
||||||
|
|
||||||
|
|
||||||
|
// #define ZIP7_DECLARE_HANDLE(name) typedef void *name;
|
||||||
|
#define Z7_DECLARE_HANDLE(name) struct name##_dummy{int unused;}; typedef struct name##_dummy *name;
|
||||||
|
|
||||||
|
|
||||||
|
#define Z7_memset_0_ARRAY(a) memset((a), 0, sizeof(a))
|
||||||
|
|
||||||
|
#ifndef Z7_ARRAY_SIZE
|
||||||
|
#define Z7_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
#define k_PropVar_TimePrec_0 0
|
||||||
|
#define k_PropVar_TimePrec_Unix 1
|
||||||
|
#define k_PropVar_TimePrec_DOS 2
|
||||||
|
#define k_PropVar_TimePrec_HighPrec 3
|
||||||
|
#define k_PropVar_TimePrec_Base 16
|
||||||
|
#define k_PropVar_TimePrec_100ns (k_PropVar_TimePrec_Base + 7)
|
||||||
|
#define k_PropVar_TimePrec_1ns (k_PropVar_TimePrec_Base + 9)
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifndef Z7_ST
|
||||||
|
#ifdef _7ZIP_ST
|
||||||
|
#define Z7_ST
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#define MY_VER_MAJOR 23
|
||||||
|
#define MY_VER_MINOR 01
|
||||||
|
#define MY_VER_BUILD 0
|
||||||
|
#define MY_VERSION_NUMBERS "23.01"
|
||||||
|
#define MY_VERSION MY_VERSION_NUMBERS
|
||||||
|
|
||||||
|
#ifdef MY_CPU_NAME
|
||||||
|
#define MY_VERSION_CPU MY_VERSION " (" MY_CPU_NAME ")"
|
||||||
|
#else
|
||||||
|
#define MY_VERSION_CPU MY_VERSION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MY_DATE "2023-06-20"
|
||||||
|
#undef MY_COPYRIGHT
|
||||||
|
#undef MY_VERSION_COPYRIGHT_DATE
|
||||||
|
#define MY_AUTHOR_NAME "Igor Pavlov"
|
||||||
|
#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain"
|
||||||
|
#define MY_COPYRIGHT_CR "Copyright (c) 1999-2023 Igor Pavlov"
|
||||||
|
|
||||||
|
#ifdef USE_COPYRIGHT_CR
|
||||||
|
#define MY_COPYRIGHT MY_COPYRIGHT_CR
|
||||||
|
#else
|
||||||
|
#define MY_COPYRIGHT MY_COPYRIGHT_PD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MY_COPYRIGHT_DATE MY_COPYRIGHT " : " MY_DATE
|
||||||
|
#define MY_VERSION_COPYRIGHT_DATE MY_VERSION_CPU " : " MY_COPYRIGHT " : " MY_DATE
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/* 7zWindows.h -- StdAfx
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_7Z_WINDOWS_H
|
||||||
|
#define ZIP7_INC_7Z_WINDOWS_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4668) // '_WIN32_WINNT' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'
|
||||||
|
|
||||||
|
#if _MSC_VER == 1900
|
||||||
|
// for old kit10 versions
|
||||||
|
// #pragma warning(disable : 4255) // winuser.h(13979): warning C4255: 'GetThreadDpiAwarenessContext':
|
||||||
|
#endif
|
||||||
|
// win10 Windows Kit:
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER <= 1200 && !defined(_WIN64)
|
||||||
|
// for msvc6 without sdk2003
|
||||||
|
#define RPC_NO_WINDOWS_H
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||||
|
// #if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <Windows.h>
|
||||||
|
#endif
|
||||||
|
// #include <basetsd.h>
|
||||||
|
// #include <wtypes.h>
|
||||||
|
|
||||||
|
// but if precompiled with clang-cl then we need
|
||||||
|
// #include <windows.h>
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER <= 1200 && !defined(_WIN64)
|
||||||
|
#ifndef _W64
|
||||||
|
|
||||||
|
typedef long LONG_PTR, *PLONG_PTR;
|
||||||
|
typedef unsigned long ULONG_PTR, *PULONG_PTR;
|
||||||
|
typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
|
||||||
|
|
||||||
|
#define Z7_OLD_WIN_SDK
|
||||||
|
#endif // _W64
|
||||||
|
#endif // _MSC_VER == 1200
|
||||||
|
|
||||||
|
#ifdef Z7_OLD_WIN_SDK
|
||||||
|
|
||||||
|
#ifndef INVALID_FILE_ATTRIBUTES
|
||||||
|
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
|
||||||
|
#endif
|
||||||
|
#ifndef INVALID_SET_FILE_POINTER
|
||||||
|
#define INVALID_SET_FILE_POINTER ((DWORD)-1)
|
||||||
|
#endif
|
||||||
|
#ifndef FILE_SPECIAL_ACCESS
|
||||||
|
#define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ShlObj.h:
|
||||||
|
// #define BIF_NEWDIALOGSTYLE 0x0040
|
||||||
|
|
||||||
|
#pragma warning(disable : 4201)
|
||||||
|
// #pragma warning(disable : 4115)
|
||||||
|
|
||||||
|
#undef VARIANT_TRUE
|
||||||
|
#define VARIANT_TRUE ((VARIANT_BOOL)-1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // Z7_OLD_WIN_SDK
|
||||||
|
|
||||||
|
#ifdef UNDER_CE
|
||||||
|
#undef VARIANT_TRUE
|
||||||
|
#define VARIANT_TRUE ((VARIANT_BOOL)-1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#if _MSC_VER >= 1400 && _MSC_VER <= 1600
|
||||||
|
// BaseTsd.h(148) : 'HandleToULong' : unreferenced inline function has been removed
|
||||||
|
// string.h
|
||||||
|
// #pragma warning(disable : 4514)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* #include "7zTypes.h" */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/* Aes.h -- AES encryption / decryption
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_AES_H
|
||||||
|
#define ZIP7_INC_AES_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
#define AES_BLOCK_SIZE 16
|
||||||
|
|
||||||
|
/* Call AesGenTables one time before other AES functions */
|
||||||
|
void AesGenTables(void);
|
||||||
|
|
||||||
|
/* UInt32 pointers must be 16-byte aligned */
|
||||||
|
|
||||||
|
/* 16-byte (4 * 32-bit words) blocks: 1 (IV) + 1 (keyMode) + 15 (AES-256 roundKeys) */
|
||||||
|
#define AES_NUM_IVMRK_WORDS ((1 + 1 + 15) * 4)
|
||||||
|
|
||||||
|
/* aes - 16-byte aligned pointer to keyMode+roundKeys sequence */
|
||||||
|
/* keySize = 16 or 24 or 32 (bytes) */
|
||||||
|
typedef void (Z7_FASTCALL *AES_SET_KEY_FUNC)(UInt32 *aes, const Byte *key, unsigned keySize);
|
||||||
|
void Z7_FASTCALL Aes_SetKey_Enc(UInt32 *aes, const Byte *key, unsigned keySize);
|
||||||
|
void Z7_FASTCALL Aes_SetKey_Dec(UInt32 *aes, const Byte *key, unsigned keySize);
|
||||||
|
|
||||||
|
/* ivAes - 16-byte aligned pointer to iv+keyMode+roundKeys sequence: UInt32[AES_NUM_IVMRK_WORDS] */
|
||||||
|
void AesCbc_Init(UInt32 *ivAes, const Byte *iv); /* iv size is AES_BLOCK_SIZE */
|
||||||
|
|
||||||
|
/* data - 16-byte aligned pointer to data */
|
||||||
|
/* numBlocks - the number of 16-byte blocks in data array */
|
||||||
|
typedef void (Z7_FASTCALL *AES_CODE_FUNC)(UInt32 *ivAes, Byte *data, size_t numBlocks);
|
||||||
|
|
||||||
|
extern AES_CODE_FUNC g_AesCbc_Decode;
|
||||||
|
#ifndef Z7_SFX
|
||||||
|
extern AES_CODE_FUNC g_AesCbc_Encode;
|
||||||
|
extern AES_CODE_FUNC g_AesCtr_Code;
|
||||||
|
#define k_Aes_SupportedFunctions_HW (1 << 2)
|
||||||
|
#define k_Aes_SupportedFunctions_HW_256 (1 << 3)
|
||||||
|
extern UInt32 g_Aes_SupportedFunctions_Flags;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define Z7_DECLARE_AES_CODE_FUNC(funcName) \
|
||||||
|
void Z7_FASTCALL funcName(UInt32 *ivAes, Byte *data, size_t numBlocks);
|
||||||
|
|
||||||
|
Z7_DECLARE_AES_CODE_FUNC (AesCbc_Encode)
|
||||||
|
Z7_DECLARE_AES_CODE_FUNC (AesCbc_Decode)
|
||||||
|
Z7_DECLARE_AES_CODE_FUNC (AesCtr_Code)
|
||||||
|
|
||||||
|
Z7_DECLARE_AES_CODE_FUNC (AesCbc_Encode_HW)
|
||||||
|
Z7_DECLARE_AES_CODE_FUNC (AesCbc_Decode_HW)
|
||||||
|
Z7_DECLARE_AES_CODE_FUNC (AesCtr_Code_HW)
|
||||||
|
|
||||||
|
Z7_DECLARE_AES_CODE_FUNC (AesCbc_Decode_HW_256)
|
||||||
|
Z7_DECLARE_AES_CODE_FUNC (AesCtr_Code_HW_256)
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/* Alloc.h -- Memory allocation functions
|
||||||
|
2023-03-04 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_ALLOC_H
|
||||||
|
#define ZIP7_INC_ALLOC_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
/*
|
||||||
|
MyFree(NULL) : is allowed, as free(NULL)
|
||||||
|
MyAlloc(0) : returns NULL : but malloc(0) is allowed to return NULL or non_NULL
|
||||||
|
MyRealloc(NULL, 0) : returns NULL : but realloc(NULL, 0) is allowed to return NULL or non_NULL
|
||||||
|
MyRealloc() is similar to realloc() for the following cases:
|
||||||
|
MyRealloc(non_NULL, 0) : returns NULL and always calls MyFree(ptr)
|
||||||
|
MyRealloc(NULL, non_ZERO) : returns NULL, if allocation failed
|
||||||
|
MyRealloc(non_NULL, non_ZERO) : returns NULL, if reallocation failed
|
||||||
|
*/
|
||||||
|
|
||||||
|
void *MyAlloc(size_t size);
|
||||||
|
void MyFree(void *address);
|
||||||
|
void *MyRealloc(void *address, size_t size);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#ifdef Z7_LARGE_PAGES
|
||||||
|
void SetLargePageSize(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *MidAlloc(size_t size);
|
||||||
|
void MidFree(void *address);
|
||||||
|
void *BigAlloc(size_t size);
|
||||||
|
void BigFree(void *address);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define MidAlloc(size) MyAlloc(size)
|
||||||
|
#define MidFree(address) MyFree(address)
|
||||||
|
#define BigAlloc(size) MyAlloc(size)
|
||||||
|
#define BigFree(address) MyFree(address)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern const ISzAlloc g_Alloc;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
extern const ISzAlloc g_BigAlloc;
|
||||||
|
extern const ISzAlloc g_MidAlloc;
|
||||||
|
#else
|
||||||
|
#define g_BigAlloc g_AlignedAlloc
|
||||||
|
#define g_MidAlloc g_AlignedAlloc
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern const ISzAlloc g_AlignedAlloc;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ISzAlloc vt;
|
||||||
|
ISzAllocPtr baseAlloc;
|
||||||
|
unsigned numAlignBits; /* ((1 << numAlignBits) >= sizeof(void *)) */
|
||||||
|
size_t offset; /* (offset == (k * sizeof(void *)) && offset < (1 << numAlignBits) */
|
||||||
|
} CAlignOffsetAlloc;
|
||||||
|
|
||||||
|
void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p);
|
||||||
|
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,290 @@
|
|||||||
|
/* Bcj2.c -- BCJ2 Decoder (Converter for x86 code)
|
||||||
|
2023-03-01 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#include "Precomp.h"
|
||||||
|
|
||||||
|
#include "Bcj2.h"
|
||||||
|
#include "CpuArch.h"
|
||||||
|
|
||||||
|
#define kTopValue ((UInt32)1 << 24)
|
||||||
|
#define kNumBitModelTotalBits 11
|
||||||
|
#define kBitModelTotal (1 << kNumBitModelTotalBits)
|
||||||
|
#define kNumMoveBits 5
|
||||||
|
|
||||||
|
// UInt32 bcj2_stats[256 + 2][2];
|
||||||
|
|
||||||
|
void Bcj2Dec_Init(CBcj2Dec *p)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
p->state = BCJ2_STREAM_RC; // BCJ2_DEC_STATE_OK;
|
||||||
|
p->ip = 0;
|
||||||
|
p->temp = 0;
|
||||||
|
p->range = 0;
|
||||||
|
p->code = 0;
|
||||||
|
for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++)
|
||||||
|
p->probs[i] = kBitModelTotal >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SRes Bcj2Dec_Decode(CBcj2Dec *p)
|
||||||
|
{
|
||||||
|
UInt32 v = p->temp;
|
||||||
|
// const Byte *src;
|
||||||
|
if (p->range <= 5)
|
||||||
|
{
|
||||||
|
UInt32 code = p->code;
|
||||||
|
p->state = BCJ2_DEC_STATE_ERROR; /* for case if we return SZ_ERROR_DATA; */
|
||||||
|
for (; p->range != 5; p->range++)
|
||||||
|
{
|
||||||
|
if (p->range == 1 && code != 0)
|
||||||
|
return SZ_ERROR_DATA;
|
||||||
|
if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC])
|
||||||
|
{
|
||||||
|
p->state = BCJ2_STREAM_RC;
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
code = (code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
|
||||||
|
p->code = code;
|
||||||
|
}
|
||||||
|
if (code == 0xffffffff)
|
||||||
|
return SZ_ERROR_DATA;
|
||||||
|
p->range = 0xffffffff;
|
||||||
|
}
|
||||||
|
// else
|
||||||
|
{
|
||||||
|
unsigned state = p->state;
|
||||||
|
// we check BCJ2_IS_32BIT_STREAM() here instead of check in the main loop
|
||||||
|
if (BCJ2_IS_32BIT_STREAM(state))
|
||||||
|
{
|
||||||
|
const Byte *cur = p->bufs[state];
|
||||||
|
if (cur == p->lims[state])
|
||||||
|
return SZ_OK;
|
||||||
|
p->bufs[state] = cur + 4;
|
||||||
|
{
|
||||||
|
const UInt32 ip = p->ip + 4;
|
||||||
|
v = GetBe32a(cur) - ip;
|
||||||
|
p->ip = ip;
|
||||||
|
}
|
||||||
|
state = BCJ2_DEC_STATE_ORIG_0;
|
||||||
|
}
|
||||||
|
if ((unsigned)(state - BCJ2_DEC_STATE_ORIG_0) < 4)
|
||||||
|
{
|
||||||
|
Byte *dest = p->dest;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (dest == p->destLim)
|
||||||
|
{
|
||||||
|
p->state = state;
|
||||||
|
p->temp = v;
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
*dest++ = (Byte)v;
|
||||||
|
p->dest = dest;
|
||||||
|
if (++state == BCJ2_DEC_STATE_ORIG_3 + 1)
|
||||||
|
break;
|
||||||
|
v >>= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// src = p->bufs[BCJ2_STREAM_MAIN];
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
if (BCJ2_IS_32BIT_STREAM(p->state))
|
||||||
|
p->state = BCJ2_DEC_STATE_OK;
|
||||||
|
else
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if (p->range < kTopValue)
|
||||||
|
{
|
||||||
|
if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC])
|
||||||
|
{
|
||||||
|
p->state = BCJ2_STREAM_RC;
|
||||||
|
p->temp = v;
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
p->range <<= 8;
|
||||||
|
p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const Byte *src = p->bufs[BCJ2_STREAM_MAIN];
|
||||||
|
const Byte *srcLim;
|
||||||
|
Byte *dest = p->dest;
|
||||||
|
{
|
||||||
|
const SizeT rem = (SizeT)(p->lims[BCJ2_STREAM_MAIN] - src);
|
||||||
|
SizeT num = (SizeT)(p->destLim - dest);
|
||||||
|
if (num >= rem)
|
||||||
|
num = rem;
|
||||||
|
#define NUM_ITERS 4
|
||||||
|
#if (NUM_ITERS & (NUM_ITERS - 1)) == 0
|
||||||
|
num &= ~((SizeT)NUM_ITERS - 1); // if (NUM_ITERS == (1 << x))
|
||||||
|
#else
|
||||||
|
num -= num % NUM_ITERS; // if (NUM_ITERS != (1 << x))
|
||||||
|
#endif
|
||||||
|
srcLim = src + num;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NUM_SHIFT_BITS 24
|
||||||
|
#define ONE_ITER(indx) { \
|
||||||
|
const unsigned b = src[indx]; \
|
||||||
|
*dest++ = (Byte)b; \
|
||||||
|
v = (v << NUM_SHIFT_BITS) | b; \
|
||||||
|
if (((b + (0x100 - 0xe8)) & 0xfe) == 0) break; \
|
||||||
|
if (((v - (((UInt32)0x0f << (NUM_SHIFT_BITS)) + 0x80)) & \
|
||||||
|
((((UInt32)1 << (4 + NUM_SHIFT_BITS)) - 0x1) << 4)) == 0) break; \
|
||||||
|
/* ++dest */; /* v = b; */ }
|
||||||
|
|
||||||
|
if (src != srcLim)
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
/* The dependency chain of 2-cycle for (v) calculation is not big problem here.
|
||||||
|
But we can remove dependency chain with v = b in the end of loop. */
|
||||||
|
ONE_ITER(0)
|
||||||
|
#if (NUM_ITERS > 1)
|
||||||
|
ONE_ITER(1)
|
||||||
|
#if (NUM_ITERS > 2)
|
||||||
|
ONE_ITER(2)
|
||||||
|
#if (NUM_ITERS > 3)
|
||||||
|
ONE_ITER(3)
|
||||||
|
#if (NUM_ITERS > 4)
|
||||||
|
ONE_ITER(4)
|
||||||
|
#if (NUM_ITERS > 5)
|
||||||
|
ONE_ITER(5)
|
||||||
|
#if (NUM_ITERS > 6)
|
||||||
|
ONE_ITER(6)
|
||||||
|
#if (NUM_ITERS > 7)
|
||||||
|
ONE_ITER(7)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
src += NUM_ITERS;
|
||||||
|
if (src == srcLim)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src == srcLim)
|
||||||
|
#if (NUM_ITERS > 1)
|
||||||
|
for (;;)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#if (NUM_ITERS > 1)
|
||||||
|
if (src == p->lims[BCJ2_STREAM_MAIN] || dest == p->destLim)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
const SizeT num = (SizeT)(src - p->bufs[BCJ2_STREAM_MAIN]);
|
||||||
|
p->bufs[BCJ2_STREAM_MAIN] = src;
|
||||||
|
p->dest = dest;
|
||||||
|
p->ip += (UInt32)num;
|
||||||
|
/* state BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */
|
||||||
|
p->state =
|
||||||
|
src == p->lims[BCJ2_STREAM_MAIN] ?
|
||||||
|
(unsigned)BCJ2_STREAM_MAIN :
|
||||||
|
(unsigned)BCJ2_DEC_STATE_ORIG;
|
||||||
|
p->temp = v;
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
#if (NUM_ITERS > 1)
|
||||||
|
ONE_ITER(0)
|
||||||
|
src++;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const SizeT num = (SizeT)(dest - p->dest);
|
||||||
|
p->dest = dest; // p->dest += num;
|
||||||
|
p->bufs[BCJ2_STREAM_MAIN] += num; // = src;
|
||||||
|
p->ip += (UInt32)num;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
UInt32 bound, ttt;
|
||||||
|
CBcj2Prob *prob; // unsigned index;
|
||||||
|
/*
|
||||||
|
prob = p->probs + (unsigned)((Byte)v == 0xe8 ?
|
||||||
|
2 + (Byte)(v >> 8) :
|
||||||
|
((v >> 5) & 1)); // ((Byte)v < 0xe8 ? 0 : 1));
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
const unsigned c = ((v + 0x17) >> 6) & 1;
|
||||||
|
prob = p->probs + (unsigned)
|
||||||
|
(((0 - c) & (Byte)(v >> NUM_SHIFT_BITS)) + c + ((v >> 5) & 1));
|
||||||
|
// (Byte)
|
||||||
|
// 8x->0 : e9->1 : xxe8->xx+2
|
||||||
|
// 8x->0x100 : e9->0x101 : xxe8->xx
|
||||||
|
// (((0x100 - (e & ~v)) & (0x100 | (v >> 8))) + (e & v));
|
||||||
|
// (((0x101 + (~e | v)) & (0x100 | (v >> 8))) + (e & v));
|
||||||
|
}
|
||||||
|
ttt = *prob;
|
||||||
|
bound = (p->range >> kNumBitModelTotalBits) * ttt;
|
||||||
|
if (p->code < bound)
|
||||||
|
{
|
||||||
|
// bcj2_stats[prob - p->probs][0]++;
|
||||||
|
p->range = bound;
|
||||||
|
*prob = (CBcj2Prob)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// bcj2_stats[prob - p->probs][1]++;
|
||||||
|
p->range -= bound;
|
||||||
|
p->code -= bound;
|
||||||
|
*prob = (CBcj2Prob)(ttt - (ttt >> kNumMoveBits));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
/* (v == 0xe8 ? 0 : 1) uses setcc instruction with additional zero register usage in x64 MSVC. */
|
||||||
|
// const unsigned cj = ((Byte)v == 0xe8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP;
|
||||||
|
const unsigned cj = (((v + 0x57) >> 6) & 1) + BCJ2_STREAM_CALL;
|
||||||
|
const Byte *cur = p->bufs[cj];
|
||||||
|
Byte *dest;
|
||||||
|
SizeT rem;
|
||||||
|
if (cur == p->lims[cj])
|
||||||
|
{
|
||||||
|
p->state = cj;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
v = GetBe32a(cur);
|
||||||
|
p->bufs[cj] = cur + 4;
|
||||||
|
{
|
||||||
|
const UInt32 ip = p->ip + 4;
|
||||||
|
v -= ip;
|
||||||
|
p->ip = ip;
|
||||||
|
}
|
||||||
|
dest = p->dest;
|
||||||
|
rem = (SizeT)(p->destLim - dest);
|
||||||
|
if (rem < 4)
|
||||||
|
{
|
||||||
|
if ((unsigned)rem > 0) { dest[0] = (Byte)v; v >>= 8;
|
||||||
|
if ((unsigned)rem > 1) { dest[1] = (Byte)v; v >>= 8;
|
||||||
|
if ((unsigned)rem > 2) { dest[2] = (Byte)v; v >>= 8; }}}
|
||||||
|
p->temp = v;
|
||||||
|
p->dest = dest + rem;
|
||||||
|
p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SetUi32(dest, v)
|
||||||
|
v >>= 24;
|
||||||
|
p->dest = dest + 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC])
|
||||||
|
{
|
||||||
|
p->range <<= 8;
|
||||||
|
p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
|
||||||
|
}
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef NUM_ITERS
|
||||||
|
#undef ONE_ITER
|
||||||
|
#undef NUM_SHIFT_BITS
|
||||||
|
#undef kTopValue
|
||||||
|
#undef kNumBitModelTotalBits
|
||||||
|
#undef kBitModelTotal
|
||||||
|
#undef kNumMoveBits
|
||||||
@@ -0,0 +1,332 @@
|
|||||||
|
/* Bcj2.h -- BCJ2 converter for x86 code (Branch CALL/JUMP variant2)
|
||||||
|
2023-03-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_BCJ2_H
|
||||||
|
#define ZIP7_INC_BCJ2_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
#define BCJ2_NUM_STREAMS 4
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
BCJ2_STREAM_MAIN,
|
||||||
|
BCJ2_STREAM_CALL,
|
||||||
|
BCJ2_STREAM_JUMP,
|
||||||
|
BCJ2_STREAM_RC
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
BCJ2_DEC_STATE_ORIG_0 = BCJ2_NUM_STREAMS,
|
||||||
|
BCJ2_DEC_STATE_ORIG_1,
|
||||||
|
BCJ2_DEC_STATE_ORIG_2,
|
||||||
|
BCJ2_DEC_STATE_ORIG_3,
|
||||||
|
|
||||||
|
BCJ2_DEC_STATE_ORIG,
|
||||||
|
BCJ2_DEC_STATE_ERROR /* after detected data error */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS,
|
||||||
|
BCJ2_ENC_STATE_FINISHED /* it's state after fully encoded stream */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* #define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP) */
|
||||||
|
#define BCJ2_IS_32BIT_STREAM(s) ((unsigned)((unsigned)(s) - (unsigned)BCJ2_STREAM_CALL) < 2)
|
||||||
|
|
||||||
|
/*
|
||||||
|
CBcj2Dec / CBcj2Enc
|
||||||
|
bufs sizes:
|
||||||
|
BUF_SIZE(n) = lims[n] - bufs[n]
|
||||||
|
bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be multiply of 4:
|
||||||
|
(BUF_SIZE(BCJ2_STREAM_CALL) & 3) == 0
|
||||||
|
(BUF_SIZE(BCJ2_STREAM_JUMP) & 3) == 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
// typedef UInt32 CBcj2Prob;
|
||||||
|
typedef UInt16 CBcj2Prob;
|
||||||
|
|
||||||
|
/*
|
||||||
|
BCJ2 encoder / decoder internal requirements:
|
||||||
|
- If last bytes of stream contain marker (e8/e8/0f8x), then
|
||||||
|
there is also encoded symbol (0 : no conversion) in RC stream.
|
||||||
|
- One case of overlapped instructions is supported,
|
||||||
|
if last byte of converted instruction is (0f) and next byte is (8x):
|
||||||
|
marker [xx xx xx 0f] 8x
|
||||||
|
then the pair (0f 8x) is treated as marker.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ---------- BCJ2 Decoder ---------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
CBcj2Dec:
|
||||||
|
(dest) is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following conditions:
|
||||||
|
bufs[BCJ2_STREAM_MAIN] >= dest &&
|
||||||
|
bufs[BCJ2_STREAM_MAIN] - dest >=
|
||||||
|
BUF_SIZE(BCJ2_STREAM_CALL) +
|
||||||
|
BUF_SIZE(BCJ2_STREAM_JUMP)
|
||||||
|
reserve = bufs[BCJ2_STREAM_MAIN] - dest -
|
||||||
|
( BUF_SIZE(BCJ2_STREAM_CALL) +
|
||||||
|
BUF_SIZE(BCJ2_STREAM_JUMP) )
|
||||||
|
and additional conditions:
|
||||||
|
if (it's first call of Bcj2Dec_Decode() after Bcj2Dec_Init())
|
||||||
|
{
|
||||||
|
(reserve != 1) : if (ver < v23.00)
|
||||||
|
}
|
||||||
|
else // if there are more than one calls of Bcj2Dec_Decode() after Bcj2Dec_Init())
|
||||||
|
{
|
||||||
|
(reserve >= 6) : if (ver < v23.00)
|
||||||
|
(reserve >= 4) : if (ver >= v23.00)
|
||||||
|
We need that (reserve) because after first call of Bcj2Dec_Decode(),
|
||||||
|
CBcj2Dec::temp can contain up to 4 bytes for writing to (dest).
|
||||||
|
}
|
||||||
|
(reserve == 0) is allowed, if we decode full stream via single call of Bcj2Dec_Decode().
|
||||||
|
(reserve == 0) also is allowed in case of multi-call, if we use fixed buffers,
|
||||||
|
and (reserve) is calculated from full (final) sizes of all streams before first call.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const Byte *bufs[BCJ2_NUM_STREAMS];
|
||||||
|
const Byte *lims[BCJ2_NUM_STREAMS];
|
||||||
|
Byte *dest;
|
||||||
|
const Byte *destLim;
|
||||||
|
|
||||||
|
unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */
|
||||||
|
|
||||||
|
UInt32 ip; /* property of starting base for decoding */
|
||||||
|
UInt32 temp; /* Byte temp[4]; */
|
||||||
|
UInt32 range;
|
||||||
|
UInt32 code;
|
||||||
|
CBcj2Prob probs[2 + 256];
|
||||||
|
} CBcj2Dec;
|
||||||
|
|
||||||
|
|
||||||
|
/* Note:
|
||||||
|
Bcj2Dec_Init() sets (CBcj2Dec::ip = 0)
|
||||||
|
if (ip != 0) property is required, the caller must set CBcj2Dec::ip after Bcj2Dec_Init()
|
||||||
|
*/
|
||||||
|
void Bcj2Dec_Init(CBcj2Dec *p);
|
||||||
|
|
||||||
|
|
||||||
|
/* Bcj2Dec_Decode():
|
||||||
|
returns:
|
||||||
|
SZ_OK
|
||||||
|
SZ_ERROR_DATA : if data in 5 starting bytes of BCJ2_STREAM_RC stream are not correct
|
||||||
|
*/
|
||||||
|
SRes Bcj2Dec_Decode(CBcj2Dec *p);
|
||||||
|
|
||||||
|
/* To check that decoding was finished you can compare
|
||||||
|
sizes of processed streams with sizes known from another sources.
|
||||||
|
You must do at least one mandatory check from the two following options:
|
||||||
|
- the check for size of processed output (ORIG) stream.
|
||||||
|
- the check for size of processed input (MAIN) stream.
|
||||||
|
additional optional checks:
|
||||||
|
- the checks for processed sizes of all input streams (MAIN, CALL, JUMP, RC)
|
||||||
|
- the checks Bcj2Dec_IsMaybeFinished*()
|
||||||
|
also before actual decoding you can check that the
|
||||||
|
following condition is met for stream sizes:
|
||||||
|
( size(ORIG) == size(MAIN) + size(CALL) + size(JUMP) )
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* (state == BCJ2_STREAM_MAIN) means that decoder is ready for
|
||||||
|
additional input data in BCJ2_STREAM_MAIN stream.
|
||||||
|
Note that (state == BCJ2_STREAM_MAIN) is allowed for non-finished decoding.
|
||||||
|
*/
|
||||||
|
#define Bcj2Dec_IsMaybeFinished_state_MAIN(_p_) ((_p_)->state == BCJ2_STREAM_MAIN)
|
||||||
|
|
||||||
|
/* if the stream decoding was finished correctly, then range decoder
|
||||||
|
part of CBcj2Dec also was finished, and then (CBcj2Dec::code == 0).
|
||||||
|
Note that (CBcj2Dec::code == 0) is allowed for non-finished decoding.
|
||||||
|
*/
|
||||||
|
#define Bcj2Dec_IsMaybeFinished_code(_p_) ((_p_)->code == 0)
|
||||||
|
|
||||||
|
/* use Bcj2Dec_IsMaybeFinished() only as additional check
|
||||||
|
after at least one mandatory check from the two following options:
|
||||||
|
- the check for size of processed output (ORIG) stream.
|
||||||
|
- the check for size of processed input (MAIN) stream.
|
||||||
|
*/
|
||||||
|
#define Bcj2Dec_IsMaybeFinished(_p_) ( \
|
||||||
|
Bcj2Dec_IsMaybeFinished_state_MAIN(_p_) && \
|
||||||
|
Bcj2Dec_IsMaybeFinished_code(_p_))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------- BCJ2 Encoder ---------- */
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
BCJ2_ENC_FINISH_MODE_CONTINUE,
|
||||||
|
BCJ2_ENC_FINISH_MODE_END_BLOCK,
|
||||||
|
BCJ2_ENC_FINISH_MODE_END_STREAM
|
||||||
|
} EBcj2Enc_FinishMode;
|
||||||
|
|
||||||
|
/*
|
||||||
|
BCJ2_ENC_FINISH_MODE_CONTINUE:
|
||||||
|
process non finished encoding.
|
||||||
|
It notifies the encoder that additional further calls
|
||||||
|
can provide more input data (src) than provided by current call.
|
||||||
|
In that case the CBcj2Enc encoder still can move (src) pointer
|
||||||
|
up to (srcLim), but CBcj2Enc encoder can store some of the last
|
||||||
|
processed bytes (up to 4 bytes) from src to internal CBcj2Enc::temp[] buffer.
|
||||||
|
at return:
|
||||||
|
(CBcj2Enc::src will point to position that includes
|
||||||
|
processed data and data copied to (temp[]) buffer)
|
||||||
|
That data from (temp[]) buffer will be used in further calls.
|
||||||
|
|
||||||
|
BCJ2_ENC_FINISH_MODE_END_BLOCK:
|
||||||
|
finish encoding of current block (ended at srcLim) without RC flushing.
|
||||||
|
at return: if (CBcj2Enc::state == BCJ2_ENC_STATE_ORIG) &&
|
||||||
|
CBcj2Enc::src == CBcj2Enc::srcLim)
|
||||||
|
: it shows that block encoding was finished. And the encoder is
|
||||||
|
ready for new (src) data or for stream finish operation.
|
||||||
|
finished block means
|
||||||
|
{
|
||||||
|
CBcj2Enc has completed block encoding up to (srcLim).
|
||||||
|
(1 + 4 bytes) or (2 + 4 bytes) CALL/JUMP cortages will
|
||||||
|
not cross block boundary at (srcLim).
|
||||||
|
temporary CBcj2Enc buffer for (ORIG) src data is empty.
|
||||||
|
3 output uncompressed streams (MAIN, CALL, JUMP) were flushed.
|
||||||
|
RC stream was not flushed. And RC stream will cross block boundary.
|
||||||
|
}
|
||||||
|
Note: some possible implementation of BCJ2 encoder could
|
||||||
|
write branch marker (e8/e8/0f8x) in one call of Bcj2Enc_Encode(),
|
||||||
|
and it could calculate symbol for RC in another call of Bcj2Enc_Encode().
|
||||||
|
BCJ2 encoder uses ip/fileIp/fileSize/relatLimit values to calculate RC symbol.
|
||||||
|
And these CBcj2Enc variables can have different values in different Bcj2Enc_Encode() calls.
|
||||||
|
So caller must finish each block with BCJ2_ENC_FINISH_MODE_END_BLOCK
|
||||||
|
to ensure that RC symbol is calculated and written in proper block.
|
||||||
|
|
||||||
|
BCJ2_ENC_FINISH_MODE_END_STREAM
|
||||||
|
finish encoding of stream (ended at srcLim) fully including RC flushing.
|
||||||
|
at return: if (CBcj2Enc::state == BCJ2_ENC_STATE_FINISHED)
|
||||||
|
: it shows that stream encoding was finished fully,
|
||||||
|
and all output streams were flushed fully.
|
||||||
|
also Bcj2Enc_IsFinished() can be called.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
32-bit relative offset in JUMP/CALL commands is
|
||||||
|
- (mod 4 GiB) for 32-bit x86 code
|
||||||
|
- signed Int32 for 64-bit x86-64 code
|
||||||
|
BCJ2 encoder also does internal relative to absolute address conversions.
|
||||||
|
And there are 2 possible ways to do it:
|
||||||
|
before v23: we used 32-bit variables and (mod 4 GiB) conversion
|
||||||
|
since v23: we use 64-bit variables and (signed Int32 offset) conversion.
|
||||||
|
The absolute address condition for conversion in v23:
|
||||||
|
((UInt64)((Int64)ip64 - (Int64)fileIp64 + 5 + (Int32)offset) < (UInt64)fileSize64)
|
||||||
|
note that if (fileSize64 > 2 GiB). there is difference between
|
||||||
|
old (mod 4 GiB) way (v22) and new (signed Int32 offset) way (v23).
|
||||||
|
And new (v23) way is more suitable to encode 64-bit x86-64 code for (fileSize64 > 2 GiB) cases.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
// for old (v22) way for conversion:
|
||||||
|
typedef UInt32 CBcj2Enc_ip_unsigned;
|
||||||
|
typedef Int32 CBcj2Enc_ip_signed;
|
||||||
|
#define BCJ2_ENC_FileSize_MAX ((UInt32)1 << 31)
|
||||||
|
*/
|
||||||
|
typedef UInt64 CBcj2Enc_ip_unsigned;
|
||||||
|
typedef Int64 CBcj2Enc_ip_signed;
|
||||||
|
|
||||||
|
/* maximum size of file that can be used for conversion condition */
|
||||||
|
#define BCJ2_ENC_FileSize_MAX ((CBcj2Enc_ip_unsigned)0 - 2)
|
||||||
|
|
||||||
|
/* default value of fileSize64_minus1 variable that means
|
||||||
|
that absolute address limitation will not be used */
|
||||||
|
#define BCJ2_ENC_FileSizeField_UNLIMITED ((CBcj2Enc_ip_unsigned)0 - 1)
|
||||||
|
|
||||||
|
/* calculate value that later can be set to CBcj2Enc::fileSize64_minus1 */
|
||||||
|
#define BCJ2_ENC_GET_FileSizeField_VAL_FROM_FileSize(fileSize) \
|
||||||
|
((CBcj2Enc_ip_unsigned)(fileSize) - 1)
|
||||||
|
|
||||||
|
/* set CBcj2Enc::fileSize64_minus1 variable from size of file */
|
||||||
|
#define Bcj2Enc_SET_FileSize(p, fileSize) \
|
||||||
|
(p)->fileSize64_minus1 = BCJ2_ENC_GET_FileSizeField_VAL_FROM_FileSize(fileSize);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Byte *bufs[BCJ2_NUM_STREAMS];
|
||||||
|
const Byte *lims[BCJ2_NUM_STREAMS];
|
||||||
|
const Byte *src;
|
||||||
|
const Byte *srcLim;
|
||||||
|
|
||||||
|
unsigned state;
|
||||||
|
EBcj2Enc_FinishMode finishMode;
|
||||||
|
|
||||||
|
Byte context;
|
||||||
|
Byte flushRem;
|
||||||
|
Byte isFlushState;
|
||||||
|
|
||||||
|
Byte cache;
|
||||||
|
UInt32 range;
|
||||||
|
UInt64 low;
|
||||||
|
UInt64 cacheSize;
|
||||||
|
|
||||||
|
// UInt32 context; // for marker version, it can include marker flag.
|
||||||
|
|
||||||
|
/* (ip64) and (fileIp64) correspond to virtual source stream position
|
||||||
|
that doesn't include data in temp[] */
|
||||||
|
CBcj2Enc_ip_unsigned ip64; /* current (ip) position */
|
||||||
|
CBcj2Enc_ip_unsigned fileIp64; /* start (ip) position of current file */
|
||||||
|
CBcj2Enc_ip_unsigned fileSize64_minus1; /* size of current file (for conversion limitation) */
|
||||||
|
UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)) : 0 means disable_conversion */
|
||||||
|
// UInt32 relatExcludeBits;
|
||||||
|
|
||||||
|
UInt32 tempTarget;
|
||||||
|
unsigned tempPos; /* the number of bytes that were copied to temp[] buffer
|
||||||
|
(tempPos <= 4) outside of Bcj2Enc_Encode() */
|
||||||
|
// Byte temp[4]; // for marker version
|
||||||
|
Byte temp[8];
|
||||||
|
CBcj2Prob probs[2 + 256];
|
||||||
|
} CBcj2Enc;
|
||||||
|
|
||||||
|
void Bcj2Enc_Init(CBcj2Enc *p);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Bcj2Enc_Encode(): at exit:
|
||||||
|
p->State < BCJ2_NUM_STREAMS : we need more buffer space for output stream
|
||||||
|
(bufs[p->State] == lims[p->State])
|
||||||
|
p->State == BCJ2_ENC_STATE_ORIG : we need more data in input src stream
|
||||||
|
(src == srcLim)
|
||||||
|
p->State == BCJ2_ENC_STATE_FINISHED : after fully encoded stream
|
||||||
|
*/
|
||||||
|
void Bcj2Enc_Encode(CBcj2Enc *p);
|
||||||
|
|
||||||
|
/* Bcj2Enc encoder can look ahead for up 4 bytes of source stream.
|
||||||
|
CBcj2Enc::tempPos : is the number of bytes that were copied from input stream to temp[] buffer.
|
||||||
|
(CBcj2Enc::src) after Bcj2Enc_Encode() is starting position after
|
||||||
|
fully processed data and after data copied to temp buffer.
|
||||||
|
So if the caller needs to get real number of fully processed input
|
||||||
|
bytes (without look ahead data in temp buffer),
|
||||||
|
the caller must subtruct (CBcj2Enc::tempPos) value from processed size
|
||||||
|
value that is calculated based on current (CBcj2Enc::src):
|
||||||
|
cur_processed_pos = Calc_Big_Processed_Pos(enc.src)) -
|
||||||
|
Bcj2Enc_Get_AvailInputSize_in_Temp(&enc);
|
||||||
|
*/
|
||||||
|
/* get the size of input data that was stored in temp[] buffer: */
|
||||||
|
#define Bcj2Enc_Get_AvailInputSize_in_Temp(p) ((p)->tempPos)
|
||||||
|
|
||||||
|
#define Bcj2Enc_IsFinished(p) ((p)->flushRem == 0)
|
||||||
|
|
||||||
|
/* Note : the decoder supports overlapping of marker (0f 80).
|
||||||
|
But we can eliminate such overlapping cases by setting
|
||||||
|
the limit for relative offset conversion as
|
||||||
|
CBcj2Enc::relatLimit <= (0x0f << 24) == (240 MiB)
|
||||||
|
*/
|
||||||
|
/* default value for CBcj2Enc::relatLimit */
|
||||||
|
#define BCJ2_ENC_RELAT_LIMIT_DEFAULT ((UInt32)0x0f << 24)
|
||||||
|
#define BCJ2_ENC_RELAT_LIMIT_MAX ((UInt32)1 << 31)
|
||||||
|
// #define BCJ2_RELAT_EXCLUDE_NUM_BITS 5
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,420 @@
|
|||||||
|
/* Bra.c -- Branch converters for RISC code
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#include "Precomp.h"
|
||||||
|
|
||||||
|
#include "Bra.h"
|
||||||
|
#include "CpuArch.h"
|
||||||
|
#include "RotateDefs.h"
|
||||||
|
|
||||||
|
#if defined(MY_CPU_SIZEOF_POINTER) \
|
||||||
|
&& ( MY_CPU_SIZEOF_POINTER == 4 \
|
||||||
|
|| MY_CPU_SIZEOF_POINTER == 8)
|
||||||
|
#define BR_CONV_USE_OPT_PC_PTR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BR_CONV_USE_OPT_PC_PTR
|
||||||
|
#define BR_PC_INIT pc -= (UInt32)(SizeT)p;
|
||||||
|
#define BR_PC_GET (pc + (UInt32)(SizeT)p)
|
||||||
|
#else
|
||||||
|
#define BR_PC_INIT pc += (UInt32)size;
|
||||||
|
#define BR_PC_GET (pc - (UInt32)(SizeT)(lim - p))
|
||||||
|
// #define BR_PC_INIT
|
||||||
|
// #define BR_PC_GET (pc + (UInt32)(SizeT)(p - data))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BR_CONVERT_VAL(v, c) if (encoding) v += c; else v -= c;
|
||||||
|
// #define BR_CONVERT_VAL(v, c) if (!encoding) c = (UInt32)0 - c; v += c;
|
||||||
|
|
||||||
|
#define Z7_BRANCH_CONV(name) z7_BranchConv_ ## name
|
||||||
|
|
||||||
|
#define Z7_BRANCH_FUNC_MAIN(name) \
|
||||||
|
static \
|
||||||
|
Z7_FORCE_INLINE \
|
||||||
|
Z7_ATTRIB_NO_VECTOR \
|
||||||
|
Byte *Z7_BRANCH_CONV(name)(Byte *p, SizeT size, UInt32 pc, int encoding)
|
||||||
|
|
||||||
|
#define Z7_BRANCH_FUNC_IMP(name, m, encoding) \
|
||||||
|
Z7_NO_INLINE \
|
||||||
|
Z7_ATTRIB_NO_VECTOR \
|
||||||
|
Byte *m(name)(Byte *data, SizeT size, UInt32 pc) \
|
||||||
|
{ return Z7_BRANCH_CONV(name)(data, size, pc, encoding); } \
|
||||||
|
|
||||||
|
#ifdef Z7_EXTRACT_ONLY
|
||||||
|
#define Z7_BRANCH_FUNCS_IMP(name) \
|
||||||
|
Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_DEC, 0)
|
||||||
|
#else
|
||||||
|
#define Z7_BRANCH_FUNCS_IMP(name) \
|
||||||
|
Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_DEC, 0) \
|
||||||
|
Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_ENC, 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#define BR_EXTERNAL_FOR
|
||||||
|
#define BR_NEXT_ITERATION continue;
|
||||||
|
#else
|
||||||
|
#define BR_EXTERNAL_FOR for (;;)
|
||||||
|
#define BR_NEXT_ITERATION break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__clang__) && (__clang_major__ >= 8) \
|
||||||
|
|| defined(__GNUC__) && (__GNUC__ >= 1000) \
|
||||||
|
// GCC is not good for __builtin_expect() here
|
||||||
|
/* || defined(_MSC_VER) && (_MSC_VER >= 1920) */
|
||||||
|
// #define Z7_unlikely [[unlikely]]
|
||||||
|
// #define Z7_LIKELY(x) (__builtin_expect((x), 1))
|
||||||
|
#define Z7_UNLIKELY(x) (__builtin_expect((x), 0))
|
||||||
|
// #define Z7_likely [[likely]]
|
||||||
|
#else
|
||||||
|
// #define Z7_LIKELY(x) (x)
|
||||||
|
#define Z7_UNLIKELY(x) (x)
|
||||||
|
// #define Z7_likely
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
Z7_BRANCH_FUNC_MAIN(ARM64)
|
||||||
|
{
|
||||||
|
// Byte *p = data;
|
||||||
|
const Byte *lim;
|
||||||
|
const UInt32 flag = (UInt32)1 << (24 - 4);
|
||||||
|
const UInt32 mask = ((UInt32)1 << 24) - (flag << 1);
|
||||||
|
size &= ~(SizeT)3;
|
||||||
|
// if (size == 0) return p;
|
||||||
|
lim = p + size;
|
||||||
|
BR_PC_INIT
|
||||||
|
pc -= 4; // because (p) will point to next instruction
|
||||||
|
|
||||||
|
BR_EXTERNAL_FOR
|
||||||
|
{
|
||||||
|
// Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
UInt32 v;
|
||||||
|
if Z7_UNLIKELY(p == lim)
|
||||||
|
return p;
|
||||||
|
v = GetUi32a(p);
|
||||||
|
p += 4;
|
||||||
|
if Z7_UNLIKELY(((v - 0x94000000) & 0xfc000000) == 0)
|
||||||
|
{
|
||||||
|
UInt32 c = BR_PC_GET >> 2;
|
||||||
|
BR_CONVERT_VAL(v, c)
|
||||||
|
v &= 0x03ffffff;
|
||||||
|
v |= 0x94000000;
|
||||||
|
SetUi32a(p - 4, v)
|
||||||
|
BR_NEXT_ITERATION
|
||||||
|
}
|
||||||
|
// v = rotlFixed(v, 8); v += (flag << 8) - 0x90; if Z7_UNLIKELY((v & ((mask << 8) + 0x9f)) == 0)
|
||||||
|
v -= 0x90000000; if Z7_UNLIKELY((v & 0x9f000000) == 0)
|
||||||
|
{
|
||||||
|
UInt32 z, c;
|
||||||
|
// v = rotrFixed(v, 8);
|
||||||
|
v += flag; if Z7_UNLIKELY(v & mask) continue;
|
||||||
|
z = (v & 0xffffffe0) | (v >> 26);
|
||||||
|
c = (BR_PC_GET >> (12 - 3)) & ~(UInt32)7;
|
||||||
|
BR_CONVERT_VAL(z, c)
|
||||||
|
v &= 0x1f;
|
||||||
|
v |= 0x90000000;
|
||||||
|
v |= z << 26;
|
||||||
|
v |= 0x00ffffe0 & ((z & (((flag << 1) - 1))) - flag);
|
||||||
|
SetUi32a(p - 4, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Z7_BRANCH_FUNCS_IMP(ARM64)
|
||||||
|
|
||||||
|
|
||||||
|
Z7_BRANCH_FUNC_MAIN(ARM)
|
||||||
|
{
|
||||||
|
// Byte *p = data;
|
||||||
|
const Byte *lim;
|
||||||
|
size &= ~(SizeT)3;
|
||||||
|
lim = p + size;
|
||||||
|
BR_PC_INIT
|
||||||
|
/* in ARM: branch offset is relative to the +2 instructions from current instruction.
|
||||||
|
(p) will point to next instruction */
|
||||||
|
pc += 8 - 4;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if Z7_UNLIKELY(p >= lim) { return p; } p += 4; if Z7_UNLIKELY(p[-1] == 0xeb) break;
|
||||||
|
if Z7_UNLIKELY(p >= lim) { return p; } p += 4; if Z7_UNLIKELY(p[-1] == 0xeb) break;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
UInt32 v = GetUi32a(p - 4);
|
||||||
|
UInt32 c = BR_PC_GET >> 2;
|
||||||
|
BR_CONVERT_VAL(v, c)
|
||||||
|
v &= 0x00ffffff;
|
||||||
|
v |= 0xeb000000;
|
||||||
|
SetUi32a(p - 4, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Z7_BRANCH_FUNCS_IMP(ARM)
|
||||||
|
|
||||||
|
|
||||||
|
Z7_BRANCH_FUNC_MAIN(PPC)
|
||||||
|
{
|
||||||
|
// Byte *p = data;
|
||||||
|
const Byte *lim;
|
||||||
|
size &= ~(SizeT)3;
|
||||||
|
lim = p + size;
|
||||||
|
BR_PC_INIT
|
||||||
|
pc -= 4; // because (p) will point to next instruction
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
UInt32 v;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if Z7_UNLIKELY(p == lim)
|
||||||
|
return p;
|
||||||
|
// v = GetBe32a(p);
|
||||||
|
v = *(UInt32 *)(void *)p;
|
||||||
|
p += 4;
|
||||||
|
// if ((v & 0xfc000003) == 0x48000001) break;
|
||||||
|
// if ((p[-4] & 0xFC) == 0x48 && (p[-1] & 3) == 1) break;
|
||||||
|
if Z7_UNLIKELY(
|
||||||
|
((v - Z7_CONV_BE_TO_NATIVE_CONST32(0x48000001))
|
||||||
|
& Z7_CONV_BE_TO_NATIVE_CONST32(0xfc000003)) == 0) break;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
v = Z7_CONV_NATIVE_TO_BE_32(v);
|
||||||
|
{
|
||||||
|
UInt32 c = BR_PC_GET;
|
||||||
|
BR_CONVERT_VAL(v, c)
|
||||||
|
}
|
||||||
|
v &= 0x03ffffff;
|
||||||
|
v |= 0x48000000;
|
||||||
|
SetBe32a(p - 4, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Z7_BRANCH_FUNCS_IMP(PPC)
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef Z7_CPU_FAST_ROTATE_SUPPORTED
|
||||||
|
#define BR_SPARC_USE_ROTATE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Z7_BRANCH_FUNC_MAIN(SPARC)
|
||||||
|
{
|
||||||
|
// Byte *p = data;
|
||||||
|
const Byte *lim;
|
||||||
|
const UInt32 flag = (UInt32)1 << 22;
|
||||||
|
size &= ~(SizeT)3;
|
||||||
|
lim = p + size;
|
||||||
|
BR_PC_INIT
|
||||||
|
pc -= 4; // because (p) will point to next instruction
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
UInt32 v;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if Z7_UNLIKELY(p == lim)
|
||||||
|
return p;
|
||||||
|
/* // the code without GetBe32a():
|
||||||
|
{ const UInt32 v = GetUi16a(p) & 0xc0ff; p += 4; if (v == 0x40 || v == 0xc07f) break; }
|
||||||
|
*/
|
||||||
|
v = GetBe32a(p);
|
||||||
|
p += 4;
|
||||||
|
#ifdef BR_SPARC_USE_ROTATE
|
||||||
|
v = rotlFixed(v, 2);
|
||||||
|
v += (flag << 2) - 1;
|
||||||
|
if Z7_UNLIKELY((v & (3 - (flag << 3))) == 0)
|
||||||
|
#else
|
||||||
|
v += (UInt32)5 << 29;
|
||||||
|
v ^= (UInt32)7 << 29;
|
||||||
|
v += flag;
|
||||||
|
if Z7_UNLIKELY((v & (0 - (flag << 1))) == 0)
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// UInt32 v = GetBe32a(p - 4);
|
||||||
|
#ifndef BR_SPARC_USE_ROTATE
|
||||||
|
v <<= 2;
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
UInt32 c = BR_PC_GET;
|
||||||
|
BR_CONVERT_VAL(v, c)
|
||||||
|
}
|
||||||
|
v &= (flag << 3) - 1;
|
||||||
|
#ifdef BR_SPARC_USE_ROTATE
|
||||||
|
v -= (flag << 2) - 1;
|
||||||
|
v = rotrFixed(v, 2);
|
||||||
|
#else
|
||||||
|
v -= (flag << 2);
|
||||||
|
v >>= 2;
|
||||||
|
v |= (UInt32)1 << 30;
|
||||||
|
#endif
|
||||||
|
SetBe32a(p - 4, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Z7_BRANCH_FUNCS_IMP(SPARC)
|
||||||
|
|
||||||
|
|
||||||
|
Z7_BRANCH_FUNC_MAIN(ARMT)
|
||||||
|
{
|
||||||
|
// Byte *p = data;
|
||||||
|
Byte *lim;
|
||||||
|
size &= ~(SizeT)1;
|
||||||
|
// if (size == 0) return p;
|
||||||
|
if (size <= 2) return p;
|
||||||
|
size -= 2;
|
||||||
|
lim = p + size;
|
||||||
|
BR_PC_INIT
|
||||||
|
/* in ARM: branch offset is relative to the +2 instructions from current instruction.
|
||||||
|
(p) will point to the +2 instructions from current instruction */
|
||||||
|
// pc += 4 - 4;
|
||||||
|
// if (encoding) pc -= 0xf800 << 1; else pc += 0xf800 << 1;
|
||||||
|
// #define ARMT_TAIL_PROC { goto armt_tail; }
|
||||||
|
#define ARMT_TAIL_PROC { return p; }
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* in MSVC 32-bit x86 compilers:
|
||||||
|
UInt32 version : it loads value from memory with movzx
|
||||||
|
Byte version : it loads value to 8-bit register (AL/CL)
|
||||||
|
movzx version is slightly faster in some cpus
|
||||||
|
*/
|
||||||
|
unsigned b1;
|
||||||
|
// Byte / unsigned
|
||||||
|
b1 = p[1];
|
||||||
|
// optimized version to reduce one (p >= lim) check:
|
||||||
|
// unsigned a1 = p[1]; b1 = p[3]; p += 2; if Z7_LIKELY((b1 & (a1 ^ 8)) < 0xf8)
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
unsigned b3; // Byte / UInt32
|
||||||
|
/* (Byte)(b3) normalization can use low byte computations in MSVC.
|
||||||
|
It gives smaller code, and no loss of speed in some compilers/cpus.
|
||||||
|
But new MSVC 32-bit x86 compilers use more slow load
|
||||||
|
from memory to low byte register in that case.
|
||||||
|
So we try to use full 32-bit computations for faster code.
|
||||||
|
*/
|
||||||
|
// if (p >= lim) { ARMT_TAIL_PROC } b3 = b1 + 8; b1 = p[3]; p += 2; if ((b3 & b1) >= 0xf8) break;
|
||||||
|
if Z7_UNLIKELY(p >= lim) { ARMT_TAIL_PROC } b3 = p[3]; p += 2; if Z7_UNLIKELY((b3 & (b1 ^ 8)) >= 0xf8) break;
|
||||||
|
if Z7_UNLIKELY(p >= lim) { ARMT_TAIL_PROC } b1 = p[3]; p += 2; if Z7_UNLIKELY((b1 & (b3 ^ 8)) >= 0xf8) break;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
/* we can adjust pc for (0xf800) to rid of (& 0x7FF) operation.
|
||||||
|
But gcc/clang for arm64 can use bfi instruction for full code here */
|
||||||
|
UInt32 v =
|
||||||
|
((UInt32)GetUi16a(p - 2) << 11) |
|
||||||
|
((UInt32)GetUi16a(p) & 0x7FF);
|
||||||
|
/*
|
||||||
|
UInt32 v =
|
||||||
|
((UInt32)p[1 - 2] << 19)
|
||||||
|
+ (((UInt32)p[1] & 0x7) << 8)
|
||||||
|
+ (((UInt32)p[-2] << 11))
|
||||||
|
+ (p[0]);
|
||||||
|
*/
|
||||||
|
p += 2;
|
||||||
|
{
|
||||||
|
UInt32 c = BR_PC_GET >> 1;
|
||||||
|
BR_CONVERT_VAL(v, c)
|
||||||
|
}
|
||||||
|
SetUi16a(p - 4, (UInt16)(((v >> 11) & 0x7ff) | 0xf000))
|
||||||
|
SetUi16a(p - 2, (UInt16)(v | 0xf800))
|
||||||
|
/*
|
||||||
|
p[-4] = (Byte)(v >> 11);
|
||||||
|
p[-3] = (Byte)(0xf0 | ((v >> 19) & 0x7));
|
||||||
|
p[-2] = (Byte)v;
|
||||||
|
p[-1] = (Byte)(0xf8 | (v >> 8));
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (p < lim);
|
||||||
|
return p;
|
||||||
|
// armt_tail:
|
||||||
|
// if ((Byte)((lim[1] & 0xf8)) != 0xf0) { lim += 2; } return lim;
|
||||||
|
// return (Byte *)(lim + ((Byte)((lim[1] ^ 0xf0) & 0xf8) == 0 ? 0 : 2));
|
||||||
|
// return (Byte *)(lim + (((lim[1] ^ ~0xfu) & ~7u) == 0 ? 0 : 2));
|
||||||
|
// return (Byte *)(lim + 2 - (((((unsigned)lim[1] ^ 8) + 8) >> 7) & 2));
|
||||||
|
}
|
||||||
|
Z7_BRANCH_FUNCS_IMP(ARMT)
|
||||||
|
|
||||||
|
|
||||||
|
// #define BR_IA64_NO_INLINE
|
||||||
|
|
||||||
|
Z7_BRANCH_FUNC_MAIN(IA64)
|
||||||
|
{
|
||||||
|
// Byte *p = data;
|
||||||
|
const Byte *lim;
|
||||||
|
size &= ~(SizeT)15;
|
||||||
|
lim = p + size;
|
||||||
|
pc -= 1 << 4;
|
||||||
|
pc >>= 4 - 1;
|
||||||
|
// pc -= 1 << 1;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
unsigned m;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if Z7_UNLIKELY(p == lim)
|
||||||
|
return p;
|
||||||
|
m = (unsigned)((UInt32)0x334b0000 >> (*p & 0x1e));
|
||||||
|
p += 16;
|
||||||
|
pc += 1 << 1;
|
||||||
|
if (m &= 3)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
p += (ptrdiff_t)m * 5 - 20; // negative value is expected here.
|
||||||
|
do
|
||||||
|
{
|
||||||
|
const UInt32 t =
|
||||||
|
#if defined(MY_CPU_X86_OR_AMD64)
|
||||||
|
// we use 32-bit load here to reduce code size on x86:
|
||||||
|
GetUi32(p);
|
||||||
|
#else
|
||||||
|
GetUi16(p);
|
||||||
|
#endif
|
||||||
|
UInt32 z = GetUi32(p + 1) >> m;
|
||||||
|
p += 5;
|
||||||
|
if (((t >> m) & (0x70 << 1)) == 0
|
||||||
|
&& ((z - (0x5000000 << 1)) & (0xf000000 << 1)) == 0)
|
||||||
|
{
|
||||||
|
UInt32 v = (UInt32)((0x8fffff << 1) | 1) & z;
|
||||||
|
z ^= v;
|
||||||
|
#ifdef BR_IA64_NO_INLINE
|
||||||
|
v |= (v & ((UInt32)1 << (23 + 1))) >> 3;
|
||||||
|
{
|
||||||
|
UInt32 c = pc;
|
||||||
|
BR_CONVERT_VAL(v, c)
|
||||||
|
}
|
||||||
|
v &= (0x1fffff << 1) | 1;
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
if (encoding)
|
||||||
|
{
|
||||||
|
// pc &= ~(0xc00000 << 1); // we just need to clear at least 2 bits
|
||||||
|
pc &= (0x1fffff << 1) | 1;
|
||||||
|
v += pc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// pc |= 0xc00000 << 1; // we need to set at least 2 bits
|
||||||
|
pc |= ~(UInt32)((0x1fffff << 1) | 1);
|
||||||
|
v -= pc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v &= ~(UInt32)(0x600000 << 1);
|
||||||
|
#endif
|
||||||
|
v += (0x700000 << 1);
|
||||||
|
v &= (0x8fffff << 1) | 1;
|
||||||
|
z |= v;
|
||||||
|
z <<= m;
|
||||||
|
SetUi32(p + 1 - 5, z)
|
||||||
|
}
|
||||||
|
m++;
|
||||||
|
}
|
||||||
|
while (m &= 3); // while (m < 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Z7_BRANCH_FUNCS_IMP(IA64)
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
/* Bra.h -- Branch converters for executables
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_BRA_H
|
||||||
|
#define ZIP7_INC_BRA_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
#define Z7_BRANCH_CONV_DEC(name) z7_BranchConv_ ## name ## _Dec
|
||||||
|
#define Z7_BRANCH_CONV_ENC(name) z7_BranchConv_ ## name ## _Enc
|
||||||
|
#define Z7_BRANCH_CONV_ST_DEC(name) z7_BranchConvSt_ ## name ## _Dec
|
||||||
|
#define Z7_BRANCH_CONV_ST_ENC(name) z7_BranchConvSt_ ## name ## _Enc
|
||||||
|
|
||||||
|
#define Z7_BRANCH_CONV_DECL(name) Byte * name(Byte *data, SizeT size, UInt32 pc)
|
||||||
|
#define Z7_BRANCH_CONV_ST_DECL(name) Byte * name(Byte *data, SizeT size, UInt32 pc, UInt32 *state)
|
||||||
|
|
||||||
|
typedef Z7_BRANCH_CONV_DECL( (*z7_Func_BranchConv));
|
||||||
|
typedef Z7_BRANCH_CONV_ST_DECL((*z7_Func_BranchConvSt));
|
||||||
|
|
||||||
|
#define Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL 0
|
||||||
|
Z7_BRANCH_CONV_ST_DECL(Z7_BRANCH_CONV_ST_DEC(X86));
|
||||||
|
Z7_BRANCH_CONV_ST_DECL(Z7_BRANCH_CONV_ST_ENC(X86));
|
||||||
|
|
||||||
|
#define Z7_BRANCH_FUNCS_DECL(name) \
|
||||||
|
Z7_BRANCH_CONV_DECL(Z7_BRANCH_CONV_DEC(name)); \
|
||||||
|
Z7_BRANCH_CONV_DECL(Z7_BRANCH_CONV_ENC(name));
|
||||||
|
|
||||||
|
Z7_BRANCH_FUNCS_DECL(ARM64)
|
||||||
|
Z7_BRANCH_FUNCS_DECL(ARM)
|
||||||
|
Z7_BRANCH_FUNCS_DECL(ARMT)
|
||||||
|
Z7_BRANCH_FUNCS_DECL(PPC)
|
||||||
|
Z7_BRANCH_FUNCS_DECL(SPARC)
|
||||||
|
Z7_BRANCH_FUNCS_DECL(IA64)
|
||||||
|
|
||||||
|
/*
|
||||||
|
These functions convert data that contain CPU instructions.
|
||||||
|
Each such function converts relative addresses to absolute addresses in some
|
||||||
|
branch instructions: CALL (in all converters) and JUMP (X86 converter only).
|
||||||
|
Such conversion allows to increase compression ratio, if we compress that data.
|
||||||
|
|
||||||
|
There are 2 types of converters:
|
||||||
|
Byte * Conv_RISC (Byte *data, SizeT size, UInt32 pc);
|
||||||
|
Byte * ConvSt_X86(Byte *data, SizeT size, UInt32 pc, UInt32 *state);
|
||||||
|
Each Converter supports 2 versions: one for encoding
|
||||||
|
and one for decoding (_Enc/_Dec postfixes in function name).
|
||||||
|
|
||||||
|
In params:
|
||||||
|
data : data buffer
|
||||||
|
size : size of data
|
||||||
|
pc : current virtual Program Counter (Instruction Pinter) value
|
||||||
|
In/Out param:
|
||||||
|
state : pointer to state variable (for X86 converter only)
|
||||||
|
|
||||||
|
Return:
|
||||||
|
The pointer to position in (data) buffer after last byte that was processed.
|
||||||
|
If the caller calls converter again, it must call it starting with that position.
|
||||||
|
But the caller is allowed to move data in buffer. so pointer to
|
||||||
|
current processed position also will be changed for next call.
|
||||||
|
Also the caller must increase internal (pc) value for next call.
|
||||||
|
|
||||||
|
Each converter has some characteristics: Endian, Alignment, LookAhead.
|
||||||
|
Type Endian Alignment LookAhead
|
||||||
|
|
||||||
|
X86 little 1 4
|
||||||
|
ARMT little 2 2
|
||||||
|
ARM little 4 0
|
||||||
|
ARM64 little 4 0
|
||||||
|
PPC big 4 0
|
||||||
|
SPARC big 4 0
|
||||||
|
IA64 little 16 0
|
||||||
|
|
||||||
|
(data) must be aligned for (Alignment).
|
||||||
|
processed size can be calculated as:
|
||||||
|
SizeT processed = Conv(data, size, pc) - data;
|
||||||
|
if (processed == 0)
|
||||||
|
it means that converter needs more data for processing.
|
||||||
|
If (size < Alignment + LookAhead)
|
||||||
|
then (processed == 0) is allowed.
|
||||||
|
|
||||||
|
Example code for conversion in loop:
|
||||||
|
UInt32 pc = 0;
|
||||||
|
size = 0;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
size += Load_more_input_data(data + size);
|
||||||
|
SizeT processed = Conv(data, size, pc) - data;
|
||||||
|
if (processed == 0 && no_more_input_data_after_size)
|
||||||
|
break; // we stop convert loop
|
||||||
|
data += processed;
|
||||||
|
size -= processed;
|
||||||
|
pc += processed;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
/* Bra86.c -- Branch converter for X86 code (BCJ)
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#include "Precomp.h"
|
||||||
|
|
||||||
|
#include "Bra.h"
|
||||||
|
#include "CpuArch.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(MY_CPU_SIZEOF_POINTER) \
|
||||||
|
&& ( MY_CPU_SIZEOF_POINTER == 4 \
|
||||||
|
|| MY_CPU_SIZEOF_POINTER == 8)
|
||||||
|
#define BR_CONV_USE_OPT_PC_PTR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BR_CONV_USE_OPT_PC_PTR
|
||||||
|
#define BR_PC_INIT pc -= (UInt32)(SizeT)p; // (MY_uintptr_t)
|
||||||
|
#define BR_PC_GET (pc + (UInt32)(SizeT)p)
|
||||||
|
#else
|
||||||
|
#define BR_PC_INIT pc += (UInt32)size;
|
||||||
|
#define BR_PC_GET (pc - (UInt32)(SizeT)(lim - p))
|
||||||
|
// #define BR_PC_INIT
|
||||||
|
// #define BR_PC_GET (pc + (UInt32)(SizeT)(p - data))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BR_CONVERT_VAL(v, c) if (encoding) v += c; else v -= c;
|
||||||
|
// #define BR_CONVERT_VAL(v, c) if (!encoding) c = (UInt32)0 - c; v += c;
|
||||||
|
|
||||||
|
#define Z7_BRANCH_CONV_ST(name) z7_BranchConvSt_ ## name
|
||||||
|
|
||||||
|
#define BR86_NEED_CONV_FOR_MS_BYTE(b) ((((b) + 1) & 0xfe) == 0)
|
||||||
|
|
||||||
|
#ifdef MY_CPU_LE_UNALIGN
|
||||||
|
#define BR86_PREPARE_BCJ_SCAN const UInt32 v = GetUi32(p) ^ 0xe8e8e8e8;
|
||||||
|
#define BR86_IS_BCJ_BYTE(n) ((v & ((UInt32)0xfe << (n) * 8)) == 0)
|
||||||
|
#else
|
||||||
|
#define BR86_PREPARE_BCJ_SCAN
|
||||||
|
// bad for MSVC X86 (partial write to byte reg):
|
||||||
|
#define BR86_IS_BCJ_BYTE(n) ((p[n - 4] & 0xfe) == 0xe8)
|
||||||
|
// bad for old MSVC (partial write to byte reg):
|
||||||
|
// #define BR86_IS_BCJ_BYTE(n) (((*p ^ 0xe8) & 0xfe) == 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static
|
||||||
|
Z7_FORCE_INLINE
|
||||||
|
Z7_ATTRIB_NO_VECTOR
|
||||||
|
Byte *Z7_BRANCH_CONV_ST(X86)(Byte *p, SizeT size, UInt32 pc, UInt32 *state, int encoding)
|
||||||
|
{
|
||||||
|
if (size < 5)
|
||||||
|
return p;
|
||||||
|
{
|
||||||
|
// Byte *p = data;
|
||||||
|
const Byte *lim = p + size - 4;
|
||||||
|
unsigned mask = (unsigned)*state; // & 7;
|
||||||
|
#ifdef BR_CONV_USE_OPT_PC_PTR
|
||||||
|
/* if BR_CONV_USE_OPT_PC_PTR is defined: we need to adjust (pc) for (+4),
|
||||||
|
because call/jump offset is relative to the next instruction.
|
||||||
|
if BR_CONV_USE_OPT_PC_PTR is not defined : we don't need to adjust (pc) for (+4),
|
||||||
|
because BR_PC_GET uses (pc - (lim - p)), and lim was adjusted for (-4) before.
|
||||||
|
*/
|
||||||
|
pc += 4;
|
||||||
|
#endif
|
||||||
|
BR_PC_INIT
|
||||||
|
goto start;
|
||||||
|
|
||||||
|
for (;; mask |= 4)
|
||||||
|
{
|
||||||
|
// cont: mask |= 4;
|
||||||
|
start:
|
||||||
|
if (p >= lim)
|
||||||
|
goto fin;
|
||||||
|
{
|
||||||
|
BR86_PREPARE_BCJ_SCAN
|
||||||
|
p += 4;
|
||||||
|
if (BR86_IS_BCJ_BYTE(0)) { goto m0; } mask >>= 1;
|
||||||
|
if (BR86_IS_BCJ_BYTE(1)) { goto m1; } mask >>= 1;
|
||||||
|
if (BR86_IS_BCJ_BYTE(2)) { goto m2; } mask = 0;
|
||||||
|
if (BR86_IS_BCJ_BYTE(3)) { goto a3; }
|
||||||
|
}
|
||||||
|
goto main_loop;
|
||||||
|
|
||||||
|
m0: p--;
|
||||||
|
m1: p--;
|
||||||
|
m2: p--;
|
||||||
|
if (mask == 0)
|
||||||
|
goto a3;
|
||||||
|
if (p > lim)
|
||||||
|
goto fin_p;
|
||||||
|
|
||||||
|
// if (((0x17u >> mask) & 1) == 0)
|
||||||
|
if (mask > 4 || mask == 3)
|
||||||
|
{
|
||||||
|
mask >>= 1;
|
||||||
|
continue; // goto cont;
|
||||||
|
}
|
||||||
|
mask >>= 1;
|
||||||
|
if (BR86_NEED_CONV_FOR_MS_BYTE(p[mask]))
|
||||||
|
continue; // goto cont;
|
||||||
|
// if (!BR86_NEED_CONV_FOR_MS_BYTE(p[3])) continue; // goto cont;
|
||||||
|
{
|
||||||
|
UInt32 v = GetUi32(p);
|
||||||
|
UInt32 c;
|
||||||
|
v += (1 << 24); if (v & 0xfe000000) continue; // goto cont;
|
||||||
|
c = BR_PC_GET;
|
||||||
|
BR_CONVERT_VAL(v, c)
|
||||||
|
{
|
||||||
|
mask <<= 3;
|
||||||
|
if (BR86_NEED_CONV_FOR_MS_BYTE(v >> mask))
|
||||||
|
{
|
||||||
|
v ^= (((UInt32)0x100 << mask) - 1);
|
||||||
|
#ifdef MY_CPU_X86
|
||||||
|
// for X86 : we can recalculate (c) to reduce register pressure
|
||||||
|
c = BR_PC_GET;
|
||||||
|
#endif
|
||||||
|
BR_CONVERT_VAL(v, c)
|
||||||
|
}
|
||||||
|
mask = 0;
|
||||||
|
}
|
||||||
|
// v = (v & ((1 << 24) - 1)) - (v & (1 << 24));
|
||||||
|
v &= (1 << 25) - 1; v -= (1 << 24);
|
||||||
|
SetUi32(p, v)
|
||||||
|
p += 4;
|
||||||
|
goto main_loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
main_loop:
|
||||||
|
if (p >= lim)
|
||||||
|
goto fin;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
BR86_PREPARE_BCJ_SCAN
|
||||||
|
p += 4;
|
||||||
|
if (BR86_IS_BCJ_BYTE(0)) { goto a0; }
|
||||||
|
if (BR86_IS_BCJ_BYTE(1)) { goto a1; }
|
||||||
|
if (BR86_IS_BCJ_BYTE(2)) { goto a2; }
|
||||||
|
if (BR86_IS_BCJ_BYTE(3)) { goto a3; }
|
||||||
|
if (p >= lim)
|
||||||
|
goto fin;
|
||||||
|
}
|
||||||
|
|
||||||
|
a0: p--;
|
||||||
|
a1: p--;
|
||||||
|
a2: p--;
|
||||||
|
a3:
|
||||||
|
if (p > lim)
|
||||||
|
goto fin_p;
|
||||||
|
// if (!BR86_NEED_CONV_FOR_MS_BYTE(p[3])) continue; // goto cont;
|
||||||
|
{
|
||||||
|
UInt32 v = GetUi32(p);
|
||||||
|
UInt32 c;
|
||||||
|
v += (1 << 24); if (v & 0xfe000000) continue; // goto cont;
|
||||||
|
c = BR_PC_GET;
|
||||||
|
BR_CONVERT_VAL(v, c)
|
||||||
|
// v = (v & ((1 << 24) - 1)) - (v & (1 << 24));
|
||||||
|
v &= (1 << 25) - 1; v -= (1 << 24);
|
||||||
|
SetUi32(p, v)
|
||||||
|
p += 4;
|
||||||
|
goto main_loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fin_p:
|
||||||
|
p--;
|
||||||
|
fin:
|
||||||
|
// the following processing for tail is optional and can be commented
|
||||||
|
/*
|
||||||
|
lim += 4;
|
||||||
|
for (; p < lim; p++, mask >>= 1)
|
||||||
|
if ((*p & 0xfe) == 0xe8)
|
||||||
|
break;
|
||||||
|
*/
|
||||||
|
*state = (UInt32)mask;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define Z7_BRANCH_CONV_ST_FUNC_IMP(name, m, encoding) \
|
||||||
|
Z7_NO_INLINE \
|
||||||
|
Z7_ATTRIB_NO_VECTOR \
|
||||||
|
Byte *m(name)(Byte *data, SizeT size, UInt32 pc, UInt32 *state) \
|
||||||
|
{ return Z7_BRANCH_CONV_ST(name)(data, size, pc, state, encoding); }
|
||||||
|
|
||||||
|
Z7_BRANCH_CONV_ST_FUNC_IMP(X86, Z7_BRANCH_CONV_ST_DEC, 0)
|
||||||
|
#ifndef Z7_EXTRACT_ONLY
|
||||||
|
Z7_BRANCH_CONV_ST_FUNC_IMP(X86, Z7_BRANCH_CONV_ST_ENC, 1)
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/* BraIA64.c -- Converter for IA-64 code
|
||||||
|
2023-02-20 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#include "Precomp.h"
|
||||||
|
|
||||||
|
// the code was moved to Bra.c
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(disable : 4206) // nonstandard extension used : translation unit is empty
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma GCC diagnostic ignored "-Wempty-translation-unit"
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
/* Compiler.h : Compiler specific defines and pragmas
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_COMPILER_H
|
||||||
|
#define ZIP7_INC_COMPILER_H
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
# define Z7_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
|
||||||
|
#endif
|
||||||
|
#if defined(__clang__) && defined(__apple_build_version__)
|
||||||
|
# define Z7_APPLE_CLANG_VERSION Z7_CLANG_VERSION
|
||||||
|
#elif defined(__clang__)
|
||||||
|
# define Z7_LLVM_CLANG_VERSION Z7_CLANG_VERSION
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# define Z7_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#if !defined(__clang__) && !defined(__GNUC__)
|
||||||
|
#define Z7_MSC_VER_ORIGINAL _MSC_VER
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||||
|
#define Z7_MINGW
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// #pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
// padding size of '' with 4 bytes to alignment boundary
|
||||||
|
#pragma GCC diagnostic ignored "-Wpadded"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
#ifdef UNDER_CE
|
||||||
|
#define RPC_NO_WINDOWS_H
|
||||||
|
/* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */
|
||||||
|
#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
|
||||||
|
#pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER >= 1800
|
||||||
|
#pragma warning(disable : 4464) // relative include path contains '..'
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// == 1200 : -O1 : for __forceinline
|
||||||
|
// >= 1900 : -O1 : for printf
|
||||||
|
#pragma warning(disable : 4710) // function not inlined
|
||||||
|
|
||||||
|
#if _MSC_VER < 1900
|
||||||
|
// winnt.h: 'Int64ShllMod32'
|
||||||
|
#pragma warning(disable : 4514) // unreferenced inline function has been removed
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _MSC_VER < 1300
|
||||||
|
// #pragma warning(disable : 4702) // unreachable code
|
||||||
|
// Bra.c : -O1:
|
||||||
|
#pragma warning(disable : 4714) // function marked as __forceinline not inlined
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
#if _MSC_VER > 1400 && _MSC_VER <= 1900
|
||||||
|
// strcat: This function or variable may be unsafe
|
||||||
|
// sysinfoapi.h: kit10: GetVersion was declared deprecated
|
||||||
|
#pragma warning(disable : 4996)
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if _MSC_VER > 1200
|
||||||
|
// -Wall warnings
|
||||||
|
|
||||||
|
#pragma warning(disable : 4711) // function selected for automatic inline expansion
|
||||||
|
#pragma warning(disable : 4820) // '2' bytes padding added after data member
|
||||||
|
|
||||||
|
#if _MSC_VER >= 1400 && _MSC_VER < 1920
|
||||||
|
// 1400: string.h: _DBG_MEMCPY_INLINE_
|
||||||
|
// 1600 - 191x : smmintrin.h __cplusplus'
|
||||||
|
// is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'
|
||||||
|
#pragma warning(disable : 4668)
|
||||||
|
|
||||||
|
// 1400 - 1600 : WinDef.h : 'FARPROC' :
|
||||||
|
// 1900 - 191x : immintrin.h: _readfsbase_u32
|
||||||
|
// no function prototype given : converting '()' to '(void)'
|
||||||
|
#pragma warning(disable : 4255)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _MSC_VER >= 1914
|
||||||
|
// Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
|
||||||
|
#pragma warning(disable : 5045)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _MSC_VER > 1200
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__clang__) && (__clang_major__ >= 4)
|
||||||
|
#define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \
|
||||||
|
_Pragma("clang loop unroll(disable)") \
|
||||||
|
_Pragma("clang loop vectorize(disable)")
|
||||||
|
#define Z7_ATTRIB_NO_VECTORIZE
|
||||||
|
#elif defined(__GNUC__) && (__GNUC__ >= 5)
|
||||||
|
#define Z7_ATTRIB_NO_VECTORIZE __attribute__((optimize("no-tree-vectorize")))
|
||||||
|
// __attribute__((optimize("no-unroll-loops")));
|
||||||
|
#define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||||
|
#elif defined(_MSC_VER) && (_MSC_VER >= 1920)
|
||||||
|
#define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \
|
||||||
|
_Pragma("loop( no_vector )")
|
||||||
|
#define Z7_ATTRIB_NO_VECTORIZE
|
||||||
|
#else
|
||||||
|
#define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||||
|
#define Z7_ATTRIB_NO_VECTORIZE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MY_CPU_X86_OR_AMD64) && ( \
|
||||||
|
defined(__clang__) && (__clang_major__ >= 4) \
|
||||||
|
|| defined(__GNUC__) && (__GNUC__ >= 5))
|
||||||
|
#define Z7_ATTRIB_NO_SSE __attribute__((__target__("no-sse")))
|
||||||
|
#else
|
||||||
|
#define Z7_ATTRIB_NO_SSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define Z7_ATTRIB_NO_VECTOR \
|
||||||
|
Z7_ATTRIB_NO_VECTORIZE \
|
||||||
|
Z7_ATTRIB_NO_SSE
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__clang__) && (__clang_major__ >= 8) \
|
||||||
|
|| defined(__GNUC__) && (__GNUC__ >= 1000) \
|
||||||
|
/* || defined(_MSC_VER) && (_MSC_VER >= 1920) */
|
||||||
|
// GCC is not good for __builtin_expect()
|
||||||
|
#define Z7_LIKELY(x) (__builtin_expect((x), 1))
|
||||||
|
#define Z7_UNLIKELY(x) (__builtin_expect((x), 0))
|
||||||
|
// #define Z7_unlikely [[unlikely]]
|
||||||
|
// #define Z7_likely [[likely]]
|
||||||
|
#else
|
||||||
|
#define Z7_LIKELY(x) (x)
|
||||||
|
#define Z7_UNLIKELY(x) (x)
|
||||||
|
// #define Z7_likely
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if (defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 36000))
|
||||||
|
#define Z7_DIAGNOSCTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER \
|
||||||
|
_Pragma("GCC diagnostic push") \
|
||||||
|
_Pragma("GCC diagnostic ignored \"-Wreserved-macro-identifier\"")
|
||||||
|
#define Z7_DIAGNOSCTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER \
|
||||||
|
_Pragma("GCC diagnostic pop")
|
||||||
|
#else
|
||||||
|
#define Z7_DIAGNOSCTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
|
||||||
|
#define Z7_DIAGNOSCTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define UNUSED_VAR(x) (void)x;
|
||||||
|
/* #define UNUSED_VAR(x) x=x; */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,823 @@
|
|||||||
|
/* CpuArch.c -- CPU specific code
|
||||||
|
2023-05-18 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#include "Precomp.h"
|
||||||
|
|
||||||
|
// #include <stdio.h>
|
||||||
|
|
||||||
|
#include "CpuArch.h"
|
||||||
|
|
||||||
|
#ifdef MY_CPU_X86_OR_AMD64
|
||||||
|
|
||||||
|
#undef NEED_CHECK_FOR_CPUID
|
||||||
|
#if !defined(MY_CPU_AMD64)
|
||||||
|
#define NEED_CHECK_FOR_CPUID
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
cpuid instruction supports (subFunction) parameter in ECX,
|
||||||
|
that is used only with some specific (function) parameter values.
|
||||||
|
But we always use only (subFunction==0).
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
__cpuid(): MSVC and GCC/CLANG use same function/macro name
|
||||||
|
but parameters are different.
|
||||||
|
We use MSVC __cpuid() parameters style for our z7_x86_cpuid() function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__GNUC__) /* && (__GNUC__ >= 10) */ \
|
||||||
|
|| defined(__clang__) /* && (__clang_major__ >= 10) */
|
||||||
|
|
||||||
|
/* there was some CLANG/GCC compilers that have issues with
|
||||||
|
rbx(ebx) handling in asm blocks in -fPIC mode (__PIC__ is defined).
|
||||||
|
compiler's <cpuid.h> contains the macro __cpuid() that is similar to our code.
|
||||||
|
The history of __cpuid() changes in CLANG/GCC:
|
||||||
|
GCC:
|
||||||
|
2007: it preserved ebx for (__PIC__ && __i386__)
|
||||||
|
2013: it preserved rbx and ebx for __PIC__
|
||||||
|
2014: it doesn't preserves rbx and ebx anymore
|
||||||
|
we suppose that (__GNUC__ >= 5) fixed that __PIC__ ebx/rbx problem.
|
||||||
|
CLANG:
|
||||||
|
2014+: it preserves rbx, but only for 64-bit code. No __PIC__ check.
|
||||||
|
Why CLANG cares about 64-bit mode only, and doesn't care about ebx (in 32-bit)?
|
||||||
|
Do we need __PIC__ test for CLANG or we must care about rbx even if
|
||||||
|
__PIC__ is not defined?
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ASM_LN "\n"
|
||||||
|
|
||||||
|
#if defined(MY_CPU_AMD64) && defined(__PIC__) \
|
||||||
|
&& ((defined (__GNUC__) && (__GNUC__ < 5)) || defined(__clang__))
|
||||||
|
|
||||||
|
#define x86_cpuid_MACRO(p, func) { \
|
||||||
|
__asm__ __volatile__ ( \
|
||||||
|
ASM_LN "mov %%rbx, %q1" \
|
||||||
|
ASM_LN "cpuid" \
|
||||||
|
ASM_LN "xchg %%rbx, %q1" \
|
||||||
|
: "=a" ((p)[0]), "=&r" ((p)[1]), "=c" ((p)[2]), "=d" ((p)[3]) : "0" (func), "2"(0)); }
|
||||||
|
|
||||||
|
/* "=&r" selects free register. It can select even rbx, if that register is free.
|
||||||
|
"=&D" for (RDI) also works, but the code can be larger with "=&D"
|
||||||
|
"2"(0) means (subFunction = 0),
|
||||||
|
2 is (zero-based) index in the output constraint list "=c" (ECX). */
|
||||||
|
|
||||||
|
#elif defined(MY_CPU_X86) && defined(__PIC__) \
|
||||||
|
&& ((defined (__GNUC__) && (__GNUC__ < 5)) || defined(__clang__))
|
||||||
|
|
||||||
|
#define x86_cpuid_MACRO(p, func) { \
|
||||||
|
__asm__ __volatile__ ( \
|
||||||
|
ASM_LN "mov %%ebx, %k1" \
|
||||||
|
ASM_LN "cpuid" \
|
||||||
|
ASM_LN "xchg %%ebx, %k1" \
|
||||||
|
: "=a" ((p)[0]), "=&r" ((p)[1]), "=c" ((p)[2]), "=d" ((p)[3]) : "0" (func), "2"(0)); }
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define x86_cpuid_MACRO(p, func) { \
|
||||||
|
__asm__ __volatile__ ( \
|
||||||
|
ASM_LN "cpuid" \
|
||||||
|
: "=a" ((p)[0]), "=b" ((p)[1]), "=c" ((p)[2]), "=d" ((p)[3]) : "0" (func), "2"(0)); }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func)
|
||||||
|
{
|
||||||
|
x86_cpuid_MACRO(p, func)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Z7_NO_INLINE
|
||||||
|
UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void)
|
||||||
|
{
|
||||||
|
#if defined(NEED_CHECK_FOR_CPUID)
|
||||||
|
#define EFALGS_CPUID_BIT 21
|
||||||
|
UInt32 a;
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
ASM_LN "pushf"
|
||||||
|
ASM_LN "pushf"
|
||||||
|
ASM_LN "pop %0"
|
||||||
|
// ASM_LN "movl %0, %1"
|
||||||
|
// ASM_LN "xorl $0x200000, %0"
|
||||||
|
ASM_LN "btc %1, %0"
|
||||||
|
ASM_LN "push %0"
|
||||||
|
ASM_LN "popf"
|
||||||
|
ASM_LN "pushf"
|
||||||
|
ASM_LN "pop %0"
|
||||||
|
ASM_LN "xorl (%%esp), %0"
|
||||||
|
|
||||||
|
ASM_LN "popf"
|
||||||
|
ASM_LN
|
||||||
|
: "=&r" (a) // "=a"
|
||||||
|
: "i" (EFALGS_CPUID_BIT)
|
||||||
|
);
|
||||||
|
if ((a & (1 << EFALGS_CPUID_BIT)) == 0)
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
UInt32 p[4];
|
||||||
|
x86_cpuid_MACRO(p, 0)
|
||||||
|
return p[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef ASM_LN
|
||||||
|
|
||||||
|
#elif !defined(_MSC_VER)
|
||||||
|
|
||||||
|
/*
|
||||||
|
// for gcc/clang and other: we can try to use __cpuid macro:
|
||||||
|
#include <cpuid.h>
|
||||||
|
void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func)
|
||||||
|
{
|
||||||
|
__cpuid(func, p[0], p[1], p[2], p[3]);
|
||||||
|
}
|
||||||
|
UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void)
|
||||||
|
{
|
||||||
|
return (UInt32)__get_cpuid_max(0, NULL);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// for unsupported cpuid:
|
||||||
|
void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func)
|
||||||
|
{
|
||||||
|
UNUSED_VAR(func)
|
||||||
|
p[0] = p[1] = p[2] = p[3] = 0;
|
||||||
|
}
|
||||||
|
UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // _MSC_VER
|
||||||
|
|
||||||
|
#if !defined(MY_CPU_AMD64)
|
||||||
|
|
||||||
|
UInt32 __declspec(naked) Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void)
|
||||||
|
{
|
||||||
|
#if defined(NEED_CHECK_FOR_CPUID)
|
||||||
|
#define EFALGS_CPUID_BIT 21
|
||||||
|
__asm pushfd
|
||||||
|
__asm pushfd
|
||||||
|
/*
|
||||||
|
__asm pop eax
|
||||||
|
// __asm mov edx, eax
|
||||||
|
__asm btc eax, EFALGS_CPUID_BIT
|
||||||
|
__asm push eax
|
||||||
|
*/
|
||||||
|
__asm btc dword ptr [esp], EFALGS_CPUID_BIT
|
||||||
|
__asm popfd
|
||||||
|
__asm pushfd
|
||||||
|
__asm pop eax
|
||||||
|
// __asm xor eax, edx
|
||||||
|
__asm xor eax, [esp]
|
||||||
|
// __asm push edx
|
||||||
|
__asm popfd
|
||||||
|
__asm and eax, (1 shl EFALGS_CPUID_BIT)
|
||||||
|
__asm jz end_func
|
||||||
|
#endif
|
||||||
|
__asm push ebx
|
||||||
|
__asm xor eax, eax // func
|
||||||
|
__asm xor ecx, ecx // subFunction (optional) for (func == 0)
|
||||||
|
__asm cpuid
|
||||||
|
__asm pop ebx
|
||||||
|
#if defined(NEED_CHECK_FOR_CPUID)
|
||||||
|
end_func:
|
||||||
|
#endif
|
||||||
|
__asm ret 0
|
||||||
|
}
|
||||||
|
|
||||||
|
void __declspec(naked) Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func)
|
||||||
|
{
|
||||||
|
UNUSED_VAR(p)
|
||||||
|
UNUSED_VAR(func)
|
||||||
|
__asm push ebx
|
||||||
|
__asm push edi
|
||||||
|
__asm mov edi, ecx // p
|
||||||
|
__asm mov eax, edx // func
|
||||||
|
__asm xor ecx, ecx // subfunction (optional) for (func == 0)
|
||||||
|
__asm cpuid
|
||||||
|
__asm mov [edi ], eax
|
||||||
|
__asm mov [edi + 4], ebx
|
||||||
|
__asm mov [edi + 8], ecx
|
||||||
|
__asm mov [edi + 12], edx
|
||||||
|
__asm pop edi
|
||||||
|
__asm pop ebx
|
||||||
|
__asm ret 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // MY_CPU_AMD64
|
||||||
|
|
||||||
|
#if _MSC_VER >= 1600
|
||||||
|
#include <intrin.h>
|
||||||
|
#define MY_cpuidex __cpuidex
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
__cpuid (func == (0 or 7)) requires subfunction number in ECX.
|
||||||
|
MSDN: The __cpuid intrinsic clears the ECX register before calling the cpuid instruction.
|
||||||
|
__cpuid() in new MSVC clears ECX.
|
||||||
|
__cpuid() in old MSVC (14.00) x64 doesn't clear ECX
|
||||||
|
We still can use __cpuid for low (func) values that don't require ECX,
|
||||||
|
but __cpuid() in old MSVC will be incorrect for some func values: (func == 7).
|
||||||
|
So here we use the hack for old MSVC to send (subFunction) in ECX register to cpuid instruction,
|
||||||
|
where ECX value is first parameter for FASTCALL / NO_INLINE func,
|
||||||
|
So the caller of MY_cpuidex_HACK() sets ECX as subFunction, and
|
||||||
|
old MSVC for __cpuid() doesn't change ECX and cpuid instruction gets (subFunction) value.
|
||||||
|
|
||||||
|
DON'T remove Z7_NO_INLINE and Z7_FASTCALL for MY_cpuidex_HACK(): !!!
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
Z7_NO_INLINE void Z7_FASTCALL MY_cpuidex_HACK(UInt32 subFunction, UInt32 func, int *CPUInfo)
|
||||||
|
{
|
||||||
|
UNUSED_VAR(subFunction)
|
||||||
|
__cpuid(CPUInfo, func);
|
||||||
|
}
|
||||||
|
#define MY_cpuidex(info, func, func2) MY_cpuidex_HACK(func2, func, info)
|
||||||
|
#pragma message("======== MY_cpuidex_HACK WAS USED ========")
|
||||||
|
#endif // _MSC_VER >= 1600
|
||||||
|
|
||||||
|
#if !defined(MY_CPU_AMD64)
|
||||||
|
/* inlining for __cpuid() in MSVC x86 (32-bit) produces big ineffective code,
|
||||||
|
so we disable inlining here */
|
||||||
|
Z7_NO_INLINE
|
||||||
|
#endif
|
||||||
|
void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func)
|
||||||
|
{
|
||||||
|
MY_cpuidex((int *)p, (int)func, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Z7_NO_INLINE
|
||||||
|
UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void)
|
||||||
|
{
|
||||||
|
int a[4];
|
||||||
|
MY_cpuidex(a, 0, 0);
|
||||||
|
return a[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MY_CPU_AMD64
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
#if defined(NEED_CHECK_FOR_CPUID)
|
||||||
|
#define CHECK_CPUID_IS_SUPPORTED { if (z7_x86_cpuid_GetMaxFunc() == 0) return 0; }
|
||||||
|
#else
|
||||||
|
#define CHECK_CPUID_IS_SUPPORTED
|
||||||
|
#endif
|
||||||
|
#undef NEED_CHECK_FOR_CPUID
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
BoolInt x86cpuid_Func_1(UInt32 *p)
|
||||||
|
{
|
||||||
|
CHECK_CPUID_IS_SUPPORTED
|
||||||
|
z7_x86_cpuid(p, 1);
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
static const UInt32 kVendors[][1] =
|
||||||
|
{
|
||||||
|
{ 0x756E6547 }, // , 0x49656E69, 0x6C65746E },
|
||||||
|
{ 0x68747541 }, // , 0x69746E65, 0x444D4163 },
|
||||||
|
{ 0x746E6543 } // , 0x48727561, 0x736C7561 }
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
};
|
||||||
|
int x86cpuid_GetFirm(const Cx86cpuid *p);
|
||||||
|
#define x86cpuid_ver_GetFamily(ver) (((ver >> 16) & 0xff0) | ((ver >> 8) & 0xf))
|
||||||
|
#define x86cpuid_ver_GetModel(ver) (((ver >> 12) & 0xf0) | ((ver >> 4) & 0xf))
|
||||||
|
#define x86cpuid_ver_GetStepping(ver) (ver & 0xf)
|
||||||
|
|
||||||
|
int x86cpuid_GetFirm(const Cx86cpuid *p)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[0]); i++)
|
||||||
|
{
|
||||||
|
const UInt32 *v = kVendors[i];
|
||||||
|
if (v[0] == p->vendor[0]
|
||||||
|
// && v[1] == p->vendor[1]
|
||||||
|
// && v[2] == p->vendor[2]
|
||||||
|
)
|
||||||
|
return (int)i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoolInt CPU_Is_InOrder()
|
||||||
|
{
|
||||||
|
Cx86cpuid p;
|
||||||
|
UInt32 family, model;
|
||||||
|
if (!x86cpuid_CheckAndRead(&p))
|
||||||
|
return True;
|
||||||
|
|
||||||
|
family = x86cpuid_ver_GetFamily(p.ver);
|
||||||
|
model = x86cpuid_ver_GetModel(p.ver);
|
||||||
|
|
||||||
|
switch (x86cpuid_GetFirm(&p))
|
||||||
|
{
|
||||||
|
case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && (
|
||||||
|
// In-Order Atom CPU
|
||||||
|
model == 0x1C // 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330
|
||||||
|
|| model == 0x26 // 45 nm, Z6xx
|
||||||
|
|| model == 0x27 // 32 nm, Z2460
|
||||||
|
|| model == 0x35 // 32 nm, Z2760
|
||||||
|
|| model == 0x36 // 32 nm, N2xxx, D2xxx
|
||||||
|
)));
|
||||||
|
case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
|
||||||
|
case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
|
||||||
|
}
|
||||||
|
return False; // v23 : unknown processors are not In-Order
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "7zWindows.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(MY_CPU_AMD64) && defined(_WIN32)
|
||||||
|
|
||||||
|
/* for legacy SSE ia32: there is no user-space cpu instruction to check
|
||||||
|
that OS supports SSE register storing/restoring on context switches.
|
||||||
|
So we need some OS-specific function to check that it's safe to use SSE registers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Z7_FORCE_INLINE
|
||||||
|
static BoolInt CPU_Sys_Is_SSE_Supported(void)
|
||||||
|
{
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4996) // `GetVersion': was declared deprecated
|
||||||
|
#endif
|
||||||
|
/* low byte is major version of Windows
|
||||||
|
We suppose that any Windows version since
|
||||||
|
Windows2000 (major == 5) supports SSE registers */
|
||||||
|
return (Byte)GetVersion() >= 5;
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False;
|
||||||
|
#else
|
||||||
|
#define CHECK_SYS_SSE_SUPPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(MY_CPU_AMD64)
|
||||||
|
|
||||||
|
BoolInt CPU_IsSupported_CMOV(void)
|
||||||
|
{
|
||||||
|
UInt32 a[4];
|
||||||
|
if (!x86cpuid_Func_1(&a[0]))
|
||||||
|
return 0;
|
||||||
|
return (a[3] >> 15) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoolInt CPU_IsSupported_SSE(void)
|
||||||
|
{
|
||||||
|
UInt32 a[4];
|
||||||
|
CHECK_SYS_SSE_SUPPORT
|
||||||
|
if (!x86cpuid_Func_1(&a[0]))
|
||||||
|
return 0;
|
||||||
|
return (a[3] >> 25) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoolInt CPU_IsSupported_SSE2(void)
|
||||||
|
{
|
||||||
|
UInt32 a[4];
|
||||||
|
CHECK_SYS_SSE_SUPPORT
|
||||||
|
if (!x86cpuid_Func_1(&a[0]))
|
||||||
|
return 0;
|
||||||
|
return (a[3] >> 26) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static UInt32 x86cpuid_Func_1_ECX(void)
|
||||||
|
{
|
||||||
|
UInt32 a[4];
|
||||||
|
CHECK_SYS_SSE_SUPPORT
|
||||||
|
if (!x86cpuid_Func_1(&a[0]))
|
||||||
|
return 0;
|
||||||
|
return a[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
BoolInt CPU_IsSupported_AES(void)
|
||||||
|
{
|
||||||
|
return (x86cpuid_Func_1_ECX() >> 25) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoolInt CPU_IsSupported_SSSE3(void)
|
||||||
|
{
|
||||||
|
return (x86cpuid_Func_1_ECX() >> 9) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoolInt CPU_IsSupported_SSE41(void)
|
||||||
|
{
|
||||||
|
return (x86cpuid_Func_1_ECX() >> 19) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoolInt CPU_IsSupported_SHA(void)
|
||||||
|
{
|
||||||
|
CHECK_SYS_SSE_SUPPORT
|
||||||
|
|
||||||
|
if (z7_x86_cpuid_GetMaxFunc() < 7)
|
||||||
|
return False;
|
||||||
|
{
|
||||||
|
UInt32 d[4];
|
||||||
|
z7_x86_cpuid(d, 7);
|
||||||
|
return (d[1] >> 29) & 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MSVC: _xgetbv() intrinsic is available since VS2010SP1.
|
||||||
|
MSVC also defines (_XCR_XFEATURE_ENABLED_MASK) macro in
|
||||||
|
<immintrin.h> that we can use or check.
|
||||||
|
For any 32-bit x86 we can use asm code in MSVC,
|
||||||
|
but MSVC asm code is huge after compilation.
|
||||||
|
So _xgetbv() is better
|
||||||
|
|
||||||
|
ICC: _xgetbv() intrinsic is available (in what version of ICC?)
|
||||||
|
ICC defines (__GNUC___) and it supports gnu assembler
|
||||||
|
also ICC supports MASM style code with -use-msasm switch.
|
||||||
|
but ICC doesn't support __attribute__((__target__))
|
||||||
|
|
||||||
|
GCC/CLANG 9:
|
||||||
|
_xgetbv() is macro that works via __builtin_ia32_xgetbv()
|
||||||
|
and we need __attribute__((__target__("xsave")).
|
||||||
|
But with __target__("xsave") the function will be not
|
||||||
|
inlined to function that has no __target__("xsave") attribute.
|
||||||
|
If we want _xgetbv() call inlining, then we should use asm version
|
||||||
|
instead of calling _xgetbv().
|
||||||
|
Note:intrinsic is broke before GCC 8.2:
|
||||||
|
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85684
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) \
|
||||||
|
|| defined(_MSC_VER) && (_MSC_VER >= 1600) && (_MSC_FULL_VER >= 160040219) \
|
||||||
|
|| defined(__GNUC__) && (__GNUC__ >= 9) \
|
||||||
|
|| defined(__clang__) && (__clang_major__ >= 9)
|
||||||
|
// we define ATTRIB_XGETBV, if we want to use predefined _xgetbv() from compiler
|
||||||
|
#if defined(__INTEL_COMPILER)
|
||||||
|
#define ATTRIB_XGETBV
|
||||||
|
#elif defined(__GNUC__) || defined(__clang__)
|
||||||
|
// we don't define ATTRIB_XGETBV here, because asm version is better for inlining.
|
||||||
|
// #define ATTRIB_XGETBV __attribute__((__target__("xsave")))
|
||||||
|
#else
|
||||||
|
#define ATTRIB_XGETBV
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ATTRIB_XGETBV)
|
||||||
|
#include <immintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// XFEATURE_ENABLED_MASK/XCR0
|
||||||
|
#define MY_XCR_XFEATURE_ENABLED_MASK 0
|
||||||
|
|
||||||
|
#if defined(ATTRIB_XGETBV)
|
||||||
|
ATTRIB_XGETBV
|
||||||
|
#endif
|
||||||
|
static UInt64 x86_xgetbv_0(UInt32 num)
|
||||||
|
{
|
||||||
|
#if defined(ATTRIB_XGETBV)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
#if (defined(_MSC_VER))
|
||||||
|
_xgetbv(num);
|
||||||
|
#else
|
||||||
|
__builtin_ia32_xgetbv(
|
||||||
|
#if !defined(__clang__)
|
||||||
|
(int)
|
||||||
|
#endif
|
||||||
|
num);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__GNUC__) || defined(__clang__) || defined(__SUNPRO_CC)
|
||||||
|
|
||||||
|
UInt32 a, d;
|
||||||
|
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4))
|
||||||
|
__asm__
|
||||||
|
(
|
||||||
|
"xgetbv"
|
||||||
|
: "=a"(a), "=d"(d) : "c"(num) : "cc"
|
||||||
|
);
|
||||||
|
#else // is old gcc
|
||||||
|
__asm__
|
||||||
|
(
|
||||||
|
".byte 0x0f, 0x01, 0xd0" "\n\t"
|
||||||
|
: "=a"(a), "=d"(d) : "c"(num) : "cc"
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
return ((UInt64)d << 32) | a;
|
||||||
|
// return a;
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER) && !defined(MY_CPU_AMD64)
|
||||||
|
|
||||||
|
UInt32 a, d;
|
||||||
|
__asm {
|
||||||
|
push eax
|
||||||
|
push edx
|
||||||
|
push ecx
|
||||||
|
mov ecx, num;
|
||||||
|
// xor ecx, ecx // = MY_XCR_XFEATURE_ENABLED_MASK
|
||||||
|
_emit 0x0f
|
||||||
|
_emit 0x01
|
||||||
|
_emit 0xd0
|
||||||
|
mov a, eax
|
||||||
|
mov d, edx
|
||||||
|
pop ecx
|
||||||
|
pop edx
|
||||||
|
pop eax
|
||||||
|
}
|
||||||
|
return ((UInt64)d << 32) | a;
|
||||||
|
// return a;
|
||||||
|
|
||||||
|
#else // it's unknown compiler
|
||||||
|
// #error "Need xgetbv function"
|
||||||
|
UNUSED_VAR(num)
|
||||||
|
// for MSVC-X64 we could call external function from external file.
|
||||||
|
/* Actually we had checked OSXSAVE/AVX in cpuid before.
|
||||||
|
So it's expected that OS supports at least AVX and below. */
|
||||||
|
// if (num != MY_XCR_XFEATURE_ENABLED_MASK) return 0; // if not XCR0
|
||||||
|
return
|
||||||
|
// (1 << 0) | // x87
|
||||||
|
(1 << 1) // SSE
|
||||||
|
| (1 << 2); // AVX
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
/*
|
||||||
|
Windows versions do not know about new ISA extensions that
|
||||||
|
can be introduced. But we still can use new extensions,
|
||||||
|
even if Windows doesn't report about supporting them,
|
||||||
|
But we can use new extensions, only if Windows knows about new ISA extension
|
||||||
|
that changes the number or size of registers: SSE, AVX/XSAVE, AVX512
|
||||||
|
So it's enough to check
|
||||||
|
MY_PF_AVX_INSTRUCTIONS_AVAILABLE
|
||||||
|
instead of
|
||||||
|
MY_PF_AVX2_INSTRUCTIONS_AVAILABLE
|
||||||
|
*/
|
||||||
|
#define MY_PF_XSAVE_ENABLED 17
|
||||||
|
// #define MY_PF_SSSE3_INSTRUCTIONS_AVAILABLE 36
|
||||||
|
// #define MY_PF_SSE4_1_INSTRUCTIONS_AVAILABLE 37
|
||||||
|
// #define MY_PF_SSE4_2_INSTRUCTIONS_AVAILABLE 38
|
||||||
|
// #define MY_PF_AVX_INSTRUCTIONS_AVAILABLE 39
|
||||||
|
// #define MY_PF_AVX2_INSTRUCTIONS_AVAILABLE 40
|
||||||
|
// #define MY_PF_AVX512F_INSTRUCTIONS_AVAILABLE 41
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BoolInt CPU_IsSupported_AVX(void)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (!IsProcessorFeaturePresent(MY_PF_XSAVE_ENABLED))
|
||||||
|
return False;
|
||||||
|
/* PF_AVX_INSTRUCTIONS_AVAILABLE probably is supported starting from
|
||||||
|
some latest Win10 revisions. But we need AVX in older Windows also.
|
||||||
|
So we don't use the following check: */
|
||||||
|
/*
|
||||||
|
if (!IsProcessorFeaturePresent(MY_PF_AVX_INSTRUCTIONS_AVAILABLE))
|
||||||
|
return False;
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
OS must use new special XSAVE/XRSTOR instructions to save
|
||||||
|
AVX registers when it required for context switching.
|
||||||
|
At OS statring:
|
||||||
|
OS sets CR4.OSXSAVE flag to signal the processor that OS supports the XSAVE extensions.
|
||||||
|
Also OS sets bitmask in XCR0 register that defines what
|
||||||
|
registers will be processed by XSAVE instruction:
|
||||||
|
XCR0.SSE[bit 0] - x87 registers and state
|
||||||
|
XCR0.SSE[bit 1] - SSE registers and state
|
||||||
|
XCR0.AVX[bit 2] - AVX registers and state
|
||||||
|
CR4.OSXSAVE is reflected to CPUID.1:ECX.OSXSAVE[bit 27].
|
||||||
|
So we can read that bit in user-space.
|
||||||
|
XCR0 is available for reading in user-space by new XGETBV instruction.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
const UInt32 c = x86cpuid_Func_1_ECX();
|
||||||
|
if (0 == (1
|
||||||
|
& (c >> 28) // AVX instructions are supported by hardware
|
||||||
|
& (c >> 27))) // OSXSAVE bit: XSAVE and related instructions are enabled by OS.
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* also we can check
|
||||||
|
CPUID.1:ECX.XSAVE [bit 26] : that shows that
|
||||||
|
XSAVE, XRESTOR, XSETBV, XGETBV instructions are supported by hardware.
|
||||||
|
But that check is redundant, because if OSXSAVE bit is set, then XSAVE is also set */
|
||||||
|
|
||||||
|
/* If OS have enabled XSAVE extension instructions (OSXSAVE == 1),
|
||||||
|
in most cases we expect that OS also will support storing/restoring
|
||||||
|
for AVX and SSE states at least.
|
||||||
|
But to be ensure for that we call user-space instruction
|
||||||
|
XGETBV(0) to get XCR0 value that contains bitmask that defines
|
||||||
|
what exact states(registers) OS have enabled for storing/restoring.
|
||||||
|
*/
|
||||||
|
|
||||||
|
{
|
||||||
|
const UInt32 bm = (UInt32)x86_xgetbv_0(MY_XCR_XFEATURE_ENABLED_MASK);
|
||||||
|
// printf("\n=== XGetBV=%d\n", bm);
|
||||||
|
return 1
|
||||||
|
& (bm >> 1) // SSE state is supported (set by OS) for storing/restoring
|
||||||
|
& (bm >> 2); // AVX state is supported (set by OS) for storing/restoring
|
||||||
|
}
|
||||||
|
// since Win7SP1: we can use GetEnabledXStateFeatures();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BoolInt CPU_IsSupported_AVX2(void)
|
||||||
|
{
|
||||||
|
if (!CPU_IsSupported_AVX())
|
||||||
|
return False;
|
||||||
|
if (z7_x86_cpuid_GetMaxFunc() < 7)
|
||||||
|
return False;
|
||||||
|
{
|
||||||
|
UInt32 d[4];
|
||||||
|
z7_x86_cpuid(d, 7);
|
||||||
|
// printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]);
|
||||||
|
return 1
|
||||||
|
& (d[1] >> 5); // avx2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BoolInt CPU_IsSupported_VAES_AVX2(void)
|
||||||
|
{
|
||||||
|
if (!CPU_IsSupported_AVX())
|
||||||
|
return False;
|
||||||
|
if (z7_x86_cpuid_GetMaxFunc() < 7)
|
||||||
|
return False;
|
||||||
|
{
|
||||||
|
UInt32 d[4];
|
||||||
|
z7_x86_cpuid(d, 7);
|
||||||
|
// printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]);
|
||||||
|
return 1
|
||||||
|
& (d[1] >> 5) // avx2
|
||||||
|
// & (d[1] >> 31) // avx512vl
|
||||||
|
& (d[2] >> 9); // vaes // VEX-256/EVEX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BoolInt CPU_IsSupported_PageGB(void)
|
||||||
|
{
|
||||||
|
CHECK_CPUID_IS_SUPPORTED
|
||||||
|
{
|
||||||
|
UInt32 d[4];
|
||||||
|
z7_x86_cpuid(d, 0x80000000);
|
||||||
|
if (d[0] < 0x80000001)
|
||||||
|
return False;
|
||||||
|
z7_x86_cpuid(d, 0x80000001);
|
||||||
|
return (d[3] >> 26) & 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#elif defined(MY_CPU_ARM_OR_ARM64)
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#include "7zWindows.h"
|
||||||
|
|
||||||
|
BoolInt CPU_IsSupported_CRC32(void) { return IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) ? 1 : 0; }
|
||||||
|
BoolInt CPU_IsSupported_CRYPTO(void) { return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) ? 1 : 0; }
|
||||||
|
BoolInt CPU_IsSupported_NEON(void) { return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) ? 1 : 0; }
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
static void Print_sysctlbyname(const char *name)
|
||||||
|
{
|
||||||
|
size_t bufSize = 256;
|
||||||
|
char buf[256];
|
||||||
|
int res = sysctlbyname(name, &buf, &bufSize, NULL, 0);
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
printf("\nres = %d : %s : '%s' : bufSize = %d, numeric", res, name, buf, (unsigned)bufSize);
|
||||||
|
for (i = 0; i < 20; i++)
|
||||||
|
printf(" %2x", (unsigned)(Byte)buf[i]);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
Print_sysctlbyname("hw.pagesize");
|
||||||
|
Print_sysctlbyname("machdep.cpu.brand_string");
|
||||||
|
*/
|
||||||
|
|
||||||
|
static BoolInt z7_sysctlbyname_Get_BoolInt(const char *name)
|
||||||
|
{
|
||||||
|
UInt32 val = 0;
|
||||||
|
if (z7_sysctlbyname_Get_UInt32(name, &val) == 0 && val == 1)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoolInt CPU_IsSupported_CRC32(void)
|
||||||
|
{
|
||||||
|
return z7_sysctlbyname_Get_BoolInt("hw.optional.armv8_crc32");
|
||||||
|
}
|
||||||
|
|
||||||
|
BoolInt CPU_IsSupported_NEON(void)
|
||||||
|
{
|
||||||
|
return z7_sysctlbyname_Get_BoolInt("hw.optional.neon");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MY_CPU_ARM64
|
||||||
|
#define APPLE_CRYPTO_SUPPORT_VAL 1
|
||||||
|
#else
|
||||||
|
#define APPLE_CRYPTO_SUPPORT_VAL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BoolInt CPU_IsSupported_SHA1(void) { return APPLE_CRYPTO_SUPPORT_VAL; }
|
||||||
|
BoolInt CPU_IsSupported_SHA2(void) { return APPLE_CRYPTO_SUPPORT_VAL; }
|
||||||
|
BoolInt CPU_IsSupported_AES (void) { return APPLE_CRYPTO_SUPPORT_VAL; }
|
||||||
|
|
||||||
|
|
||||||
|
#else // __APPLE__
|
||||||
|
|
||||||
|
#include <sys/auxv.h>
|
||||||
|
|
||||||
|
#define USE_HWCAP
|
||||||
|
|
||||||
|
#ifdef USE_HWCAP
|
||||||
|
|
||||||
|
#include <asm/hwcap.h>
|
||||||
|
|
||||||
|
#define MY_HWCAP_CHECK_FUNC_2(name1, name2) \
|
||||||
|
BoolInt CPU_IsSupported_ ## name1() { return (getauxval(AT_HWCAP) & (HWCAP_ ## name2)) ? 1 : 0; }
|
||||||
|
|
||||||
|
#ifdef MY_CPU_ARM64
|
||||||
|
#define MY_HWCAP_CHECK_FUNC(name) \
|
||||||
|
MY_HWCAP_CHECK_FUNC_2(name, name)
|
||||||
|
MY_HWCAP_CHECK_FUNC_2(NEON, ASIMD)
|
||||||
|
// MY_HWCAP_CHECK_FUNC (ASIMD)
|
||||||
|
#elif defined(MY_CPU_ARM)
|
||||||
|
#define MY_HWCAP_CHECK_FUNC(name) \
|
||||||
|
BoolInt CPU_IsSupported_ ## name() { return (getauxval(AT_HWCAP2) & (HWCAP2_ ## name)) ? 1 : 0; }
|
||||||
|
MY_HWCAP_CHECK_FUNC_2(NEON, NEON)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else // USE_HWCAP
|
||||||
|
|
||||||
|
#define MY_HWCAP_CHECK_FUNC(name) \
|
||||||
|
BoolInt CPU_IsSupported_ ## name() { return 0; }
|
||||||
|
MY_HWCAP_CHECK_FUNC(NEON)
|
||||||
|
|
||||||
|
#endif // USE_HWCAP
|
||||||
|
|
||||||
|
MY_HWCAP_CHECK_FUNC (CRC32)
|
||||||
|
MY_HWCAP_CHECK_FUNC (SHA1)
|
||||||
|
MY_HWCAP_CHECK_FUNC (SHA2)
|
||||||
|
MY_HWCAP_CHECK_FUNC (AES)
|
||||||
|
|
||||||
|
#endif // __APPLE__
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
#endif // MY_CPU_ARM_OR_ARM64
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
|
||||||
|
int z7_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize)
|
||||||
|
{
|
||||||
|
return sysctlbyname(name, buf, bufSize, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int z7_sysctlbyname_Get_UInt32(const char *name, UInt32 *val)
|
||||||
|
{
|
||||||
|
size_t bufSize = sizeof(*val);
|
||||||
|
const int res = z7_sysctlbyname_Get(name, val, &bufSize);
|
||||||
|
if (res == 0 && bufSize != sizeof(*val))
|
||||||
|
return EFAULT;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,523 @@
|
|||||||
|
/* CpuArch.h -- CPU specific code
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_CPU_ARCH_H
|
||||||
|
#define ZIP7_INC_CPU_ARCH_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
/*
|
||||||
|
MY_CPU_LE means that CPU is LITTLE ENDIAN.
|
||||||
|
MY_CPU_BE means that CPU is BIG ENDIAN.
|
||||||
|
If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform.
|
||||||
|
|
||||||
|
MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
|
||||||
|
|
||||||
|
MY_CPU_64BIT means that processor can work with 64-bit registers.
|
||||||
|
MY_CPU_64BIT can be used to select fast code branch
|
||||||
|
MY_CPU_64BIT doesn't mean that (sizeof(void *) == 8)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(_M_X64) \
|
||||||
|
|| defined(_M_AMD64) \
|
||||||
|
|| defined(__x86_64__) \
|
||||||
|
|| defined(__AMD64__) \
|
||||||
|
|| defined(__amd64__)
|
||||||
|
#define MY_CPU_AMD64
|
||||||
|
#ifdef __ILP32__
|
||||||
|
#define MY_CPU_NAME "x32"
|
||||||
|
#define MY_CPU_SIZEOF_POINTER 4
|
||||||
|
#else
|
||||||
|
#define MY_CPU_NAME "x64"
|
||||||
|
#define MY_CPU_SIZEOF_POINTER 8
|
||||||
|
#endif
|
||||||
|
#define MY_CPU_64BIT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_M_IX86) \
|
||||||
|
|| defined(__i386__)
|
||||||
|
#define MY_CPU_X86
|
||||||
|
#define MY_CPU_NAME "x86"
|
||||||
|
/* #define MY_CPU_32BIT */
|
||||||
|
#define MY_CPU_SIZEOF_POINTER 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_M_ARM64) \
|
||||||
|
|| defined(__AARCH64EL__) \
|
||||||
|
|| defined(__AARCH64EB__) \
|
||||||
|
|| defined(__aarch64__)
|
||||||
|
#define MY_CPU_ARM64
|
||||||
|
#ifdef __ILP32__
|
||||||
|
#define MY_CPU_NAME "arm64-32"
|
||||||
|
#define MY_CPU_SIZEOF_POINTER 4
|
||||||
|
#else
|
||||||
|
#define MY_CPU_NAME "arm64"
|
||||||
|
#define MY_CPU_SIZEOF_POINTER 8
|
||||||
|
#endif
|
||||||
|
#define MY_CPU_64BIT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_M_ARM) \
|
||||||
|
|| defined(_M_ARM_NT) \
|
||||||
|
|| defined(_M_ARMT) \
|
||||||
|
|| defined(__arm__) \
|
||||||
|
|| defined(__thumb__) \
|
||||||
|
|| defined(__ARMEL__) \
|
||||||
|
|| defined(__ARMEB__) \
|
||||||
|
|| defined(__THUMBEL__) \
|
||||||
|
|| defined(__THUMBEB__)
|
||||||
|
#define MY_CPU_ARM
|
||||||
|
|
||||||
|
#if defined(__thumb__) || defined(__THUMBEL__) || defined(_M_ARMT)
|
||||||
|
#define MY_CPU_ARMT
|
||||||
|
#define MY_CPU_NAME "armt"
|
||||||
|
#else
|
||||||
|
#define MY_CPU_ARM32
|
||||||
|
#define MY_CPU_NAME "arm"
|
||||||
|
#endif
|
||||||
|
/* #define MY_CPU_32BIT */
|
||||||
|
#define MY_CPU_SIZEOF_POINTER 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_M_IA64) \
|
||||||
|
|| defined(__ia64__)
|
||||||
|
#define MY_CPU_IA64
|
||||||
|
#define MY_CPU_NAME "ia64"
|
||||||
|
#define MY_CPU_64BIT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__mips64) \
|
||||||
|
|| defined(__mips64__) \
|
||||||
|
|| (defined(__mips) && (__mips == 64 || __mips == 4 || __mips == 3))
|
||||||
|
#define MY_CPU_NAME "mips64"
|
||||||
|
#define MY_CPU_64BIT
|
||||||
|
#elif defined(__mips__)
|
||||||
|
#define MY_CPU_NAME "mips"
|
||||||
|
/* #define MY_CPU_32BIT */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__ppc64__) \
|
||||||
|
|| defined(__powerpc64__) \
|
||||||
|
|| defined(__ppc__) \
|
||||||
|
|| defined(__powerpc__) \
|
||||||
|
|| defined(__PPC__) \
|
||||||
|
|| defined(_POWER)
|
||||||
|
|
||||||
|
#define MY_CPU_PPC_OR_PPC64
|
||||||
|
|
||||||
|
#if defined(__ppc64__) \
|
||||||
|
|| defined(__powerpc64__) \
|
||||||
|
|| defined(_LP64) \
|
||||||
|
|| defined(__64BIT__)
|
||||||
|
#ifdef __ILP32__
|
||||||
|
#define MY_CPU_NAME "ppc64-32"
|
||||||
|
#define MY_CPU_SIZEOF_POINTER 4
|
||||||
|
#else
|
||||||
|
#define MY_CPU_NAME "ppc64"
|
||||||
|
#define MY_CPU_SIZEOF_POINTER 8
|
||||||
|
#endif
|
||||||
|
#define MY_CPU_64BIT
|
||||||
|
#else
|
||||||
|
#define MY_CPU_NAME "ppc"
|
||||||
|
#define MY_CPU_SIZEOF_POINTER 4
|
||||||
|
/* #define MY_CPU_32BIT */
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__riscv) \
|
||||||
|
|| defined(__riscv__)
|
||||||
|
#if __riscv_xlen == 32
|
||||||
|
#define MY_CPU_NAME "riscv32"
|
||||||
|
#elif __riscv_xlen == 64
|
||||||
|
#define MY_CPU_NAME "riscv64"
|
||||||
|
#else
|
||||||
|
#define MY_CPU_NAME "riscv"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
|
||||||
|
#define MY_CPU_X86_OR_AMD64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MY_CPU_ARM) || defined(MY_CPU_ARM64)
|
||||||
|
#define MY_CPU_ARM_OR_ARM64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#ifdef MY_CPU_ARM
|
||||||
|
#define MY_CPU_ARM_LE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MY_CPU_ARM64
|
||||||
|
#define MY_CPU_ARM64_LE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _M_IA64
|
||||||
|
#define MY_CPU_IA64_LE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(MY_CPU_X86_OR_AMD64) \
|
||||||
|
|| defined(MY_CPU_ARM_LE) \
|
||||||
|
|| defined(MY_CPU_ARM64_LE) \
|
||||||
|
|| defined(MY_CPU_IA64_LE) \
|
||||||
|
|| defined(__LITTLE_ENDIAN__) \
|
||||||
|
|| defined(__ARMEL__) \
|
||||||
|
|| defined(__THUMBEL__) \
|
||||||
|
|| defined(__AARCH64EL__) \
|
||||||
|
|| defined(__MIPSEL__) \
|
||||||
|
|| defined(__MIPSEL) \
|
||||||
|
|| defined(_MIPSEL) \
|
||||||
|
|| defined(__BFIN__) \
|
||||||
|
|| (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
|
||||||
|
#define MY_CPU_LE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__BIG_ENDIAN__) \
|
||||||
|
|| defined(__ARMEB__) \
|
||||||
|
|| defined(__THUMBEB__) \
|
||||||
|
|| defined(__AARCH64EB__) \
|
||||||
|
|| defined(__MIPSEB__) \
|
||||||
|
|| defined(__MIPSEB) \
|
||||||
|
|| defined(_MIPSEB) \
|
||||||
|
|| defined(__m68k__) \
|
||||||
|
|| defined(__s390__) \
|
||||||
|
|| defined(__s390x__) \
|
||||||
|
|| defined(__zarch__) \
|
||||||
|
|| (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
||||||
|
#define MY_CPU_BE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
|
||||||
|
#error Stop_Compiling_Bad_Endian
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(MY_CPU_LE) && !defined(MY_CPU_BE)
|
||||||
|
#error Stop_Compiling_CPU_ENDIAN_must_be_detected_at_compile_time
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MY_CPU_32BIT) && defined(MY_CPU_64BIT)
|
||||||
|
#error Stop_Compiling_Bad_32_64_BIT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __SIZEOF_POINTER__
|
||||||
|
#ifdef MY_CPU_SIZEOF_POINTER
|
||||||
|
#if MY_CPU_SIZEOF_POINTER != __SIZEOF_POINTER__
|
||||||
|
#error Stop_Compiling_Bad_MY_CPU_PTR_SIZE
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define MY_CPU_SIZEOF_POINTER __SIZEOF_POINTER__
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4)
|
||||||
|
#if defined (_LP64)
|
||||||
|
#error Stop_Compiling_Bad_MY_CPU_PTR_SIZE
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#if _MSC_VER >= 1300
|
||||||
|
#define MY_CPU_pragma_pack_push_1 __pragma(pack(push, 1))
|
||||||
|
#define MY_CPU_pragma_pop __pragma(pack(pop))
|
||||||
|
#else
|
||||||
|
#define MY_CPU_pragma_pack_push_1
|
||||||
|
#define MY_CPU_pragma_pop
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#ifdef __xlC__
|
||||||
|
#define MY_CPU_pragma_pack_push_1 _Pragma("pack(1)")
|
||||||
|
#define MY_CPU_pragma_pop _Pragma("pack()")
|
||||||
|
#else
|
||||||
|
#define MY_CPU_pragma_pack_push_1 _Pragma("pack(push, 1)")
|
||||||
|
#define MY_CPU_pragma_pop _Pragma("pack(pop)")
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MY_CPU_NAME
|
||||||
|
#ifdef MY_CPU_LE
|
||||||
|
#define MY_CPU_NAME "LE"
|
||||||
|
#elif defined(MY_CPU_BE)
|
||||||
|
#define MY_CPU_NAME "BE"
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
#define MY_CPU_NAME ""
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __has_builtin
|
||||||
|
#define Z7_has_builtin(x) __has_builtin(x)
|
||||||
|
#else
|
||||||
|
#define Z7_has_builtin(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define Z7_BSWAP32_CONST(v) \
|
||||||
|
( (((UInt32)(v) << 24) ) \
|
||||||
|
| (((UInt32)(v) << 8) & (UInt32)0xff0000) \
|
||||||
|
| (((UInt32)(v) >> 8) & (UInt32)0xff00 ) \
|
||||||
|
| (((UInt32)(v) >> 24) ))
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && (_MSC_VER >= 1300)
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* Note: these macros will use bswap instruction (486), that is unsupported in 386 cpu */
|
||||||
|
|
||||||
|
#pragma intrinsic(_byteswap_ushort)
|
||||||
|
#pragma intrinsic(_byteswap_ulong)
|
||||||
|
#pragma intrinsic(_byteswap_uint64)
|
||||||
|
|
||||||
|
#define Z7_BSWAP16(v) _byteswap_ushort(v)
|
||||||
|
#define Z7_BSWAP32(v) _byteswap_ulong (v)
|
||||||
|
#define Z7_BSWAP64(v) _byteswap_uint64(v)
|
||||||
|
#define Z7_CPU_FAST_BSWAP_SUPPORTED
|
||||||
|
|
||||||
|
#elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \
|
||||||
|
|| (defined(__clang__) && Z7_has_builtin(__builtin_bswap16))
|
||||||
|
|
||||||
|
#define Z7_BSWAP16(v) __builtin_bswap16(v)
|
||||||
|
#define Z7_BSWAP32(v) __builtin_bswap32(v)
|
||||||
|
#define Z7_BSWAP64(v) __builtin_bswap64(v)
|
||||||
|
#define Z7_CPU_FAST_BSWAP_SUPPORTED
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define Z7_BSWAP16(v) ((UInt16) \
|
||||||
|
( ((UInt32)(v) << 8) \
|
||||||
|
| ((UInt32)(v) >> 8) \
|
||||||
|
))
|
||||||
|
|
||||||
|
#define Z7_BSWAP32(v) Z7_BSWAP32_CONST(v)
|
||||||
|
|
||||||
|
#define Z7_BSWAP64(v) \
|
||||||
|
( ( ( (UInt64)(v) ) << 8 * 7 ) \
|
||||||
|
| ( ( (UInt64)(v) & ((UInt32)0xff << 8 * 1) ) << 8 * 5 ) \
|
||||||
|
| ( ( (UInt64)(v) & ((UInt32)0xff << 8 * 2) ) << 8 * 3 ) \
|
||||||
|
| ( ( (UInt64)(v) & ((UInt32)0xff << 8 * 3) ) << 8 * 1 ) \
|
||||||
|
| ( ( (UInt64)(v) >> 8 * 1 ) & ((UInt32)0xff << 8 * 3) ) \
|
||||||
|
| ( ( (UInt64)(v) >> 8 * 3 ) & ((UInt32)0xff << 8 * 2) ) \
|
||||||
|
| ( ( (UInt64)(v) >> 8 * 5 ) & ((UInt32)0xff << 8 * 1) ) \
|
||||||
|
| ( ( (UInt64)(v) >> 8 * 7 ) ) \
|
||||||
|
)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MY_CPU_LE
|
||||||
|
#if defined(MY_CPU_X86_OR_AMD64) \
|
||||||
|
|| defined(MY_CPU_ARM64)
|
||||||
|
#define MY_CPU_LE_UNALIGN
|
||||||
|
#define MY_CPU_LE_UNALIGN_64
|
||||||
|
#elif defined(__ARM_FEATURE_UNALIGNED)
|
||||||
|
/* gcc9 for 32-bit arm can use LDRD instruction that requires 32-bit alignment.
|
||||||
|
So we can't use unaligned 64-bit operations. */
|
||||||
|
#define MY_CPU_LE_UNALIGN
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MY_CPU_LE_UNALIGN
|
||||||
|
|
||||||
|
#define GetUi16(p) (*(const UInt16 *)(const void *)(p))
|
||||||
|
#define GetUi32(p) (*(const UInt32 *)(const void *)(p))
|
||||||
|
#ifdef MY_CPU_LE_UNALIGN_64
|
||||||
|
#define GetUi64(p) (*(const UInt64 *)(const void *)(p))
|
||||||
|
#define SetUi64(p, v) { *(UInt64 *)(void *)(p) = (v); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SetUi16(p, v) { *(UInt16 *)(void *)(p) = (v); }
|
||||||
|
#define SetUi32(p, v) { *(UInt32 *)(void *)(p) = (v); }
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define GetUi16(p) ( (UInt16) ( \
|
||||||
|
((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 SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
|
||||||
|
_ppp_[0] = (Byte)_vvv_; \
|
||||||
|
_ppp_[1] = (Byte)(_vvv_ >> 8); }
|
||||||
|
|
||||||
|
#define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
|
||||||
|
_ppp_[0] = (Byte)_vvv_; \
|
||||||
|
_ppp_[1] = (Byte)(_vvv_ >> 8); \
|
||||||
|
_ppp_[2] = (Byte)(_vvv_ >> 16); \
|
||||||
|
_ppp_[3] = (Byte)(_vvv_ >> 24); }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef GetUi64
|
||||||
|
#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SetUi64
|
||||||
|
#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \
|
||||||
|
SetUi32(_ppp2_ , (UInt32)_vvv2_) \
|
||||||
|
SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)) }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(MY_CPU_LE_UNALIGN) && defined(Z7_CPU_FAST_BSWAP_SUPPORTED)
|
||||||
|
|
||||||
|
#define GetBe32(p) Z7_BSWAP32 (*(const UInt32 *)(const void *)(p))
|
||||||
|
#define SetBe32(p, v) { (*(UInt32 *)(void *)(p)) = Z7_BSWAP32(v); }
|
||||||
|
|
||||||
|
#if defined(MY_CPU_LE_UNALIGN_64)
|
||||||
|
#define GetBe64(p) Z7_BSWAP64 (*(const UInt64 *)(const void *)(p))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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 SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
|
||||||
|
_ppp_[0] = (Byte)(_vvv_ >> 24); \
|
||||||
|
_ppp_[1] = (Byte)(_vvv_ >> 16); \
|
||||||
|
_ppp_[2] = (Byte)(_vvv_ >> 8); \
|
||||||
|
_ppp_[3] = (Byte)_vvv_; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GetBe64
|
||||||
|
#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GetBe16
|
||||||
|
#define GetBe16(p) ( (UInt16) ( \
|
||||||
|
((UInt16)((const Byte *)(p))[0] << 8) | \
|
||||||
|
((const Byte *)(p))[1] ))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(MY_CPU_BE)
|
||||||
|
#define Z7_CONV_BE_TO_NATIVE_CONST32(v) (v)
|
||||||
|
#define Z7_CONV_LE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v)
|
||||||
|
#define Z7_CONV_NATIVE_TO_BE_32(v) (v)
|
||||||
|
#elif defined(MY_CPU_LE)
|
||||||
|
#define Z7_CONV_BE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v)
|
||||||
|
#define Z7_CONV_LE_TO_NATIVE_CONST32(v) (v)
|
||||||
|
#define Z7_CONV_NATIVE_TO_BE_32(v) Z7_BSWAP32(v)
|
||||||
|
#else
|
||||||
|
#error Stop_Compiling_Unknown_Endian_CONV
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(MY_CPU_BE)
|
||||||
|
|
||||||
|
#define GetBe32a(p) (*(const UInt32 *)(const void *)(p))
|
||||||
|
#define GetBe16a(p) (*(const UInt16 *)(const void *)(p))
|
||||||
|
#define SetBe32a(p, v) { *(UInt32 *)(void *)(p) = (v); }
|
||||||
|
#define SetBe16a(p, v) { *(UInt16 *)(void *)(p) = (v); }
|
||||||
|
|
||||||
|
#define GetUi32a(p) GetUi32(p)
|
||||||
|
#define GetUi16a(p) GetUi16(p)
|
||||||
|
#define SetUi32a(p, v) SetUi32(p, v)
|
||||||
|
#define SetUi16a(p, v) SetUi16(p, v)
|
||||||
|
|
||||||
|
#elif defined(MY_CPU_LE)
|
||||||
|
|
||||||
|
#define GetUi32a(p) (*(const UInt32 *)(const void *)(p))
|
||||||
|
#define GetUi16a(p) (*(const UInt16 *)(const void *)(p))
|
||||||
|
#define SetUi32a(p, v) { *(UInt32 *)(void *)(p) = (v); }
|
||||||
|
#define SetUi16a(p, v) { *(UInt16 *)(void *)(p) = (v); }
|
||||||
|
|
||||||
|
#define GetBe32a(p) GetBe32(p)
|
||||||
|
#define GetBe16a(p) GetBe16(p)
|
||||||
|
#define SetBe32a(p, v) SetBe32(p, v)
|
||||||
|
#define SetBe16a(p, v) SetBe16(p, v)
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error Stop_Compiling_Unknown_Endian_CPU_a
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(MY_CPU_X86_OR_AMD64) \
|
||||||
|
|| defined(MY_CPU_ARM_OR_ARM64) \
|
||||||
|
|| defined(MY_CPU_PPC_OR_PPC64)
|
||||||
|
#define Z7_CPU_FAST_ROTATE_SUPPORTED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MY_CPU_X86_OR_AMD64
|
||||||
|
|
||||||
|
void Z7_FASTCALL z7_x86_cpuid(UInt32 a[4], UInt32 function);
|
||||||
|
UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void);
|
||||||
|
#if defined(MY_CPU_AMD64)
|
||||||
|
#define Z7_IF_X86_CPUID_SUPPORTED
|
||||||
|
#else
|
||||||
|
#define Z7_IF_X86_CPUID_SUPPORTED if (z7_x86_cpuid_GetMaxFunc())
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BoolInt CPU_IsSupported_AES(void);
|
||||||
|
BoolInt CPU_IsSupported_AVX(void);
|
||||||
|
BoolInt CPU_IsSupported_AVX2(void);
|
||||||
|
BoolInt CPU_IsSupported_VAES_AVX2(void);
|
||||||
|
BoolInt CPU_IsSupported_CMOV(void);
|
||||||
|
BoolInt CPU_IsSupported_SSE(void);
|
||||||
|
BoolInt CPU_IsSupported_SSE2(void);
|
||||||
|
BoolInt CPU_IsSupported_SSSE3(void);
|
||||||
|
BoolInt CPU_IsSupported_SSE41(void);
|
||||||
|
BoolInt CPU_IsSupported_SHA(void);
|
||||||
|
BoolInt CPU_IsSupported_PageGB(void);
|
||||||
|
|
||||||
|
#elif defined(MY_CPU_ARM_OR_ARM64)
|
||||||
|
|
||||||
|
BoolInt CPU_IsSupported_CRC32(void);
|
||||||
|
BoolInt CPU_IsSupported_NEON(void);
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
BoolInt CPU_IsSupported_CRYPTO(void);
|
||||||
|
#define CPU_IsSupported_SHA1 CPU_IsSupported_CRYPTO
|
||||||
|
#define CPU_IsSupported_SHA2 CPU_IsSupported_CRYPTO
|
||||||
|
#define CPU_IsSupported_AES CPU_IsSupported_CRYPTO
|
||||||
|
#else
|
||||||
|
BoolInt CPU_IsSupported_SHA1(void);
|
||||||
|
BoolInt CPU_IsSupported_SHA2(void);
|
||||||
|
BoolInt CPU_IsSupported_AES(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
int z7_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize);
|
||||||
|
int z7_sysctlbyname_Get_UInt32(const char *name, UInt32 *val);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
/* Delta.c -- Delta converter
|
||||||
|
2021-02-09 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#include "Precomp.h"
|
||||||
|
|
||||||
|
#include "Delta.h"
|
||||||
|
|
||||||
|
void Delta_Init(Byte *state)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < DELTA_STATE_SIZE; i++)
|
||||||
|
state[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size)
|
||||||
|
{
|
||||||
|
Byte temp[DELTA_STATE_SIZE];
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
{
|
||||||
|
unsigned i = 0;
|
||||||
|
do
|
||||||
|
temp[i] = state[i];
|
||||||
|
while (++i != delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size <= delta)
|
||||||
|
{
|
||||||
|
unsigned i = 0, k;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Byte b = *data;
|
||||||
|
*data++ = (Byte)(b - temp[i]);
|
||||||
|
temp[i] = b;
|
||||||
|
}
|
||||||
|
while (++i != size);
|
||||||
|
|
||||||
|
k = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (i == delta)
|
||||||
|
i = 0;
|
||||||
|
state[k] = temp[i++];
|
||||||
|
}
|
||||||
|
while (++k != delta);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Byte *p = data + size - delta;
|
||||||
|
{
|
||||||
|
unsigned i = 0;
|
||||||
|
do
|
||||||
|
state[i] = *p++;
|
||||||
|
while (++i != delta);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const Byte *lim = data + delta;
|
||||||
|
ptrdiff_t dif = -(ptrdiff_t)delta;
|
||||||
|
|
||||||
|
if (((ptrdiff_t)size + dif) & 1)
|
||||||
|
{
|
||||||
|
--p; *p = (Byte)(*p - p[dif]);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (p != lim)
|
||||||
|
{
|
||||||
|
--p; *p = (Byte)(*p - p[dif]);
|
||||||
|
--p; *p = (Byte)(*p - p[dif]);
|
||||||
|
}
|
||||||
|
|
||||||
|
dif = -dif;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
--p; *p = (Byte)(*p - temp[--dif]);
|
||||||
|
}
|
||||||
|
while (dif != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
const Byte *lim;
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
lim = data + size;
|
||||||
|
|
||||||
|
if (size <= delta)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
*data = (Byte)(*data + state[i++]);
|
||||||
|
while (++data != lim);
|
||||||
|
|
||||||
|
for (; delta != i; state++, delta--)
|
||||||
|
*state = state[i];
|
||||||
|
data -= i;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
#define B(n) b ## n
|
||||||
|
#define I(n) Byte B(n) = state[n];
|
||||||
|
#define U(n) { B(n) = (Byte)((B(n)) + *data++); data[-1] = (B(n)); }
|
||||||
|
#define F(n) if (data != lim) { U(n) }
|
||||||
|
|
||||||
|
if (delta == 1)
|
||||||
|
{
|
||||||
|
I(0)
|
||||||
|
if ((lim - data) & 1) { U(0) }
|
||||||
|
while (data != lim) { U(0) U(0) }
|
||||||
|
data -= 1;
|
||||||
|
}
|
||||||
|
else if (delta == 2)
|
||||||
|
{
|
||||||
|
I(0) I(1)
|
||||||
|
lim -= 1; while (data < lim) { U(0) U(1) }
|
||||||
|
lim += 1; F(0)
|
||||||
|
data -= 2;
|
||||||
|
}
|
||||||
|
else if (delta == 3)
|
||||||
|
{
|
||||||
|
I(0) I(1) I(2)
|
||||||
|
lim -= 2; while (data < lim) { U(0) U(1) U(2) }
|
||||||
|
lim += 2; F(0) F(1)
|
||||||
|
data -= 3;
|
||||||
|
}
|
||||||
|
else if (delta == 4)
|
||||||
|
{
|
||||||
|
I(0) I(1) I(2) I(3)
|
||||||
|
lim -= 3; while (data < lim) { U(0) U(1) U(2) U(3) }
|
||||||
|
lim += 3; F(0) F(1) F(2)
|
||||||
|
data -= 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
*data = (Byte)(*data + state[i++]);
|
||||||
|
data++;
|
||||||
|
}
|
||||||
|
while (i != delta);
|
||||||
|
|
||||||
|
{
|
||||||
|
ptrdiff_t dif = -(ptrdiff_t)delta;
|
||||||
|
do
|
||||||
|
*data = (Byte)(*data + data[dif]);
|
||||||
|
while (++data != lim);
|
||||||
|
data += dif;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
*state++ = *data;
|
||||||
|
while (++data != lim);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/* Delta.h -- Delta converter
|
||||||
|
2023-03-03 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_DELTA_H
|
||||||
|
#define ZIP7_INC_DELTA_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
#define DELTA_STATE_SIZE 256
|
||||||
|
|
||||||
|
void Delta_Init(Byte *state);
|
||||||
|
void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size);
|
||||||
|
void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/* DllSecur.h -- DLL loading for security
|
||||||
|
2023-03-03 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_DLL_SECUR_H
|
||||||
|
#define ZIP7_INC_DLL_SECUR_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
void My_SetDefaultDllDirectories(void);
|
||||||
|
void LoadSecurityDlls(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,404 @@
|
|||||||
|
LZMA SDK 23.01
|
||||||
|
--------------
|
||||||
|
|
||||||
|
LZMA SDK provides the documentation, samples, header files,
|
||||||
|
libraries, and tools you need to develop applications that
|
||||||
|
use 7z / LZMA / LZMA2 / XZ compression.
|
||||||
|
|
||||||
|
LZMA is an improved version of famous LZ77 compression algorithm.
|
||||||
|
It was improved in way of maximum increasing of compression ratio,
|
||||||
|
keeping high decompression speed and low memory requirements for
|
||||||
|
decompressing.
|
||||||
|
|
||||||
|
LZMA2 is a LZMA based compression method. LZMA2 provides better
|
||||||
|
multithreading support for compression than LZMA and some other improvements.
|
||||||
|
|
||||||
|
7z is a file format for data compression and file archiving.
|
||||||
|
7z is a main file format for 7-Zip compression program (www.7-zip.org).
|
||||||
|
7z format supports different compression methods: LZMA, LZMA2 and others.
|
||||||
|
7z also supports AES-256 based encryption.
|
||||||
|
|
||||||
|
XZ is a file format for data compression that uses LZMA2 compression.
|
||||||
|
XZ format provides additional features: SHA/CRC check, filters for
|
||||||
|
improved compression ratio, splitting to blocks and streams,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LICENSE
|
||||||
|
-------
|
||||||
|
|
||||||
|
LZMA SDK is written and placed in the public domain by Igor Pavlov.
|
||||||
|
|
||||||
|
Some code in LZMA SDK is based on public domain code from another developers:
|
||||||
|
1) PPMd var.H (2001): Dmitry Shkarin
|
||||||
|
2) SHA-256: Wei Dai (Crypto++ library)
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or distribute the
|
||||||
|
original LZMA SDK code, either in source code form or as a compiled binary, for
|
||||||
|
any purpose, commercial or non-commercial, and by any means.
|
||||||
|
|
||||||
|
LZMA SDK code is compatible with open source licenses, for example, you can
|
||||||
|
include it to GNU GPL or GNU LGPL code.
|
||||||
|
|
||||||
|
|
||||||
|
LZMA SDK Contents
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Source code:
|
||||||
|
|
||||||
|
- C / C++ / C# / Java - LZMA compression and decompression
|
||||||
|
- C / C++ - LZMA2 compression and decompression
|
||||||
|
- C / C++ - XZ compression and decompression
|
||||||
|
- C - 7z decompression
|
||||||
|
- C++ - 7z compression and decompression
|
||||||
|
- C - small SFXs for installers (7z decompression)
|
||||||
|
- C++ - SFXs and SFXs for installers (7z decompression)
|
||||||
|
|
||||||
|
Precomiled binaries:
|
||||||
|
|
||||||
|
- console programs for lzma / 7z / xz compression and decompression
|
||||||
|
- SFX modules for installers.
|
||||||
|
|
||||||
|
|
||||||
|
UNIX/Linux version
|
||||||
|
------------------
|
||||||
|
There are several otpions to compile 7-Zip with different compilers: gcc and clang.
|
||||||
|
Also 7-Zip code contains two versions for some critical parts of code: in C and in Assembeler.
|
||||||
|
So if you compile the version with Assembeler code, you will get faster 7-Zip binary.
|
||||||
|
|
||||||
|
7-Zip's assembler code uses the following syntax for different platforms:
|
||||||
|
|
||||||
|
1) x86 and x86-64 (AMD64): MASM syntax.
|
||||||
|
There are 2 programs that supports MASM syntax in Linux.
|
||||||
|
' 'Asmc Macro Assembler and JWasm. But JWasm now doesn't support some
|
||||||
|
cpu instructions used in 7-Zip.
|
||||||
|
So you must install Asmc Macro Assembler in Linux, if you want to compile fastest version
|
||||||
|
of 7-Zip x86 and x86-64:
|
||||||
|
https://github.com/nidud/asmc
|
||||||
|
|
||||||
|
2) arm64: GNU assembler for ARM64 with preprocessor.
|
||||||
|
That systax of that arm64 assembler code in 7-Zip is supported by GCC and CLANG for ARM64.
|
||||||
|
|
||||||
|
There are different binaries that can be compiled from 7-Zip source.
|
||||||
|
There are 2 main files in folder for compiling:
|
||||||
|
makefile - that can be used for compiling Windows version of 7-Zip with nmake command
|
||||||
|
makefile.gcc - that can be used for compiling Linux/macOS versions of 7-Zip with make command
|
||||||
|
|
||||||
|
At first you must change the current folder to folder that contains `makefile.gcc`:
|
||||||
|
|
||||||
|
cd CPP/7zip/Bundles/Alone7z
|
||||||
|
|
||||||
|
Then you can compile `makefile.gcc` with the command:
|
||||||
|
|
||||||
|
make -j -f makefile.gcc
|
||||||
|
|
||||||
|
Also there are additional "*.mak" files in folder "CPP/7zip/" that can be used to compile
|
||||||
|
7-Zip binaries with optimized code and optimzing options.
|
||||||
|
|
||||||
|
To compile with GCC without assembler:
|
||||||
|
cd CPP/7zip/Bundles/Alone7z
|
||||||
|
make -j -f ../../cmpl_gcc.mak
|
||||||
|
|
||||||
|
To compile with CLANG without assembler:
|
||||||
|
make -j -f ../../cmpl_clang.mak
|
||||||
|
|
||||||
|
To compile 7-Zip for x86-64 with asmc assembler:
|
||||||
|
make -j -f ../../cmpl_gcc_x64.mak
|
||||||
|
|
||||||
|
To compile 7-Zip for arm64 with assembler:
|
||||||
|
make -j -f ../../cmpl_gcc_arm64.mak
|
||||||
|
|
||||||
|
To compile 7-Zip for arm64 for macOS:
|
||||||
|
make -j -f ../../cmpl_mac_arm64.mak
|
||||||
|
|
||||||
|
Also you can change some compiler options in the mak files:
|
||||||
|
cmpl_gcc.mak
|
||||||
|
var_gcc.mak
|
||||||
|
warn_gcc.mak
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Also you can use p7zip (port of 7-Zip for POSIX systems like Unix or Linux):
|
||||||
|
|
||||||
|
http://p7zip.sourceforge.net/
|
||||||
|
|
||||||
|
|
||||||
|
Files
|
||||||
|
-----
|
||||||
|
|
||||||
|
DOC/7zC.txt - 7z ANSI-C Decoder description
|
||||||
|
DOC/7zFormat.txt - 7z Format description
|
||||||
|
DOC/installer.txt - information about 7-Zip for installers
|
||||||
|
DOC/lzma.txt - LZMA compression description
|
||||||
|
DOC/lzma-sdk.txt - LZMA SDK description (this file)
|
||||||
|
DOC/lzma-history.txt - history of LZMA SDK
|
||||||
|
DOC/lzma-specification.txt - Specification of LZMA
|
||||||
|
DOC/Methods.txt - Compression method IDs for .7z
|
||||||
|
|
||||||
|
bin/installer/ - example script to create installer that uses SFX module,
|
||||||
|
|
||||||
|
bin/7zdec.exe - simplified 7z archive decoder
|
||||||
|
bin/7zr.exe - 7-Zip console program (reduced version)
|
||||||
|
bin/x64/7zr.exe - 7-Zip console program (reduced version) (x64 version)
|
||||||
|
bin/lzma.exe - file->file LZMA encoder/decoder for Windows
|
||||||
|
bin/7zS2.sfx - small SFX module for installers (GUI version)
|
||||||
|
bin/7zS2con.sfx - small SFX module for installers (Console version)
|
||||||
|
bin/7zSD.sfx - SFX module for installers.
|
||||||
|
|
||||||
|
|
||||||
|
7zDec.exe
|
||||||
|
---------
|
||||||
|
7zDec.exe is simplified 7z archive decoder.
|
||||||
|
It supports only LZMA, LZMA2, and PPMd methods.
|
||||||
|
7zDec decodes whole solid block from 7z archive to RAM.
|
||||||
|
The RAM consumption can be high.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Source code structure
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
|
||||||
|
Asm/ - asm files (optimized code for CRC calculation and Intel-AES encryption)
|
||||||
|
|
||||||
|
C/ - C files (compression / decompression and other)
|
||||||
|
Util/
|
||||||
|
7z - 7z decoder program (decoding 7z files)
|
||||||
|
Lzma - LZMA program (file->file LZMA encoder/decoder).
|
||||||
|
LzmaLib - LZMA library (.DLL for Windows)
|
||||||
|
SfxSetup - small SFX module for installers
|
||||||
|
|
||||||
|
CPP/ -- CPP files
|
||||||
|
|
||||||
|
Common - common files for C++ projects
|
||||||
|
Windows - common files for Windows related code
|
||||||
|
|
||||||
|
7zip - files related to 7-Zip
|
||||||
|
|
||||||
|
Archive - files related to archiving
|
||||||
|
|
||||||
|
Common - common files for archive handling
|
||||||
|
7z - 7z C++ Encoder/Decoder
|
||||||
|
|
||||||
|
Bundles - Modules that are bundles of other modules (files)
|
||||||
|
|
||||||
|
Alone7z - 7zr.exe: Standalone 7-Zip console program (reduced version)
|
||||||
|
Format7zExtractR - 7zxr.dll: Reduced version of 7z DLL: extracting from 7z/LZMA/BCJ/BCJ2.
|
||||||
|
Format7zR - 7zr.dll: Reduced version of 7z DLL: extracting/compressing to 7z/LZMA/BCJ/BCJ2
|
||||||
|
LzmaCon - lzma.exe: LZMA compression/decompression
|
||||||
|
LzmaSpec - example code for LZMA Specification
|
||||||
|
SFXCon - 7zCon.sfx: Console 7z SFX module
|
||||||
|
SFXSetup - 7zS.sfx: 7z SFX module for installers
|
||||||
|
SFXWin - 7z.sfx: GUI 7z SFX module
|
||||||
|
|
||||||
|
Common - common files for 7-Zip
|
||||||
|
|
||||||
|
Compress - files for compression/decompression
|
||||||
|
|
||||||
|
Crypto - files for encryption / decompression
|
||||||
|
|
||||||
|
UI - User Interface files
|
||||||
|
|
||||||
|
Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll
|
||||||
|
Common - Common UI files
|
||||||
|
Console - Code for console program (7z.exe)
|
||||||
|
Explorer - Some code from 7-Zip Shell extension
|
||||||
|
FileManager - Some GUI code from 7-Zip File Manager
|
||||||
|
GUI - Some GUI code from 7-Zip
|
||||||
|
|
||||||
|
|
||||||
|
CS/ - C# files
|
||||||
|
7zip
|
||||||
|
Common - some common files for 7-Zip
|
||||||
|
Compress - files related to compression/decompression
|
||||||
|
LZ - files related to LZ (Lempel-Ziv) compression algorithm
|
||||||
|
LZMA - LZMA compression/decompression
|
||||||
|
LzmaAlone - file->file LZMA compression/decompression
|
||||||
|
RangeCoder - Range Coder (special code of compression/decompression)
|
||||||
|
|
||||||
|
Java/ - Java files
|
||||||
|
SevenZip
|
||||||
|
Compression - files related to compression/decompression
|
||||||
|
LZ - files related to LZ (Lempel-Ziv) compression algorithm
|
||||||
|
LZMA - LZMA compression/decompression
|
||||||
|
RangeCoder - Range Coder (special code of compression/decompression)
|
||||||
|
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Asm / C / C++ source code of LZMA SDK is part of 7-Zip's source code.
|
||||||
|
7-Zip's source code can be downloaded from 7-Zip's SourceForge page:
|
||||||
|
|
||||||
|
http://sourceforge.net/projects/sevenzip/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LZMA features
|
||||||
|
-------------
|
||||||
|
- Variable dictionary size (up to 1 GB)
|
||||||
|
- Estimated compressing speed: about 2 MB/s on 2 GHz CPU
|
||||||
|
- Estimated decompressing speed:
|
||||||
|
- 20-30 MB/s on modern 2 GHz cpu
|
||||||
|
- 1-2 MB/s on 200 MHz simple RISC cpu: (ARM, MIPS, PowerPC)
|
||||||
|
- Small memory requirements for decompressing (16 KB + DictionarySize)
|
||||||
|
- Small code size for decompressing: 5-8 KB
|
||||||
|
|
||||||
|
LZMA decoder uses only integer operations and can be
|
||||||
|
implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions).
|
||||||
|
|
||||||
|
Some critical operations that affect the speed of LZMA decompression:
|
||||||
|
1) 32*16 bit integer multiply
|
||||||
|
2) Mispredicted branches (penalty mostly depends from pipeline length)
|
||||||
|
3) 32-bit shift and arithmetic operations
|
||||||
|
|
||||||
|
The speed of LZMA decompressing mostly depends from CPU speed.
|
||||||
|
Memory speed has no big meaning. But if your CPU has small data cache,
|
||||||
|
overall weight of memory speed will slightly increase.
|
||||||
|
|
||||||
|
|
||||||
|
How To Use
|
||||||
|
----------
|
||||||
|
|
||||||
|
Using LZMA encoder/decoder executable
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
Usage: LZMA <e|d> inputFile outputFile [<switches>...]
|
||||||
|
|
||||||
|
e: encode file
|
||||||
|
|
||||||
|
d: decode file
|
||||||
|
|
||||||
|
b: Benchmark. There are two tests: compressing and decompressing
|
||||||
|
with LZMA method. Benchmark shows rating in MIPS (million
|
||||||
|
instructions per second). Rating value is calculated from
|
||||||
|
measured speed and it is normalized with Intel's Core 2 results.
|
||||||
|
Also Benchmark checks possible hardware errors (RAM
|
||||||
|
errors in most cases). Benchmark uses these settings:
|
||||||
|
(-a1, -d21, -fb32, -mfbt4). You can change only -d parameter.
|
||||||
|
Also you can change the number of iterations. Example for 30 iterations:
|
||||||
|
LZMA b 30
|
||||||
|
Default number of iterations is 10.
|
||||||
|
|
||||||
|
<Switches>
|
||||||
|
|
||||||
|
|
||||||
|
-a{N}: set compression mode 0 = fast, 1 = normal
|
||||||
|
default: 1 (normal)
|
||||||
|
|
||||||
|
d{N}: Sets Dictionary size - [0, 30], default: 23 (8MB)
|
||||||
|
The maximum value for dictionary size is 1 GB = 2^30 bytes.
|
||||||
|
Dictionary size is calculated as DictionarySize = 2^N bytes.
|
||||||
|
For decompressing file compressed by LZMA method with dictionary
|
||||||
|
size D = 2^N you need about D bytes of memory (RAM).
|
||||||
|
|
||||||
|
-fb{N}: set number of fast bytes - [5, 273], default: 128
|
||||||
|
Usually big number gives a little bit better compression ratio
|
||||||
|
and slower compression process.
|
||||||
|
|
||||||
|
-lc{N}: set number of literal context bits - [0, 8], default: 3
|
||||||
|
Sometimes lc=4 gives gain for big files.
|
||||||
|
|
||||||
|
-lp{N}: set number of literal pos bits - [0, 4], default: 0
|
||||||
|
lp switch is intended for periodical data when period is
|
||||||
|
equal 2^N. For example, for 32-bit (4 bytes)
|
||||||
|
periodical data you can use lp=2. Often it's better to set lc0,
|
||||||
|
if you change lp switch.
|
||||||
|
|
||||||
|
-pb{N}: set number of pos bits - [0, 4], default: 2
|
||||||
|
pb switch is intended for periodical data
|
||||||
|
when period is equal 2^N.
|
||||||
|
|
||||||
|
-mf{MF_ID}: set Match Finder. Default: bt4.
|
||||||
|
Algorithms from hc* group doesn't provide good compression
|
||||||
|
ratio, but they often works pretty fast in combination with
|
||||||
|
fast mode (-a0).
|
||||||
|
|
||||||
|
Memory requirements depend from dictionary size
|
||||||
|
(parameter "d" in table below).
|
||||||
|
|
||||||
|
MF_ID Memory Description
|
||||||
|
|
||||||
|
bt2 d * 9.5 + 4MB Binary Tree with 2 bytes hashing.
|
||||||
|
bt3 d * 11.5 + 4MB Binary Tree with 3 bytes hashing.
|
||||||
|
bt4 d * 11.5 + 4MB Binary Tree with 4 bytes hashing.
|
||||||
|
hc4 d * 7.5 + 4MB Hash Chain with 4 bytes hashing.
|
||||||
|
|
||||||
|
-eos: write End Of Stream marker. By default LZMA doesn't write
|
||||||
|
eos marker, since LZMA decoder knows uncompressed size
|
||||||
|
stored in .lzma file header.
|
||||||
|
|
||||||
|
-si: Read data from stdin (it will write End Of Stream marker).
|
||||||
|
-so: Write data to stdout
|
||||||
|
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
1) LZMA e file.bin file.lzma -d16 -lc0
|
||||||
|
|
||||||
|
compresses file.bin to file.lzma with 64 KB dictionary (2^16=64K)
|
||||||
|
and 0 literal context bits. -lc0 allows to reduce memory requirements
|
||||||
|
for decompression.
|
||||||
|
|
||||||
|
|
||||||
|
2) LZMA e file.bin file.lzma -lc0 -lp2
|
||||||
|
|
||||||
|
compresses file.bin to file.lzma with settings suitable
|
||||||
|
for 32-bit periodical data (for example, ARM or MIPS code).
|
||||||
|
|
||||||
|
3) LZMA d file.lzma file.bin
|
||||||
|
|
||||||
|
decompresses file.lzma to file.bin.
|
||||||
|
|
||||||
|
|
||||||
|
Compression ratio hints
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Recommendations
|
||||||
|
---------------
|
||||||
|
|
||||||
|
To increase the compression ratio for LZMA compressing it's desirable
|
||||||
|
to have aligned data (if it's possible) and also it's desirable to locate
|
||||||
|
data in such order, where code is grouped in one place and data is
|
||||||
|
grouped in other place (it's better than such mixing: code, data, code,
|
||||||
|
data, ...).
|
||||||
|
|
||||||
|
|
||||||
|
Filters
|
||||||
|
-------
|
||||||
|
You can increase the compression ratio for some data types, using
|
||||||
|
special filters before compressing. For example, it's possible to
|
||||||
|
increase the compression ratio on 5-10% for code for those CPU ISAs:
|
||||||
|
x86, IA-64, ARM, ARM-Thumb, PowerPC, SPARC.
|
||||||
|
|
||||||
|
You can find C source code of such filters in C/Bra*.* files
|
||||||
|
|
||||||
|
You can check the compression ratio gain of these filters with such
|
||||||
|
7-Zip commands (example for ARM code):
|
||||||
|
No filter:
|
||||||
|
7z a a1.7z a.bin -m0=lzma
|
||||||
|
|
||||||
|
With filter for little-endian ARM code:
|
||||||
|
7z a a2.7z a.bin -m0=arm -m1=lzma
|
||||||
|
|
||||||
|
It works in such manner:
|
||||||
|
Compressing = Filter_encoding + LZMA_encoding
|
||||||
|
Decompressing = LZMA_decoding + Filter_decoding
|
||||||
|
|
||||||
|
Compressing and decompressing speed of such filters is very high,
|
||||||
|
so it will not increase decompressing time too much.
|
||||||
|
Moreover, it reduces decompression time for LZMA_decoding,
|
||||||
|
since compression ratio with filtering is higher.
|
||||||
|
|
||||||
|
These filters convert CALL (calling procedure) instructions
|
||||||
|
from relative offsets to absolute addresses, so such data becomes more
|
||||||
|
compressible.
|
||||||
|
|
||||||
|
For some ISAs (for example, for MIPS) it's impossible to get gain from such filter.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
http://www.7-zip.org
|
||||||
|
http://www.7-zip.org/sdk.html
|
||||||
|
http://www.7-zip.org/support.html
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
/* LzFind.h -- Match finder for LZ algorithms
|
||||||
|
2023-03-04 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_LZ_FIND_H
|
||||||
|
#define ZIP7_INC_LZ_FIND_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
typedef UInt32 CLzRef;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const Byte *buffer;
|
||||||
|
UInt32 pos;
|
||||||
|
UInt32 posLimit;
|
||||||
|
UInt32 streamPos; /* wrap over Zero is allowed (streamPos < pos). Use (UInt32)(streamPos - pos) */
|
||||||
|
UInt32 lenLimit;
|
||||||
|
|
||||||
|
UInt32 cyclicBufferPos;
|
||||||
|
UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
|
||||||
|
|
||||||
|
Byte streamEndWasReached;
|
||||||
|
Byte btMode;
|
||||||
|
Byte bigHash;
|
||||||
|
Byte directInput;
|
||||||
|
|
||||||
|
UInt32 matchMaxLen;
|
||||||
|
CLzRef *hash;
|
||||||
|
CLzRef *son;
|
||||||
|
UInt32 hashMask;
|
||||||
|
UInt32 cutValue;
|
||||||
|
|
||||||
|
Byte *bufBase;
|
||||||
|
ISeqInStreamPtr stream;
|
||||||
|
|
||||||
|
UInt32 blockSize;
|
||||||
|
UInt32 keepSizeBefore;
|
||||||
|
UInt32 keepSizeAfter;
|
||||||
|
|
||||||
|
UInt32 numHashBytes;
|
||||||
|
size_t directInputRem;
|
||||||
|
UInt32 historySize;
|
||||||
|
UInt32 fixedHashSize;
|
||||||
|
Byte numHashBytes_Min;
|
||||||
|
Byte numHashOutBits;
|
||||||
|
Byte _pad2_[2];
|
||||||
|
SRes result;
|
||||||
|
UInt32 crc[256];
|
||||||
|
size_t numRefs;
|
||||||
|
|
||||||
|
UInt64 expectedDataSize;
|
||||||
|
} CMatchFinder;
|
||||||
|
|
||||||
|
#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((const Byte *)(p)->buffer)
|
||||||
|
|
||||||
|
#define Inline_MatchFinder_GetNumAvailableBytes(p) ((UInt32)((p)->streamPos - (p)->pos))
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define Inline_MatchFinder_IsFinishedOK(p) \
|
||||||
|
((p)->streamEndWasReached \
|
||||||
|
&& (p)->streamPos == (p)->pos \
|
||||||
|
&& (!(p)->directInput || (p)->directInputRem == 0))
|
||||||
|
*/
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* (directInput = 0) is default value.
|
||||||
|
It's required to provide correct (directInput) value
|
||||||
|
before calling MatchFinder_Create().
|
||||||
|
You can set (directInput) by any of the following calls:
|
||||||
|
- MatchFinder_SET_DIRECT_INPUT_BUF()
|
||||||
|
- MatchFinder_SET_STREAM()
|
||||||
|
- MatchFinder_SET_STREAM_MODE()
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MatchFinder_SET_DIRECT_INPUT_BUF(p, _src_, _srcLen_) { \
|
||||||
|
(p)->stream = NULL; \
|
||||||
|
(p)->directInput = 1; \
|
||||||
|
(p)->buffer = (_src_); \
|
||||||
|
(p)->directInputRem = (_srcLen_); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define MatchFinder_SET_STREAM_MODE(p) { \
|
||||||
|
(p)->directInput = 0; }
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MatchFinder_SET_STREAM(p, _stream_) { \
|
||||||
|
(p)->stream = _stream_; \
|
||||||
|
(p)->directInput = 0; }
|
||||||
|
|
||||||
|
|
||||||
|
int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
|
||||||
|
UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
|
||||||
|
ISzAllocPtr alloc);
|
||||||
|
void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc);
|
||||||
|
void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems);
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define MatchFinder_INIT_POS(p, val) \
|
||||||
|
(p)->pos = (val); \
|
||||||
|
(p)->streamPos = (val);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
|
||||||
|
#define MatchFinder_REDUCE_OFFSETS(p, subValue) \
|
||||||
|
(p)->pos -= (subValue); \
|
||||||
|
(p)->streamPos -= (subValue);
|
||||||
|
|
||||||
|
|
||||||
|
UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
|
||||||
|
size_t _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 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
|
||||||
|
{
|
||||||
|
Mf_Init_Func Init;
|
||||||
|
Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
|
||||||
|
Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
|
||||||
|
Mf_GetMatches_Func GetMatches;
|
||||||
|
Mf_Skip_Func Skip;
|
||||||
|
} IMatchFinder2;
|
||||||
|
|
||||||
|
void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable);
|
||||||
|
|
||||||
|
void MatchFinder_Init_LowHash(CMatchFinder *p);
|
||||||
|
void MatchFinder_Init_HighHash(CMatchFinder *p);
|
||||||
|
void MatchFinder_Init_4(CMatchFinder *p);
|
||||||
|
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);
|
||||||
|
|
||||||
|
void LzFindPrepare(void);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
/* LzFindMt.h -- multithreaded Match finder for LZ algorithms
|
||||||
|
2023-03-05 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_LZ_FIND_MT_H
|
||||||
|
#define ZIP7_INC_LZ_FIND_MT_H
|
||||||
|
|
||||||
|
#include "LzFind.h"
|
||||||
|
#include "Threads.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UInt32 numProcessedBlocks;
|
||||||
|
CThread thread;
|
||||||
|
UInt64 affinity;
|
||||||
|
|
||||||
|
BoolInt wasCreated;
|
||||||
|
BoolInt needStart;
|
||||||
|
BoolInt csWasInitialized;
|
||||||
|
BoolInt csWasEntered;
|
||||||
|
|
||||||
|
BoolInt exit;
|
||||||
|
BoolInt stopWriting;
|
||||||
|
|
||||||
|
CAutoResetEvent canStart;
|
||||||
|
CAutoResetEvent wasStopped;
|
||||||
|
CSemaphore freeSemaphore;
|
||||||
|
CSemaphore filledSemaphore;
|
||||||
|
CCriticalSection cs;
|
||||||
|
// UInt32 numBlocks_Sent;
|
||||||
|
} CMtSync;
|
||||||
|
|
||||||
|
typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distances);
|
||||||
|
|
||||||
|
/* kMtCacheLineDummy must be >= size_of_CPU_cache_line */
|
||||||
|
#define kMtCacheLineDummy 128
|
||||||
|
|
||||||
|
typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos,
|
||||||
|
UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* LZ */
|
||||||
|
const Byte *pointerToCurPos;
|
||||||
|
UInt32 *btBuf;
|
||||||
|
const UInt32 *btBufPos;
|
||||||
|
const UInt32 *btBufPosLimit;
|
||||||
|
UInt32 lzPos;
|
||||||
|
UInt32 btNumAvailBytes;
|
||||||
|
|
||||||
|
UInt32 *hash;
|
||||||
|
UInt32 fixedHashSize;
|
||||||
|
// UInt32 hash4Mask;
|
||||||
|
UInt32 historySize;
|
||||||
|
const UInt32 *crc;
|
||||||
|
|
||||||
|
Mf_Mix_Matches MixMatchesFunc;
|
||||||
|
UInt32 failure_LZ_BT; // failure in BT transfered to LZ
|
||||||
|
// UInt32 failure_LZ_LZ; // failure in LZ tables
|
||||||
|
UInt32 failureBuf[1];
|
||||||
|
// UInt32 crc[256];
|
||||||
|
|
||||||
|
/* LZ + BT */
|
||||||
|
CMtSync btSync;
|
||||||
|
Byte btDummy[kMtCacheLineDummy];
|
||||||
|
|
||||||
|
/* BT */
|
||||||
|
UInt32 *hashBuf;
|
||||||
|
UInt32 hashBufPos;
|
||||||
|
UInt32 hashBufPosLimit;
|
||||||
|
UInt32 hashNumAvail;
|
||||||
|
UInt32 failure_BT;
|
||||||
|
|
||||||
|
|
||||||
|
CLzRef *son;
|
||||||
|
UInt32 matchMaxLen;
|
||||||
|
UInt32 numHashBytes;
|
||||||
|
UInt32 pos;
|
||||||
|
const Byte *buffer;
|
||||||
|
UInt32 cyclicBufferPos;
|
||||||
|
UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
|
||||||
|
UInt32 cutValue;
|
||||||
|
|
||||||
|
/* BT + Hash */
|
||||||
|
CMtSync hashSync;
|
||||||
|
/* Byte hashDummy[kMtCacheLineDummy]; */
|
||||||
|
|
||||||
|
/* Hash */
|
||||||
|
Mf_GetHeads GetHeadsFunc;
|
||||||
|
CMatchFinder *MatchFinder;
|
||||||
|
// CMatchFinder MatchFinder;
|
||||||
|
} CMatchFinderMt;
|
||||||
|
|
||||||
|
// only for Mt part
|
||||||
|
void MatchFinderMt_Construct(CMatchFinderMt *p);
|
||||||
|
void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc);
|
||||||
|
|
||||||
|
SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
|
||||||
|
UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc);
|
||||||
|
void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder2 *vTable);
|
||||||
|
|
||||||
|
/* call MatchFinderMt_InitMt() before IMatchFinder::Init() */
|
||||||
|
SRes MatchFinderMt_InitMt(CMatchFinderMt *p);
|
||||||
|
void MatchFinderMt_ReleaseStream(CMatchFinderMt *p);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/* LzHash.h -- HASH constants for LZ algorithms
|
||||||
|
2023-03-05 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_LZ_HASH_H
|
||||||
|
#define ZIP7_INC_LZ_HASH_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
(kHash2Size >= (1 << 8)) : Required
|
||||||
|
(kHash3Size >= (1 << 16)) : Required
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define kHash2Size (1 << 10)
|
||||||
|
#define kHash3Size (1 << 16)
|
||||||
|
// #define kHash4Size (1 << 20)
|
||||||
|
|
||||||
|
#define kFix3HashSize (kHash2Size)
|
||||||
|
#define kFix4HashSize (kHash2Size + kHash3Size)
|
||||||
|
// #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
|
||||||
|
|
||||||
|
/*
|
||||||
|
We use up to 3 crc values for hash:
|
||||||
|
crc0
|
||||||
|
crc1 << Shift_1
|
||||||
|
crc2 << Shift_2
|
||||||
|
(Shift_1 = 5) and (Shift_2 = 10) is good tradeoff.
|
||||||
|
Small values for Shift are not good for collision rate.
|
||||||
|
Big value for Shift_2 increases the minimum size
|
||||||
|
of hash table, that will be slow for small files.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define kLzHash_CrcShift_1 5
|
||||||
|
#define kLzHash_CrcShift_2 10
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,491 @@
|
|||||||
|
/* Lzma2Dec.c -- LZMA2 Decoder
|
||||||
|
2023-03-03 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
/* #define SHOW_DEBUG_INFO */
|
||||||
|
|
||||||
|
#include "Precomp.h"
|
||||||
|
|
||||||
|
#ifdef SHOW_DEBUG_INFO
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "Lzma2Dec.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
00000000 - End of data
|
||||||
|
00000001 U U - Uncompressed, reset dic, need reset state and set new prop
|
||||||
|
00000010 U U - Uncompressed, no reset
|
||||||
|
100uuuuu U U P P - LZMA, no reset
|
||||||
|
101uuuuu U U P P - LZMA, reset state
|
||||||
|
110uuuuu U U P P S - LZMA, reset state + set new prop
|
||||||
|
111uuuuu U U P P S - LZMA, reset state + set new prop, reset dic
|
||||||
|
|
||||||
|
u, U - Unpack Size
|
||||||
|
P - Pack Size
|
||||||
|
S - Props
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LZMA2_CONTROL_COPY_RESET_DIC 1
|
||||||
|
|
||||||
|
#define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & (1 << 7)) == 0)
|
||||||
|
|
||||||
|
#define LZMA2_LCLP_MAX 4
|
||||||
|
#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11))
|
||||||
|
|
||||||
|
#ifdef SHOW_DEBUG_INFO
|
||||||
|
#define PRF(x) x
|
||||||
|
#else
|
||||||
|
#define PRF(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
LZMA2_STATE_CONTROL,
|
||||||
|
LZMA2_STATE_UNPACK0,
|
||||||
|
LZMA2_STATE_UNPACK1,
|
||||||
|
LZMA2_STATE_PACK0,
|
||||||
|
LZMA2_STATE_PACK1,
|
||||||
|
LZMA2_STATE_PROP,
|
||||||
|
LZMA2_STATE_DATA,
|
||||||
|
LZMA2_STATE_DATA_CONT,
|
||||||
|
LZMA2_STATE_FINISHED,
|
||||||
|
LZMA2_STATE_ERROR
|
||||||
|
} ELzma2State;
|
||||||
|
|
||||||
|
static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props)
|
||||||
|
{
|
||||||
|
UInt32 dicSize;
|
||||||
|
if (prop > 40)
|
||||||
|
return SZ_ERROR_UNSUPPORTED;
|
||||||
|
dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop);
|
||||||
|
props[0] = (Byte)LZMA2_LCLP_MAX;
|
||||||
|
props[1] = (Byte)(dicSize);
|
||||||
|
props[2] = (Byte)(dicSize >> 8);
|
||||||
|
props[3] = (Byte)(dicSize >> 16);
|
||||||
|
props[4] = (Byte)(dicSize >> 24);
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc)
|
||||||
|
{
|
||||||
|
Byte props[LZMA_PROPS_SIZE];
|
||||||
|
RINOK(Lzma2Dec_GetOldProps(prop, props))
|
||||||
|
return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc)
|
||||||
|
{
|
||||||
|
Byte props[LZMA_PROPS_SIZE];
|
||||||
|
RINOK(Lzma2Dec_GetOldProps(prop, props))
|
||||||
|
return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lzma2Dec_Init(CLzma2Dec *p)
|
||||||
|
{
|
||||||
|
p->state = LZMA2_STATE_CONTROL;
|
||||||
|
p->needInitLevel = 0xE0;
|
||||||
|
p->isExtraMode = False;
|
||||||
|
p->unpackSize = 0;
|
||||||
|
|
||||||
|
// p->decoder.dicPos = 0; // we can use it instead of full init
|
||||||
|
LzmaDec_Init(&p->decoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ELzma2State
|
||||||
|
static unsigned Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b)
|
||||||
|
{
|
||||||
|
switch (p->state)
|
||||||
|
{
|
||||||
|
case LZMA2_STATE_CONTROL:
|
||||||
|
p->isExtraMode = False;
|
||||||
|
p->control = b;
|
||||||
|
PRF(printf("\n %8X", (unsigned)p->decoder.dicPos));
|
||||||
|
PRF(printf(" %02X", (unsigned)b));
|
||||||
|
if (b == 0)
|
||||||
|
return LZMA2_STATE_FINISHED;
|
||||||
|
if (LZMA2_IS_UNCOMPRESSED_STATE(p))
|
||||||
|
{
|
||||||
|
if (b == LZMA2_CONTROL_COPY_RESET_DIC)
|
||||||
|
p->needInitLevel = 0xC0;
|
||||||
|
else if (b > 2 || p->needInitLevel == 0xE0)
|
||||||
|
return LZMA2_STATE_ERROR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (b < p->needInitLevel)
|
||||||
|
return LZMA2_STATE_ERROR;
|
||||||
|
p->needInitLevel = 0;
|
||||||
|
p->unpackSize = (UInt32)(b & 0x1F) << 16;
|
||||||
|
}
|
||||||
|
return LZMA2_STATE_UNPACK0;
|
||||||
|
|
||||||
|
case LZMA2_STATE_UNPACK0:
|
||||||
|
p->unpackSize |= (UInt32)b << 8;
|
||||||
|
return LZMA2_STATE_UNPACK1;
|
||||||
|
|
||||||
|
case LZMA2_STATE_UNPACK1:
|
||||||
|
p->unpackSize |= (UInt32)b;
|
||||||
|
p->unpackSize++;
|
||||||
|
PRF(printf(" %7u", (unsigned)p->unpackSize));
|
||||||
|
return LZMA2_IS_UNCOMPRESSED_STATE(p) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0;
|
||||||
|
|
||||||
|
case LZMA2_STATE_PACK0:
|
||||||
|
p->packSize = (UInt32)b << 8;
|
||||||
|
return LZMA2_STATE_PACK1;
|
||||||
|
|
||||||
|
case LZMA2_STATE_PACK1:
|
||||||
|
p->packSize |= (UInt32)b;
|
||||||
|
p->packSize++;
|
||||||
|
// if (p->packSize < 5) return LZMA2_STATE_ERROR;
|
||||||
|
PRF(printf(" %5u", (unsigned)p->packSize));
|
||||||
|
return (p->control & 0x40) ? LZMA2_STATE_PROP : LZMA2_STATE_DATA;
|
||||||
|
|
||||||
|
case LZMA2_STATE_PROP:
|
||||||
|
{
|
||||||
|
unsigned lc, lp;
|
||||||
|
if (b >= (9 * 5 * 5))
|
||||||
|
return LZMA2_STATE_ERROR;
|
||||||
|
lc = b % 9;
|
||||||
|
b /= 9;
|
||||||
|
p->decoder.prop.pb = (Byte)(b / 5);
|
||||||
|
lp = b % 5;
|
||||||
|
if (lc + lp > LZMA2_LCLP_MAX)
|
||||||
|
return LZMA2_STATE_ERROR;
|
||||||
|
p->decoder.prop.lc = (Byte)lc;
|
||||||
|
p->decoder.prop.lp = (Byte)lp;
|
||||||
|
return LZMA2_STATE_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return LZMA2_STATE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size)
|
||||||
|
{
|
||||||
|
memcpy(p->dic + p->dicPos, src, size);
|
||||||
|
p->dicPos += size;
|
||||||
|
if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size)
|
||||||
|
p->checkDicSize = p->prop.dicSize;
|
||||||
|
p->processedPos += (UInt32)size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState);
|
||||||
|
|
||||||
|
|
||||||
|
SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
|
||||||
|
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
|
||||||
|
{
|
||||||
|
SizeT inSize = *srcLen;
|
||||||
|
*srcLen = 0;
|
||||||
|
*status = LZMA_STATUS_NOT_SPECIFIED;
|
||||||
|
|
||||||
|
while (p->state != LZMA2_STATE_ERROR)
|
||||||
|
{
|
||||||
|
SizeT dicPos;
|
||||||
|
|
||||||
|
if (p->state == LZMA2_STATE_FINISHED)
|
||||||
|
{
|
||||||
|
*status = LZMA_STATUS_FINISHED_WITH_MARK;
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
dicPos = p->decoder.dicPos;
|
||||||
|
|
||||||
|
if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY)
|
||||||
|
{
|
||||||
|
*status = LZMA_STATUS_NOT_FINISHED;
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT)
|
||||||
|
{
|
||||||
|
if (*srcLen == inSize)
|
||||||
|
{
|
||||||
|
*status = LZMA_STATUS_NEEDS_MORE_INPUT;
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
(*srcLen)++;
|
||||||
|
p->state = Lzma2Dec_UpdateState(p, *src++);
|
||||||
|
if (dicPos == dicLimit && p->state != LZMA2_STATE_FINISHED)
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
SizeT inCur = inSize - *srcLen;
|
||||||
|
SizeT outCur = dicLimit - dicPos;
|
||||||
|
ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY;
|
||||||
|
|
||||||
|
if (outCur >= p->unpackSize)
|
||||||
|
{
|
||||||
|
outCur = (SizeT)p->unpackSize;
|
||||||
|
curFinishMode = LZMA_FINISH_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LZMA2_IS_UNCOMPRESSED_STATE(p))
|
||||||
|
{
|
||||||
|
if (inCur == 0)
|
||||||
|
{
|
||||||
|
*status = LZMA_STATUS_NEEDS_MORE_INPUT;
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->state == LZMA2_STATE_DATA)
|
||||||
|
{
|
||||||
|
BoolInt initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC);
|
||||||
|
LzmaDec_InitDicAndState(&p->decoder, initDic, False);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inCur > outCur)
|
||||||
|
inCur = outCur;
|
||||||
|
if (inCur == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
LzmaDec_UpdateWithUncompressed(&p->decoder, src, inCur);
|
||||||
|
|
||||||
|
src += inCur;
|
||||||
|
*srcLen += inCur;
|
||||||
|
p->unpackSize -= (UInt32)inCur;
|
||||||
|
p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SRes res;
|
||||||
|
|
||||||
|
if (p->state == LZMA2_STATE_DATA)
|
||||||
|
{
|
||||||
|
BoolInt initDic = (p->control >= 0xE0);
|
||||||
|
BoolInt initState = (p->control >= 0xA0);
|
||||||
|
LzmaDec_InitDicAndState(&p->decoder, initDic, initState);
|
||||||
|
p->state = LZMA2_STATE_DATA_CONT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inCur > p->packSize)
|
||||||
|
inCur = (SizeT)p->packSize;
|
||||||
|
|
||||||
|
res = LzmaDec_DecodeToDic(&p->decoder, dicPos + outCur, src, &inCur, curFinishMode, status);
|
||||||
|
|
||||||
|
src += inCur;
|
||||||
|
*srcLen += inCur;
|
||||||
|
p->packSize -= (UInt32)inCur;
|
||||||
|
outCur = p->decoder.dicPos - dicPos;
|
||||||
|
p->unpackSize -= (UInt32)outCur;
|
||||||
|
|
||||||
|
if (res != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (*status == LZMA_STATUS_NEEDS_MORE_INPUT)
|
||||||
|
{
|
||||||
|
if (p->packSize == 0)
|
||||||
|
break;
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inCur == 0 && outCur == 0)
|
||||||
|
{
|
||||||
|
if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
|
||||||
|
|| p->unpackSize != 0
|
||||||
|
|| p->packSize != 0)
|
||||||
|
break;
|
||||||
|
p->state = LZMA2_STATE_CONTROL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*status = LZMA_STATUS_NOT_SPECIFIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*status = LZMA_STATUS_NOT_SPECIFIED;
|
||||||
|
p->state = LZMA2_STATE_ERROR;
|
||||||
|
return SZ_ERROR_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ELzma2ParseStatus Lzma2Dec_Parse(CLzma2Dec *p,
|
||||||
|
SizeT outSize,
|
||||||
|
const Byte *src, SizeT *srcLen,
|
||||||
|
int checkFinishBlock)
|
||||||
|
{
|
||||||
|
SizeT inSize = *srcLen;
|
||||||
|
*srcLen = 0;
|
||||||
|
|
||||||
|
while (p->state != LZMA2_STATE_ERROR)
|
||||||
|
{
|
||||||
|
if (p->state == LZMA2_STATE_FINISHED)
|
||||||
|
return (ELzma2ParseStatus)LZMA_STATUS_FINISHED_WITH_MARK;
|
||||||
|
|
||||||
|
if (outSize == 0 && !checkFinishBlock)
|
||||||
|
return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED;
|
||||||
|
|
||||||
|
if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT)
|
||||||
|
{
|
||||||
|
if (*srcLen == inSize)
|
||||||
|
return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT;
|
||||||
|
(*srcLen)++;
|
||||||
|
|
||||||
|
p->state = Lzma2Dec_UpdateState(p, *src++);
|
||||||
|
|
||||||
|
if (p->state == LZMA2_STATE_UNPACK0)
|
||||||
|
{
|
||||||
|
// if (p->decoder.dicPos != 0)
|
||||||
|
if (p->control == LZMA2_CONTROL_COPY_RESET_DIC || p->control >= 0xE0)
|
||||||
|
return LZMA2_PARSE_STATUS_NEW_BLOCK;
|
||||||
|
// if (outSize == 0) return LZMA_STATUS_NOT_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following code can be commented.
|
||||||
|
// It's not big problem, if we read additional input bytes.
|
||||||
|
// It will be stopped later in LZMA2_STATE_DATA / LZMA2_STATE_DATA_CONT state.
|
||||||
|
|
||||||
|
if (outSize == 0 && p->state != LZMA2_STATE_FINISHED)
|
||||||
|
{
|
||||||
|
// checkFinishBlock is true. So we expect that block must be finished,
|
||||||
|
// We can return LZMA_STATUS_NOT_SPECIFIED or LZMA_STATUS_NOT_FINISHED here
|
||||||
|
// break;
|
||||||
|
return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->state == LZMA2_STATE_DATA)
|
||||||
|
return LZMA2_PARSE_STATUS_NEW_CHUNK;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outSize == 0)
|
||||||
|
return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED;
|
||||||
|
|
||||||
|
{
|
||||||
|
SizeT inCur = inSize - *srcLen;
|
||||||
|
|
||||||
|
if (LZMA2_IS_UNCOMPRESSED_STATE(p))
|
||||||
|
{
|
||||||
|
if (inCur == 0)
|
||||||
|
return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT;
|
||||||
|
if (inCur > p->unpackSize)
|
||||||
|
inCur = p->unpackSize;
|
||||||
|
if (inCur > outSize)
|
||||||
|
inCur = outSize;
|
||||||
|
p->decoder.dicPos += inCur;
|
||||||
|
src += inCur;
|
||||||
|
*srcLen += inCur;
|
||||||
|
outSize -= inCur;
|
||||||
|
p->unpackSize -= (UInt32)inCur;
|
||||||
|
p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p->isExtraMode = True;
|
||||||
|
|
||||||
|
if (inCur == 0)
|
||||||
|
{
|
||||||
|
if (p->packSize != 0)
|
||||||
|
return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT;
|
||||||
|
}
|
||||||
|
else if (p->state == LZMA2_STATE_DATA)
|
||||||
|
{
|
||||||
|
p->state = LZMA2_STATE_DATA_CONT;
|
||||||
|
if (*src != 0)
|
||||||
|
{
|
||||||
|
// first byte of lzma chunk must be Zero
|
||||||
|
*srcLen += 1;
|
||||||
|
p->packSize--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inCur > p->packSize)
|
||||||
|
inCur = (SizeT)p->packSize;
|
||||||
|
|
||||||
|
src += inCur;
|
||||||
|
*srcLen += inCur;
|
||||||
|
p->packSize -= (UInt32)inCur;
|
||||||
|
|
||||||
|
if (p->packSize == 0)
|
||||||
|
{
|
||||||
|
SizeT rem = outSize;
|
||||||
|
if (rem > p->unpackSize)
|
||||||
|
rem = p->unpackSize;
|
||||||
|
p->decoder.dicPos += rem;
|
||||||
|
p->unpackSize -= (UInt32)rem;
|
||||||
|
outSize -= rem;
|
||||||
|
if (p->unpackSize == 0)
|
||||||
|
p->state = LZMA2_STATE_CONTROL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p->state = LZMA2_STATE_ERROR;
|
||||||
|
return (ELzma2ParseStatus)LZMA_STATUS_NOT_SPECIFIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
|
||||||
|
{
|
||||||
|
SizeT outSize = *destLen, inSize = *srcLen;
|
||||||
|
*srcLen = *destLen = 0;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
SizeT inCur = inSize, outCur, dicPos;
|
||||||
|
ELzmaFinishMode curFinishMode;
|
||||||
|
SRes res;
|
||||||
|
|
||||||
|
if (p->decoder.dicPos == p->decoder.dicBufSize)
|
||||||
|
p->decoder.dicPos = 0;
|
||||||
|
dicPos = p->decoder.dicPos;
|
||||||
|
curFinishMode = LZMA_FINISH_ANY;
|
||||||
|
outCur = p->decoder.dicBufSize - dicPos;
|
||||||
|
|
||||||
|
if (outCur >= outSize)
|
||||||
|
{
|
||||||
|
outCur = outSize;
|
||||||
|
curFinishMode = finishMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = Lzma2Dec_DecodeToDic(p, dicPos + outCur, src, &inCur, curFinishMode, status);
|
||||||
|
|
||||||
|
src += inCur;
|
||||||
|
inSize -= inCur;
|
||||||
|
*srcLen += inCur;
|
||||||
|
outCur = p->decoder.dicPos - dicPos;
|
||||||
|
memcpy(dest, p->decoder.dic + dicPos, outCur);
|
||||||
|
dest += outCur;
|
||||||
|
outSize -= outCur;
|
||||||
|
*destLen += outCur;
|
||||||
|
if (res != 0)
|
||||||
|
return res;
|
||||||
|
if (outCur == 0 || outSize == 0)
|
||||||
|
return SZ_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||||
|
Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAllocPtr alloc)
|
||||||
|
{
|
||||||
|
CLzma2Dec p;
|
||||||
|
SRes res;
|
||||||
|
SizeT outSize = *destLen, inSize = *srcLen;
|
||||||
|
*destLen = *srcLen = 0;
|
||||||
|
*status = LZMA_STATUS_NOT_SPECIFIED;
|
||||||
|
Lzma2Dec_CONSTRUCT(&p)
|
||||||
|
RINOK(Lzma2Dec_AllocateProbs(&p, prop, alloc))
|
||||||
|
p.decoder.dic = dest;
|
||||||
|
p.decoder.dicBufSize = outSize;
|
||||||
|
Lzma2Dec_Init(&p);
|
||||||
|
*srcLen = inSize;
|
||||||
|
res = Lzma2Dec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
|
||||||
|
*destLen = p.decoder.dicPos;
|
||||||
|
if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
|
||||||
|
res = SZ_ERROR_INPUT_EOF;
|
||||||
|
Lzma2Dec_FreeProbs(&p, alloc);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef PRF
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
/* Lzma2Dec.h -- LZMA2 Decoder
|
||||||
|
2023-03-03 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_LZMA2_DEC_H
|
||||||
|
#define ZIP7_INC_LZMA2_DEC_H
|
||||||
|
|
||||||
|
#include "LzmaDec.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
/* ---------- State Interface ---------- */
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned state;
|
||||||
|
Byte control;
|
||||||
|
Byte needInitLevel;
|
||||||
|
Byte isExtraMode;
|
||||||
|
Byte _pad_;
|
||||||
|
UInt32 packSize;
|
||||||
|
UInt32 unpackSize;
|
||||||
|
CLzmaDec decoder;
|
||||||
|
} CLzma2Dec;
|
||||||
|
|
||||||
|
#define Lzma2Dec_CONSTRUCT(p) LzmaDec_CONSTRUCT(&(p)->decoder)
|
||||||
|
#define Lzma2Dec_Construct(p) Lzma2Dec_CONSTRUCT(p)
|
||||||
|
#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc)
|
||||||
|
#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc)
|
||||||
|
|
||||||
|
SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc);
|
||||||
|
SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc);
|
||||||
|
void Lzma2Dec_Init(CLzma2Dec *p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
finishMode:
|
||||||
|
It has meaning only if the decoding reaches output limit (*destLen or dicLimit).
|
||||||
|
LZMA_FINISH_ANY - use smallest number of input bytes
|
||||||
|
LZMA_FINISH_END - read EndOfStream marker after decoding
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
SZ_OK
|
||||||
|
status:
|
||||||
|
LZMA_STATUS_FINISHED_WITH_MARK
|
||||||
|
LZMA_STATUS_NOT_FINISHED
|
||||||
|
LZMA_STATUS_NEEDS_MORE_INPUT
|
||||||
|
SZ_ERROR_DATA - Data error
|
||||||
|
*/
|
||||||
|
|
||||||
|
SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
|
||||||
|
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
|
||||||
|
|
||||||
|
SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen,
|
||||||
|
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------- LZMA2 block and chunk parsing ---------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
Lzma2Dec_Parse() parses compressed data stream up to next independent block or next chunk data.
|
||||||
|
It can return LZMA_STATUS_* code or LZMA2_PARSE_STATUS_* code:
|
||||||
|
- LZMA2_PARSE_STATUS_NEW_BLOCK - there is new block, and 1 additional byte (control byte of next block header) was read from input.
|
||||||
|
- LZMA2_PARSE_STATUS_NEW_CHUNK - there is new chunk, and only lzma2 header of new chunk was read.
|
||||||
|
CLzma2Dec::unpackSize contains unpack size of that chunk
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
LZMA_STATUS_NOT_SPECIFIED // data error
|
||||||
|
LZMA_STATUS_FINISHED_WITH_MARK
|
||||||
|
LZMA_STATUS_NOT_FINISHED //
|
||||||
|
LZMA_STATUS_NEEDS_MORE_INPUT
|
||||||
|
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK // unused
|
||||||
|
*/
|
||||||
|
LZMA2_PARSE_STATUS_NEW_BLOCK = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + 1,
|
||||||
|
LZMA2_PARSE_STATUS_NEW_CHUNK
|
||||||
|
} ELzma2ParseStatus;
|
||||||
|
|
||||||
|
ELzma2ParseStatus Lzma2Dec_Parse(CLzma2Dec *p,
|
||||||
|
SizeT outSize, // output size
|
||||||
|
const Byte *src, SizeT *srcLen,
|
||||||
|
int checkFinishBlock // set (checkFinishBlock = 1), if it must read full input data, if decoder.dicPos reaches blockMax position.
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
LZMA2 parser doesn't decode LZMA chunks, so we must read
|
||||||
|
full input LZMA chunk to decode some part of LZMA chunk.
|
||||||
|
|
||||||
|
Lzma2Dec_GetUnpackExtra() returns the value that shows
|
||||||
|
max possible number of output bytes that can be output by decoder
|
||||||
|
at current input positon.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define Lzma2Dec_GetUnpackExtra(p) ((p)->isExtraMode ? (p)->unpackSize : 0)
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------- One Call Interface ---------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
finishMode:
|
||||||
|
It has meaning only if the decoding reaches output limit (*destLen).
|
||||||
|
LZMA_FINISH_ANY - use smallest number of input bytes
|
||||||
|
LZMA_FINISH_END - read EndOfStream marker after decoding
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
SZ_OK
|
||||||
|
status:
|
||||||
|
LZMA_STATUS_FINISHED_WITH_MARK
|
||||||
|
LZMA_STATUS_NOT_FINISHED
|
||||||
|
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 Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||||
|
Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAllocPtr alloc);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/* Lzma2DecMt.h -- LZMA2 Decoder Multi-thread
|
||||||
|
2023-04-13 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_LZMA2_DEC_MT_H
|
||||||
|
#define ZIP7_INC_LZMA2_DEC_MT_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
size_t inBufSize_ST;
|
||||||
|
size_t outStep_ST;
|
||||||
|
|
||||||
|
#ifndef Z7_ST
|
||||||
|
unsigned numThreads;
|
||||||
|
size_t inBufSize_MT;
|
||||||
|
size_t outBlockMax;
|
||||||
|
size_t inBlockMax;
|
||||||
|
#endif
|
||||||
|
} CLzma2DecMtProps;
|
||||||
|
|
||||||
|
/* init to single-thread mode */
|
||||||
|
void Lzma2DecMtProps_Init(CLzma2DecMtProps *p);
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------- CLzma2DecMtHandle Interface ---------- */
|
||||||
|
|
||||||
|
/* Lzma2DecMt_ * functions can return the following exit codes:
|
||||||
|
SRes:
|
||||||
|
SZ_OK - OK
|
||||||
|
SZ_ERROR_MEM - Memory allocation error
|
||||||
|
SZ_ERROR_PARAM - Incorrect paramater in props
|
||||||
|
SZ_ERROR_WRITE - ISeqOutStream write callback error
|
||||||
|
// SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output
|
||||||
|
SZ_ERROR_PROGRESS - some break from progress callback
|
||||||
|
SZ_ERROR_THREAD - error in multithreading functions (only for Mt version)
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct CLzma2DecMt CLzma2DecMt;
|
||||||
|
typedef CLzma2DecMt * CLzma2DecMtHandle;
|
||||||
|
// Z7_DECLARE_HANDLE(CLzma2DecMtHandle)
|
||||||
|
|
||||||
|
CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid);
|
||||||
|
void Lzma2DecMt_Destroy(CLzma2DecMtHandle p);
|
||||||
|
|
||||||
|
SRes Lzma2DecMt_Decode(CLzma2DecMtHandle p,
|
||||||
|
Byte prop,
|
||||||
|
const CLzma2DecMtProps *props,
|
||||||
|
ISeqOutStreamPtr outStream,
|
||||||
|
const UInt64 *outDataSize, // NULL means undefined
|
||||||
|
int finishMode, // 0 - partial unpacking is allowed, 1 - if lzma2 stream must be finished
|
||||||
|
// Byte *outBuf, size_t *outBufSize,
|
||||||
|
ISeqInStreamPtr inStream,
|
||||||
|
// const Byte *inData, size_t inDataSize,
|
||||||
|
|
||||||
|
// out variables:
|
||||||
|
UInt64 *inProcessed,
|
||||||
|
int *isMT, /* out: (*isMT == 0), if single thread decoding was used */
|
||||||
|
|
||||||
|
// UInt64 *outProcessed,
|
||||||
|
ICompressProgressPtr progress);
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------- Read from CLzma2DecMtHandle Interface ---------- */
|
||||||
|
|
||||||
|
SRes Lzma2DecMt_Init(CLzma2DecMtHandle pp,
|
||||||
|
Byte prop,
|
||||||
|
const CLzma2DecMtProps *props,
|
||||||
|
const UInt64 *outDataSize, int finishMode,
|
||||||
|
ISeqInStreamPtr inStream);
|
||||||
|
|
||||||
|
SRes Lzma2DecMt_Read(CLzma2DecMtHandle pp,
|
||||||
|
Byte *data, size_t *outSize,
|
||||||
|
UInt64 *inStreamProcessed);
|
||||||
|
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/* Lzma2Enc.h -- LZMA2 Encoder
|
||||||
|
2023-04-13 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_LZMA2_ENC_H
|
||||||
|
#define ZIP7_INC_LZMA2_ENC_H
|
||||||
|
|
||||||
|
#include "LzmaEnc.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
#define LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO 0
|
||||||
|
#define LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID ((UInt64)(Int64)-1)
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
CLzmaEncProps lzmaProps;
|
||||||
|
UInt64 blockSize;
|
||||||
|
int numBlockThreads_Reduced;
|
||||||
|
int numBlockThreads_Max;
|
||||||
|
int numTotalThreads;
|
||||||
|
} CLzma2EncProps;
|
||||||
|
|
||||||
|
void Lzma2EncProps_Init(CLzma2EncProps *p);
|
||||||
|
void Lzma2EncProps_Normalize(CLzma2EncProps *p);
|
||||||
|
|
||||||
|
/* ---------- CLzmaEnc2Handle Interface ---------- */
|
||||||
|
|
||||||
|
/* Lzma2Enc_* functions can return the following exit codes:
|
||||||
|
SRes:
|
||||||
|
SZ_OK - OK
|
||||||
|
SZ_ERROR_MEM - Memory allocation error
|
||||||
|
SZ_ERROR_PARAM - Incorrect paramater in props
|
||||||
|
SZ_ERROR_WRITE - ISeqOutStream write callback error
|
||||||
|
SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output
|
||||||
|
SZ_ERROR_PROGRESS - some break from progress callback
|
||||||
|
SZ_ERROR_THREAD - error in multithreading functions (only for Mt version)
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct CLzma2Enc CLzma2Enc;
|
||||||
|
typedef CLzma2Enc * CLzma2EncHandle;
|
||||||
|
// Z7_DECLARE_HANDLE(CLzma2EncHandle)
|
||||||
|
|
||||||
|
CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig);
|
||||||
|
void Lzma2Enc_Destroy(CLzma2EncHandle p);
|
||||||
|
SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props);
|
||||||
|
void Lzma2Enc_SetDataSize(CLzma2EncHandle p, UInt64 expectedDataSiize);
|
||||||
|
Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p);
|
||||||
|
SRes Lzma2Enc_Encode2(CLzma2EncHandle p,
|
||||||
|
ISeqOutStreamPtr outStream,
|
||||||
|
Byte *outBuf, size_t *outBufSize,
|
||||||
|
ISeqInStreamPtr inStream,
|
||||||
|
const Byte *inData, size_t inDataSize,
|
||||||
|
ICompressProgressPtr progress);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
/* Lzma86.h -- LZMA + x86 (BCJ) Filter
|
||||||
|
2023-03-03 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_LZMA86_H
|
||||||
|
#define ZIP7_INC_LZMA86_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
#define LZMA86_SIZE_OFFSET (1 + 5)
|
||||||
|
#define LZMA86_HEADER_SIZE (LZMA86_SIZE_OFFSET + 8)
|
||||||
|
|
||||||
|
/*
|
||||||
|
It's an example for LZMA + x86 Filter use.
|
||||||
|
You can use .lzma86 extension, if you write that stream to file.
|
||||||
|
.lzma86 header adds one additional byte to standard .lzma header.
|
||||||
|
.lzma86 header (14 bytes):
|
||||||
|
Offset Size Description
|
||||||
|
0 1 = 0 - no filter, pure LZMA
|
||||||
|
= 1 - x86 filter + LZMA
|
||||||
|
1 1 lc, lp and pb in encoded form
|
||||||
|
2 4 dictSize (little endian)
|
||||||
|
6 8 uncompressed size (little endian)
|
||||||
|
|
||||||
|
|
||||||
|
Lzma86_Encode
|
||||||
|
-------------
|
||||||
|
level - compression level: 0 <= level <= 9, the default value for "level" is 5.
|
||||||
|
|
||||||
|
dictSize - The dictionary size in bytes. The maximum value is
|
||||||
|
128 MB = (1 << 27) bytes for 32-bit version
|
||||||
|
1 GB = (1 << 30) bytes for 64-bit version
|
||||||
|
The default value is 16 MB = (1 << 24) bytes, for level = 5.
|
||||||
|
It's recommended to use the dictionary that is larger than 4 KB and
|
||||||
|
that can be calculated as (1 << N) or (3 << N) sizes.
|
||||||
|
For better compression ratio dictSize must be >= inSize.
|
||||||
|
|
||||||
|
filterMode:
|
||||||
|
SZ_FILTER_NO - no Filter
|
||||||
|
SZ_FILTER_YES - x86 Filter
|
||||||
|
SZ_FILTER_AUTO - it tries both alternatives to select best.
|
||||||
|
Encoder will use 2 or 3 passes:
|
||||||
|
2 passes when FILTER_NO provides better compression.
|
||||||
|
3 passes when FILTER_YES provides better compression.
|
||||||
|
|
||||||
|
Lzma86Encode allocates Data with MyAlloc functions.
|
||||||
|
RAM Requirements for compressing:
|
||||||
|
RamSize = dictionarySize * 11.5 + 6MB + FilterBlockSize
|
||||||
|
filterMode FilterBlockSize
|
||||||
|
SZ_FILTER_NO 0
|
||||||
|
SZ_FILTER_YES inSize
|
||||||
|
SZ_FILTER_AUTO inSize
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum ESzFilterMode
|
||||||
|
{
|
||||||
|
SZ_FILTER_NO,
|
||||||
|
SZ_FILTER_YES,
|
||||||
|
SZ_FILTER_AUTO
|
||||||
|
};
|
||||||
|
|
||||||
|
SRes Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen,
|
||||||
|
int level, UInt32 dictSize, int filterMode);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Lzma86_GetUnpackSize:
|
||||||
|
In:
|
||||||
|
src - input data
|
||||||
|
srcLen - input data size
|
||||||
|
Out:
|
||||||
|
unpackSize - size of uncompressed stream
|
||||||
|
Return code:
|
||||||
|
SZ_OK - OK
|
||||||
|
SZ_ERROR_INPUT_EOF - Error in headers
|
||||||
|
*/
|
||||||
|
|
||||||
|
SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Lzma86_Decode:
|
||||||
|
In:
|
||||||
|
dest - output data
|
||||||
|
destLen - output data size
|
||||||
|
src - input data
|
||||||
|
srcLen - input data size
|
||||||
|
Out:
|
||||||
|
destLen - processed output size
|
||||||
|
srcLen - processed input size
|
||||||
|
Return code:
|
||||||
|
SZ_OK - OK
|
||||||
|
SZ_ERROR_DATA - Data error
|
||||||
|
SZ_ERROR_MEM - Memory allocation error
|
||||||
|
SZ_ERROR_UNSUPPORTED - unsupported file
|
||||||
|
SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer
|
||||||
|
*/
|
||||||
|
|
||||||
|
SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,237 @@
|
|||||||
|
/* LzmaDec.h -- LZMA Decoder
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_LZMA_DEC_H
|
||||||
|
#define ZIP7_INC_LZMA_DEC_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
/* #define Z7_LZMA_PROB32 */
|
||||||
|
/* Z7_LZMA_PROB32 can increase the speed on some CPUs,
|
||||||
|
but memory usage for CLzmaDec::probs will be doubled in that case */
|
||||||
|
|
||||||
|
typedef
|
||||||
|
#ifdef Z7_LZMA_PROB32
|
||||||
|
UInt32
|
||||||
|
#else
|
||||||
|
UInt16
|
||||||
|
#endif
|
||||||
|
CLzmaProb;
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------- LZMA Properties ---------- */
|
||||||
|
|
||||||
|
#define LZMA_PROPS_SIZE 5
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Byte lc;
|
||||||
|
Byte lp;
|
||||||
|
Byte pb;
|
||||||
|
Byte _pad_;
|
||||||
|
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
|
||||||
|
{
|
||||||
|
/* Don't change this structure. ASM code can use it. */
|
||||||
|
CLzmaProps prop;
|
||||||
|
CLzmaProb *probs;
|
||||||
|
CLzmaProb *probs_1664;
|
||||||
|
Byte *dic;
|
||||||
|
SizeT dicBufSize;
|
||||||
|
SizeT dicPos;
|
||||||
|
const Byte *buf;
|
||||||
|
UInt32 range;
|
||||||
|
UInt32 code;
|
||||||
|
UInt32 processedPos;
|
||||||
|
UInt32 checkDicSize;
|
||||||
|
UInt32 reps[4];
|
||||||
|
UInt32 state;
|
||||||
|
UInt32 remainLen;
|
||||||
|
|
||||||
|
UInt32 numProbs;
|
||||||
|
unsigned tempBufSize;
|
||||||
|
Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
|
||||||
|
} CLzmaDec;
|
||||||
|
|
||||||
|
#define LzmaDec_CONSTRUCT(p) { (p)->dic = NULL; (p)->probs = NULL; }
|
||||||
|
#define LzmaDec_Construct(p) LzmaDec_CONSTRUCT(p)
|
||||||
|
|
||||||
|
void LzmaDec_Init(CLzmaDec *p);
|
||||||
|
|
||||||
|
/* There are two types of LZMA streams:
|
||||||
|
- Stream with end mark. That end mark adds about 6 bytes to compressed size.
|
||||||
|
- 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, ISzAllocPtr alloc);
|
||||||
|
void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc);
|
||||||
|
|
||||||
|
SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc);
|
||||||
|
void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr 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_Construct()
|
||||||
|
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
|
||||||
|
SZ_ERROR_FAIL - Some unexpected error: internal error of code, memory corruption or hardware failure
|
||||||
|
*/
|
||||||
|
|
||||||
|
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).
|
||||||
|
SZ_ERROR_FAIL - Some unexpected error: internal error of code, memory corruption or hardware failure
|
||||||
|
*/
|
||||||
|
|
||||||
|
SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||||
|
const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
|
||||||
|
ELzmaStatus *status, ISzAllocPtr alloc);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/* LzmaEnc.h -- LZMA Encoder
|
||||||
|
2023-04-13 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_LZMA_ENC_H
|
||||||
|
#define ZIP7_INC_LZMA_ENC_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
#define LZMA_PROPS_SIZE 5
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int level; /* 0 <= level <= 9 */
|
||||||
|
UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
|
||||||
|
(1 << 12) <= dictSize <= (3 << 29) 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 */
|
||||||
|
unsigned numHashOutBits; /* default = ? */
|
||||||
|
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 */
|
||||||
|
|
||||||
|
// int _pad;
|
||||||
|
|
||||||
|
UInt64 reduceSize; /* estimated size of data that will be compressed. default = (UInt64)(Int64)-1.
|
||||||
|
Encoder uses this value to reduce dictionary size */
|
||||||
|
|
||||||
|
UInt64 affinity;
|
||||||
|
} 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:
|
||||||
|
SRes:
|
||||||
|
SZ_OK - OK
|
||||||
|
SZ_ERROR_MEM - Memory allocation error
|
||||||
|
SZ_ERROR_PARAM - Incorrect paramater in props
|
||||||
|
SZ_ERROR_WRITE - ISeqOutStream write callback error
|
||||||
|
SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output
|
||||||
|
SZ_ERROR_PROGRESS - some break from progress callback
|
||||||
|
SZ_ERROR_THREAD - error in multithreading functions (only for Mt version)
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct CLzmaEnc CLzmaEnc;
|
||||||
|
typedef CLzmaEnc * CLzmaEncHandle;
|
||||||
|
// Z7_DECLARE_HANDLE(CLzmaEncHandle)
|
||||||
|
|
||||||
|
CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc);
|
||||||
|
void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig);
|
||||||
|
|
||||||
|
SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
|
||||||
|
void LzmaEnc_SetDataSize(CLzmaEncHandle p, UInt64 expectedDataSiize);
|
||||||
|
SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
|
||||||
|
unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle p);
|
||||||
|
|
||||||
|
SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream,
|
||||||
|
ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig);
|
||||||
|
SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
|
||||||
|
int writeEndMark, ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig);
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------- One Call Interface ---------- */
|
||||||
|
|
||||||
|
SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
|
||||||
|
const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
|
||||||
|
ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
/* LzmaLib.h -- LZMA library interface
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_LZMA_LIB_H
|
||||||
|
#define ZIP7_INC_LZMA_LIB_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
#define Z7_STDAPI int Z7_STDCALL
|
||||||
|
|
||||||
|
#define LZMA_PROPS_SIZE 5
|
||||||
|
|
||||||
|
/*
|
||||||
|
RAM requirements for LZMA:
|
||||||
|
for compression: (dictSize * 11.5 + 6 MB) + state_size
|
||||||
|
for decompression: dictSize + state_size
|
||||||
|
state_size = (4 + (1.5 << (lc + lp))) KB
|
||||||
|
by default (lc=3, lp=0), state_size = 16 KB.
|
||||||
|
|
||||||
|
LZMA properties (5 bytes) format
|
||||||
|
Offset Size Description
|
||||||
|
0 1 lc, lp and pb in encoded form.
|
||||||
|
1 4 dictSize (little endian).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
LzmaCompress
|
||||||
|
------------
|
||||||
|
|
||||||
|
outPropsSize -
|
||||||
|
In: the pointer to the size of outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5.
|
||||||
|
Out: the pointer to the size of written properties in outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5.
|
||||||
|
|
||||||
|
LZMA Encoder will use defult values for any parameter, if it is
|
||||||
|
-1 for any from: level, loc, lp, pb, fb, numThreads
|
||||||
|
0 for dictSize
|
||||||
|
|
||||||
|
level - compression level: 0 <= level <= 9;
|
||||||
|
|
||||||
|
level dictSize algo fb
|
||||||
|
0: 64 KB 0 32
|
||||||
|
1: 256 KB 0 32
|
||||||
|
2: 1 MB 0 32
|
||||||
|
3: 4 MB 0 32
|
||||||
|
4: 16 MB 0 32
|
||||||
|
5: 16 MB 1 32
|
||||||
|
6: 32 MB 1 32
|
||||||
|
7: 32 MB 1 64
|
||||||
|
8: 64 MB 1 64
|
||||||
|
9: 64 MB 1 64
|
||||||
|
|
||||||
|
The default value for "level" is 5.
|
||||||
|
|
||||||
|
algo = 0 means fast method
|
||||||
|
algo = 1 means normal method
|
||||||
|
|
||||||
|
dictSize - The dictionary size in bytes. The maximum value is
|
||||||
|
128 MB = (1 << 27) bytes for 32-bit version
|
||||||
|
1 GB = (1 << 30) bytes for 64-bit version
|
||||||
|
The default value is 16 MB = (1 << 24) bytes.
|
||||||
|
It's recommended to use the dictionary that is larger than 4 KB and
|
||||||
|
that can be calculated as (1 << N) or (3 << N) sizes.
|
||||||
|
|
||||||
|
lc - The number of literal context bits (high bits of previous literal).
|
||||||
|
It can be in the range from 0 to 8. The default value is 3.
|
||||||
|
Sometimes lc=4 gives the gain for big files.
|
||||||
|
|
||||||
|
lp - The number of literal pos bits (low bits of current position for literals).
|
||||||
|
It can be in the range from 0 to 4. The default value is 0.
|
||||||
|
The lp switch is intended for periodical data when the period is equal to 2^lp.
|
||||||
|
For example, for 32-bit (4 bytes) periodical data you can use lp=2. Often it's
|
||||||
|
better to set lc=0, if you change lp switch.
|
||||||
|
|
||||||
|
pb - The number of pos bits (low bits of current position).
|
||||||
|
It can be in the range from 0 to 4. The default value is 2.
|
||||||
|
The pb switch is intended for periodical data when the period is equal 2^pb.
|
||||||
|
|
||||||
|
fb - Word size (the number of fast bytes).
|
||||||
|
It can be in the range from 5 to 273. The default value is 32.
|
||||||
|
Usually, a big number gives a little bit better compression ratio and
|
||||||
|
slower compression process.
|
||||||
|
|
||||||
|
numThreads - The number of thereads. 1 or 2. The default value is 2.
|
||||||
|
Fast mode (algo = 0) can use only 1 thread.
|
||||||
|
|
||||||
|
In:
|
||||||
|
dest - output data buffer
|
||||||
|
destLen - output data buffer size
|
||||||
|
src - input data
|
||||||
|
srcLen - input data size
|
||||||
|
Out:
|
||||||
|
destLen - processed output size
|
||||||
|
Returns:
|
||||||
|
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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
Z7_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen,
|
||||||
|
unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */
|
||||||
|
int level, /* 0 <= level <= 9, default = 5 */
|
||||||
|
unsigned dictSize, /* 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 fb, /* 5 <= fb <= 273, default = 32 */
|
||||||
|
int numThreads /* 1 or 2, default = 2 */
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
LzmaUncompress
|
||||||
|
--------------
|
||||||
|
In:
|
||||||
|
dest - output data buffer
|
||||||
|
destLen - output data buffer size
|
||||||
|
src - input data
|
||||||
|
srcLen - input data size
|
||||||
|
Out:
|
||||||
|
destLen - processed output size
|
||||||
|
srcLen - processed input size
|
||||||
|
Returns:
|
||||||
|
SZ_OK - OK
|
||||||
|
SZ_ERROR_DATA - Data error
|
||||||
|
SZ_ERROR_MEM - Memory allocation arror
|
||||||
|
SZ_ERROR_UNSUPPORTED - Unsupported properties
|
||||||
|
SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer (src)
|
||||||
|
*/
|
||||||
|
|
||||||
|
Z7_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, SizeT *srcLen,
|
||||||
|
const unsigned char *props, size_t propsSize);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
/* MtCoder.h -- Multi-thread Coder
|
||||||
|
2023-04-13 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_MT_CODER_H
|
||||||
|
#define ZIP7_INC_MT_CODER_H
|
||||||
|
|
||||||
|
#include "MtDec.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
/*
|
||||||
|
if ( defined MTCODER_USE_WRITE_THREAD) : main thread writes all data blocks to output stream
|
||||||
|
if (not defined MTCODER_USE_WRITE_THREAD) : any coder thread can write data blocks to output stream
|
||||||
|
*/
|
||||||
|
/* #define MTCODER_USE_WRITE_THREAD */
|
||||||
|
|
||||||
|
#ifndef Z7_ST
|
||||||
|
#define MTCODER_GET_NUM_BLOCKS_FROM_THREADS(numThreads) ((numThreads) + (numThreads) / 8 + 1)
|
||||||
|
#define MTCODER_THREADS_MAX 64
|
||||||
|
#define MTCODER_BLOCKS_MAX (MTCODER_GET_NUM_BLOCKS_FROM_THREADS(MTCODER_THREADS_MAX) + 3)
|
||||||
|
#else
|
||||||
|
#define MTCODER_THREADS_MAX 1
|
||||||
|
#define MTCODER_BLOCKS_MAX 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef Z7_ST
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ICompressProgress vt;
|
||||||
|
CMtProgress *mtProgress;
|
||||||
|
UInt64 inSize;
|
||||||
|
UInt64 outSize;
|
||||||
|
} CMtProgressThunk;
|
||||||
|
|
||||||
|
void MtProgressThunk_CreateVTable(CMtProgressThunk *p);
|
||||||
|
|
||||||
|
#define MtProgressThunk_INIT(p) { (p)->inSize = 0; (p)->outSize = 0; }
|
||||||
|
|
||||||
|
|
||||||
|
struct CMtCoder_;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
struct CMtCoder_ *mtCoder;
|
||||||
|
unsigned index;
|
||||||
|
int stop;
|
||||||
|
Byte *inBuf;
|
||||||
|
|
||||||
|
CAutoResetEvent startEvent;
|
||||||
|
CThread thread;
|
||||||
|
} CMtCoderThread;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SRes (*Code)(void *p, unsigned coderIndex, unsigned outBufIndex,
|
||||||
|
const Byte *src, size_t srcSize, int finished);
|
||||||
|
SRes (*Write)(void *p, unsigned outBufIndex);
|
||||||
|
} IMtCoderCallback2;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SRes res;
|
||||||
|
unsigned bufIndex;
|
||||||
|
BoolInt finished;
|
||||||
|
} CMtCoderBlock;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct CMtCoder_
|
||||||
|
{
|
||||||
|
/* input variables */
|
||||||
|
|
||||||
|
size_t blockSize; /* size of input block */
|
||||||
|
unsigned numThreadsMax;
|
||||||
|
UInt64 expectedDataSize;
|
||||||
|
|
||||||
|
ISeqInStreamPtr inStream;
|
||||||
|
const Byte *inData;
|
||||||
|
size_t inDataSize;
|
||||||
|
|
||||||
|
ICompressProgressPtr progress;
|
||||||
|
ISzAllocPtr allocBig;
|
||||||
|
|
||||||
|
IMtCoderCallback2 *mtCallback;
|
||||||
|
void *mtCallbackObject;
|
||||||
|
|
||||||
|
|
||||||
|
/* internal variables */
|
||||||
|
|
||||||
|
size_t allocatedBufsSize;
|
||||||
|
|
||||||
|
CAutoResetEvent readEvent;
|
||||||
|
CSemaphore blocksSemaphore;
|
||||||
|
|
||||||
|
BoolInt stopReading;
|
||||||
|
SRes readRes;
|
||||||
|
|
||||||
|
#ifdef MTCODER_USE_WRITE_THREAD
|
||||||
|
CAutoResetEvent writeEvents[MTCODER_BLOCKS_MAX];
|
||||||
|
#else
|
||||||
|
CAutoResetEvent finishedEvent;
|
||||||
|
SRes writeRes;
|
||||||
|
unsigned writeIndex;
|
||||||
|
Byte ReadyBlocks[MTCODER_BLOCKS_MAX];
|
||||||
|
LONG numFinishedThreads;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
unsigned numStartedThreadsLimit;
|
||||||
|
unsigned numStartedThreads;
|
||||||
|
|
||||||
|
unsigned numBlocksMax;
|
||||||
|
unsigned blockIndex;
|
||||||
|
UInt64 readProcessed;
|
||||||
|
|
||||||
|
CCriticalSection cs;
|
||||||
|
|
||||||
|
unsigned freeBlockHead;
|
||||||
|
unsigned freeBlockList[MTCODER_BLOCKS_MAX];
|
||||||
|
|
||||||
|
CMtProgress mtProgress;
|
||||||
|
CMtCoderBlock blocks[MTCODER_BLOCKS_MAX];
|
||||||
|
CMtCoderThread threads[MTCODER_THREADS_MAX];
|
||||||
|
} CMtCoder;
|
||||||
|
|
||||||
|
|
||||||
|
void MtCoder_Construct(CMtCoder *p);
|
||||||
|
void MtCoder_Destruct(CMtCoder *p);
|
||||||
|
SRes MtCoder_Code(CMtCoder *p);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
/* MtDec.h -- Multi-thread Decoder
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_MT_DEC_H
|
||||||
|
#define ZIP7_INC_MT_DEC_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
#ifndef Z7_ST
|
||||||
|
#include "Threads.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
#ifndef Z7_ST
|
||||||
|
|
||||||
|
#ifndef Z7_ST
|
||||||
|
#define MTDEC_THREADS_MAX 32
|
||||||
|
#else
|
||||||
|
#define MTDEC_THREADS_MAX 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ICompressProgressPtr progress;
|
||||||
|
SRes res;
|
||||||
|
UInt64 totalInSize;
|
||||||
|
UInt64 totalOutSize;
|
||||||
|
CCriticalSection cs;
|
||||||
|
} CMtProgress;
|
||||||
|
|
||||||
|
void MtProgress_Init(CMtProgress *p, ICompressProgressPtr progress);
|
||||||
|
SRes MtProgress_Progress_ST(CMtProgress *p);
|
||||||
|
SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize);
|
||||||
|
SRes MtProgress_GetError(CMtProgress *p);
|
||||||
|
void MtProgress_SetError(CMtProgress *p, SRes res);
|
||||||
|
|
||||||
|
struct CMtDec;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
struct CMtDec_ *mtDec;
|
||||||
|
unsigned index;
|
||||||
|
void *inBuf;
|
||||||
|
|
||||||
|
size_t inDataSize_Start; // size of input data in start block
|
||||||
|
UInt64 inDataSize; // total size of input data in all blocks
|
||||||
|
|
||||||
|
CThread thread;
|
||||||
|
CAutoResetEvent canRead;
|
||||||
|
CAutoResetEvent canWrite;
|
||||||
|
void *allocaPtr;
|
||||||
|
} CMtDecThread;
|
||||||
|
|
||||||
|
void MtDecThread_FreeInBufs(CMtDecThread *t);
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
MTDEC_PARSE_CONTINUE, // continue this block with more input data
|
||||||
|
MTDEC_PARSE_OVERFLOW, // MT buffers overflow, need switch to single-thread
|
||||||
|
MTDEC_PARSE_NEW, // new block
|
||||||
|
MTDEC_PARSE_END // end of block threading. But we still can return to threading after Write(&needContinue)
|
||||||
|
} EMtDecParseState;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
// in
|
||||||
|
int startCall;
|
||||||
|
const Byte *src;
|
||||||
|
size_t srcSize;
|
||||||
|
// in : (srcSize == 0) is allowed
|
||||||
|
// out : it's allowed to return less that actually was used ?
|
||||||
|
int srcFinished;
|
||||||
|
|
||||||
|
// out
|
||||||
|
EMtDecParseState state;
|
||||||
|
BoolInt canCreateNewThread;
|
||||||
|
UInt64 outPos; // check it (size_t)
|
||||||
|
} CMtDecCallbackInfo;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
void (*Parse)(void *p, unsigned coderIndex, CMtDecCallbackInfo *ci);
|
||||||
|
|
||||||
|
// PreCode() and Code():
|
||||||
|
// (SRes_return_result != SZ_OK) means stop decoding, no need another blocks
|
||||||
|
SRes (*PreCode)(void *p, unsigned coderIndex);
|
||||||
|
SRes (*Code)(void *p, unsigned coderIndex,
|
||||||
|
const Byte *src, size_t srcSize, int srcFinished,
|
||||||
|
UInt64 *inCodePos, UInt64 *outCodePos, int *stop);
|
||||||
|
// stop - means stop another Code calls
|
||||||
|
|
||||||
|
|
||||||
|
/* Write() must be called, if Parse() was called
|
||||||
|
set (needWrite) if
|
||||||
|
{
|
||||||
|
&& (was not interrupted by progress)
|
||||||
|
&& (was not interrupted in previous block)
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (*needContinue), decoder still need to continue decoding with new iteration,
|
||||||
|
even after MTDEC_PARSE_END
|
||||||
|
if (*canRecode), we didn't flush current block data, so we still can decode current block later.
|
||||||
|
*/
|
||||||
|
SRes (*Write)(void *p, unsigned coderIndex,
|
||||||
|
BoolInt needWriteToStream,
|
||||||
|
const Byte *src, size_t srcSize, BoolInt isCross,
|
||||||
|
// int srcFinished,
|
||||||
|
BoolInt *needContinue,
|
||||||
|
BoolInt *canRecode);
|
||||||
|
|
||||||
|
} IMtDecCallback2;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct CMtDec_
|
||||||
|
{
|
||||||
|
/* input variables */
|
||||||
|
|
||||||
|
size_t inBufSize; /* size of input block */
|
||||||
|
unsigned numThreadsMax;
|
||||||
|
// size_t inBlockMax;
|
||||||
|
unsigned numThreadsMax_2;
|
||||||
|
|
||||||
|
ISeqInStreamPtr inStream;
|
||||||
|
// const Byte *inData;
|
||||||
|
// size_t inDataSize;
|
||||||
|
|
||||||
|
ICompressProgressPtr progress;
|
||||||
|
ISzAllocPtr alloc;
|
||||||
|
|
||||||
|
IMtDecCallback2 *mtCallback;
|
||||||
|
void *mtCallbackObject;
|
||||||
|
|
||||||
|
|
||||||
|
/* internal variables */
|
||||||
|
|
||||||
|
size_t allocatedBufsSize;
|
||||||
|
|
||||||
|
BoolInt exitThread;
|
||||||
|
WRes exitThreadWRes;
|
||||||
|
|
||||||
|
UInt64 blockIndex;
|
||||||
|
BoolInt isAllocError;
|
||||||
|
BoolInt overflow;
|
||||||
|
SRes threadingErrorSRes;
|
||||||
|
|
||||||
|
BoolInt needContinue;
|
||||||
|
|
||||||
|
// CAutoResetEvent finishedEvent;
|
||||||
|
|
||||||
|
SRes readRes;
|
||||||
|
SRes codeRes;
|
||||||
|
|
||||||
|
BoolInt wasInterrupted;
|
||||||
|
|
||||||
|
unsigned numStartedThreads_Limit;
|
||||||
|
unsigned numStartedThreads;
|
||||||
|
|
||||||
|
Byte *crossBlock;
|
||||||
|
size_t crossStart;
|
||||||
|
size_t crossEnd;
|
||||||
|
UInt64 readProcessed;
|
||||||
|
BoolInt readWasFinished;
|
||||||
|
UInt64 inProcessed;
|
||||||
|
|
||||||
|
unsigned filledThreadStart;
|
||||||
|
unsigned numFilledThreads;
|
||||||
|
|
||||||
|
#ifndef Z7_ST
|
||||||
|
BoolInt needInterrupt;
|
||||||
|
UInt64 interruptIndex;
|
||||||
|
CMtProgress mtProgress;
|
||||||
|
CMtDecThread threads[MTDEC_THREADS_MAX];
|
||||||
|
#endif
|
||||||
|
} CMtDec;
|
||||||
|
|
||||||
|
|
||||||
|
void MtDec_Construct(CMtDec *p);
|
||||||
|
void MtDec_Destruct(CMtDec *p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
MtDec_Code() returns:
|
||||||
|
SZ_OK - in most cases
|
||||||
|
MY_SRes_HRESULT_FROM_WRes(WRes_error) - in case of unexpected error in threading function
|
||||||
|
*/
|
||||||
|
|
||||||
|
SRes MtDec_Code(CMtDec *p);
|
||||||
|
Byte *MtDec_GetCrossBuff(CMtDec *p);
|
||||||
|
|
||||||
|
int MtDec_PrepareRead(CMtDec *p);
|
||||||
|
const Byte *MtDec_Read(CMtDec *p, size_t *inLim);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
/* Ppmd.h -- PPMD codec common code
|
||||||
|
2023-03-05 : Igor Pavlov : Public domain
|
||||||
|
This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_PPMD_H
|
||||||
|
#define ZIP7_INC_PPMD_H
|
||||||
|
|
||||||
|
#include "CpuArch.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
#if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4)
|
||||||
|
/*
|
||||||
|
PPMD code always uses 32-bit internal fields in PPMD structures to store internal references in main block.
|
||||||
|
if (PPMD_32BIT is defined), the PPMD code stores internal pointers to 32-bit reference fields.
|
||||||
|
if (PPMD_32BIT is NOT defined), the PPMD code stores internal UInt32 offsets to reference fields.
|
||||||
|
if (pointer size is 64-bit), then (PPMD_32BIT) mode is not allowed,
|
||||||
|
if (pointer size is 32-bit), then (PPMD_32BIT) mode is optional,
|
||||||
|
and it's allowed to disable PPMD_32BIT mode even if pointer is 32-bit.
|
||||||
|
PPMD code works slightly faster in (PPMD_32BIT) mode.
|
||||||
|
*/
|
||||||
|
#define PPMD_32BIT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PPMD_INT_BITS 7
|
||||||
|
#define PPMD_PERIOD_BITS 7
|
||||||
|
#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS))
|
||||||
|
|
||||||
|
#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift))
|
||||||
|
#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2)
|
||||||
|
#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob))
|
||||||
|
#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob))
|
||||||
|
|
||||||
|
#define PPMD_N1 4
|
||||||
|
#define PPMD_N2 4
|
||||||
|
#define PPMD_N3 4
|
||||||
|
#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4)
|
||||||
|
#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4)
|
||||||
|
|
||||||
|
MY_CPU_pragma_pack_push_1
|
||||||
|
/* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */
|
||||||
|
|
||||||
|
/* SEE-contexts for PPM-contexts with masked symbols */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UInt16 Summ; /* Freq */
|
||||||
|
Byte Shift; /* Speed of Freq change; low Shift is for fast change */
|
||||||
|
Byte Count; /* Count to next change of Shift */
|
||||||
|
} CPpmd_See;
|
||||||
|
|
||||||
|
#define Ppmd_See_UPDATE(p) \
|
||||||
|
{ if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \
|
||||||
|
{ (p)->Summ = (UInt16)((p)->Summ << 1); \
|
||||||
|
(p)->Count = (Byte)(3 << (p)->Shift++); }}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Byte Symbol;
|
||||||
|
Byte Freq;
|
||||||
|
UInt16 Successor_0;
|
||||||
|
UInt16 Successor_1;
|
||||||
|
} CPpmd_State;
|
||||||
|
|
||||||
|
typedef struct CPpmd_State2_
|
||||||
|
{
|
||||||
|
Byte Symbol;
|
||||||
|
Byte Freq;
|
||||||
|
} CPpmd_State2;
|
||||||
|
|
||||||
|
typedef struct CPpmd_State4_
|
||||||
|
{
|
||||||
|
UInt16 Successor_0;
|
||||||
|
UInt16 Successor_1;
|
||||||
|
} CPpmd_State4;
|
||||||
|
|
||||||
|
MY_CPU_pragma_pop
|
||||||
|
|
||||||
|
/*
|
||||||
|
PPMD code can write full CPpmd_State structure data to CPpmd*_Context
|
||||||
|
at (byte offset = 2) instead of some fields of original CPpmd*_Context structure.
|
||||||
|
|
||||||
|
If we use pointers to different types, but that point to shared
|
||||||
|
memory space, we can have aliasing problem (strict aliasing).
|
||||||
|
|
||||||
|
XLC compiler in -O2 mode can change the order of memory write instructions
|
||||||
|
in relation to read instructions, if we have use pointers to different types.
|
||||||
|
|
||||||
|
To solve that aliasing problem we use combined CPpmd*_Context structure
|
||||||
|
with unions that contain the fields from both structures:
|
||||||
|
the original CPpmd*_Context and CPpmd_State.
|
||||||
|
So we can access the fields from both structures via one pointer,
|
||||||
|
and the compiler doesn't change the order of write instructions
|
||||||
|
in relation to read instructions.
|
||||||
|
|
||||||
|
If we don't use memory write instructions to shared memory in
|
||||||
|
some local code, and we use only reading instructions (read only),
|
||||||
|
then probably it's safe to use pointers to different types for reading.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef PPMD_32BIT
|
||||||
|
|
||||||
|
#define Ppmd_Ref_Type(type) type *
|
||||||
|
#define Ppmd_GetRef(p, ptr) (ptr)
|
||||||
|
#define Ppmd_GetPtr(p, ptr) (ptr)
|
||||||
|
#define Ppmd_GetPtr_Type(p, ptr, note_type) (ptr)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define Ppmd_Ref_Type(type) UInt32
|
||||||
|
#define Ppmd_GetRef(p, ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))
|
||||||
|
#define Ppmd_GetPtr(p, offs) ((void *)((p)->Base + (offs)))
|
||||||
|
#define Ppmd_GetPtr_Type(p, offs, type) ((type *)Ppmd_GetPtr(p, offs))
|
||||||
|
|
||||||
|
#endif // PPMD_32BIT
|
||||||
|
|
||||||
|
|
||||||
|
typedef Ppmd_Ref_Type(CPpmd_State) CPpmd_State_Ref;
|
||||||
|
typedef Ppmd_Ref_Type(void) CPpmd_Void_Ref;
|
||||||
|
typedef Ppmd_Ref_Type(Byte) CPpmd_Byte_Ref;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifdef MY_CPU_LE_UNALIGN
|
||||||
|
// the unaligned 32-bit access latency can be too large, if the data is not in L1 cache.
|
||||||
|
#define Ppmd_GET_SUCCESSOR(p) ((CPpmd_Void_Ref)*(const UInt32 *)(const void *)&(p)->Successor_0)
|
||||||
|
#define Ppmd_SET_SUCCESSOR(p, v) *(UInt32 *)(void *)(void *)&(p)->Successor_0 = (UInt32)(v)
|
||||||
|
|
||||||
|
#else
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
We can write 16-bit halves to 32-bit (Successor) field in any selected order.
|
||||||
|
But the native order is more consistent way.
|
||||||
|
So we use the native order, if LE/BE order can be detected here at compile time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef MY_CPU_BE
|
||||||
|
|
||||||
|
#define Ppmd_GET_SUCCESSOR(p) \
|
||||||
|
( (CPpmd_Void_Ref) (((UInt32)(p)->Successor_0 << 16) | (p)->Successor_1) )
|
||||||
|
|
||||||
|
#define Ppmd_SET_SUCCESSOR(p, v) { \
|
||||||
|
(p)->Successor_0 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); \
|
||||||
|
(p)->Successor_1 = (UInt16)((UInt32)(v) /* & 0xFFFF */); }
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define Ppmd_GET_SUCCESSOR(p) \
|
||||||
|
( (CPpmd_Void_Ref) ((p)->Successor_0 | ((UInt32)(p)->Successor_1 << 16)) )
|
||||||
|
|
||||||
|
#define Ppmd_SET_SUCCESSOR(p, v) { \
|
||||||
|
(p)->Successor_0 = (UInt16)((UInt32)(v) /* & 0xFFFF */); \
|
||||||
|
(p)->Successor_1 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
|
||||||
|
#define PPMD_SetAllBitsIn256Bytes(p) \
|
||||||
|
{ size_t z; for (z = 0; z < 256 / sizeof(p[0]); z += 8) { \
|
||||||
|
p[z+7] = p[z+6] = p[z+5] = p[z+4] = p[z+3] = p[z+2] = p[z+1] = p[z+0] = ~(size_t)0; }}
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,181 @@
|
|||||||
|
/* Ppmd7.h -- Ppmd7 (PPMdH) compression codec
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain
|
||||||
|
This code is based on:
|
||||||
|
PPMd var.H (2001): Dmitry Shkarin : Public domain */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_PPMD7_H
|
||||||
|
#define ZIP7_INC_PPMD7_H
|
||||||
|
|
||||||
|
#include "Ppmd.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
#define PPMD7_MIN_ORDER 2
|
||||||
|
#define PPMD7_MAX_ORDER 64
|
||||||
|
|
||||||
|
#define PPMD7_MIN_MEM_SIZE (1 << 11)
|
||||||
|
#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3)
|
||||||
|
|
||||||
|
struct CPpmd7_Context_;
|
||||||
|
|
||||||
|
typedef Ppmd_Ref_Type(struct CPpmd7_Context_) CPpmd7_Context_Ref;
|
||||||
|
|
||||||
|
// MY_CPU_pragma_pack_push_1
|
||||||
|
|
||||||
|
typedef struct CPpmd7_Context_
|
||||||
|
{
|
||||||
|
UInt16 NumStats;
|
||||||
|
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
UInt16 SummFreq;
|
||||||
|
CPpmd_State2 State2;
|
||||||
|
} Union2;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
CPpmd_State_Ref Stats;
|
||||||
|
CPpmd_State4 State4;
|
||||||
|
} Union4;
|
||||||
|
|
||||||
|
CPpmd7_Context_Ref Suffix;
|
||||||
|
} CPpmd7_Context;
|
||||||
|
|
||||||
|
// MY_CPU_pragma_pop
|
||||||
|
|
||||||
|
#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->Union2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UInt32 Range;
|
||||||
|
UInt32 Code;
|
||||||
|
UInt32 Low;
|
||||||
|
IByteInPtr Stream;
|
||||||
|
} CPpmd7_RangeDec;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UInt32 Range;
|
||||||
|
Byte Cache;
|
||||||
|
// Byte _dummy_[3];
|
||||||
|
UInt64 Low;
|
||||||
|
UInt64 CacheSize;
|
||||||
|
IByteOutPtr Stream;
|
||||||
|
} CPpmd7z_RangeEnc;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
CPpmd7_Context *MinContext, *MaxContext;
|
||||||
|
CPpmd_State *FoundState;
|
||||||
|
unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag;
|
||||||
|
Int32 RunLength, InitRL; /* must be 32-bit at least */
|
||||||
|
|
||||||
|
UInt32 Size;
|
||||||
|
UInt32 GlueCount;
|
||||||
|
UInt32 AlignOffset;
|
||||||
|
Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
CPpmd7_RangeDec dec;
|
||||||
|
CPpmd7z_RangeEnc enc;
|
||||||
|
} rc;
|
||||||
|
|
||||||
|
Byte Indx2Units[PPMD_NUM_INDEXES + 2]; // +2 for alignment
|
||||||
|
Byte Units2Indx[128];
|
||||||
|
CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];
|
||||||
|
|
||||||
|
Byte NS2BSIndx[256], NS2Indx[256];
|
||||||
|
Byte ExpEscape[16];
|
||||||
|
CPpmd_See DummySee, See[25][16];
|
||||||
|
UInt16 BinSumm[128][64];
|
||||||
|
// int LastSymbol;
|
||||||
|
} CPpmd7;
|
||||||
|
|
||||||
|
|
||||||
|
void Ppmd7_Construct(CPpmd7 *p);
|
||||||
|
BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc);
|
||||||
|
void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc);
|
||||||
|
void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder);
|
||||||
|
#define Ppmd7_WasAllocated(p) ((p)->Base != NULL)
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------- Internal Functions ---------- */
|
||||||
|
|
||||||
|
#define Ppmd7_GetPtr(p, ptr) Ppmd_GetPtr(p, ptr)
|
||||||
|
#define Ppmd7_GetContext(p, ptr) Ppmd_GetPtr_Type(p, ptr, CPpmd7_Context)
|
||||||
|
#define Ppmd7_GetStats(p, ctx) Ppmd_GetPtr_Type(p, (ctx)->Union4.Stats, CPpmd_State)
|
||||||
|
|
||||||
|
void Ppmd7_Update1(CPpmd7 *p);
|
||||||
|
void Ppmd7_Update1_0(CPpmd7 *p);
|
||||||
|
void Ppmd7_Update2(CPpmd7 *p);
|
||||||
|
|
||||||
|
#define PPMD7_HiBitsFlag_3(sym) ((((unsigned)sym + 0xC0) >> (8 - 3)) & (1 << 3))
|
||||||
|
#define PPMD7_HiBitsFlag_4(sym) ((((unsigned)sym + 0xC0) >> (8 - 4)) & (1 << 4))
|
||||||
|
// #define PPMD7_HiBitsFlag_3(sym) ((sym) < 0x40 ? 0 : (1 << 3))
|
||||||
|
// #define PPMD7_HiBitsFlag_4(sym) ((sym) < 0x40 ? 0 : (1 << 4))
|
||||||
|
|
||||||
|
#define Ppmd7_GetBinSumm(p) \
|
||||||
|
&p->BinSumm[(size_t)(unsigned)Ppmd7Context_OneState(p->MinContext)->Freq - 1] \
|
||||||
|
[ p->PrevSuccess + ((p->RunLength >> 26) & 0x20) \
|
||||||
|
+ p->NS2BSIndx[(size_t)Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] \
|
||||||
|
+ PPMD7_HiBitsFlag_4(Ppmd7Context_OneState(p->MinContext)->Symbol) \
|
||||||
|
+ (p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol)) ]
|
||||||
|
|
||||||
|
CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
We support two versions of Ppmd7 (PPMdH) methods that use same CPpmd7 structure:
|
||||||
|
1) Ppmd7a_*: original PPMdH
|
||||||
|
2) Ppmd7z_*: modified PPMdH with 7z Range Coder
|
||||||
|
Ppmd7_*: the structures and functions that are common for both versions of PPMd7 (PPMdH)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ---------- Decode ---------- */
|
||||||
|
|
||||||
|
#define PPMD7_SYM_END (-1)
|
||||||
|
#define PPMD7_SYM_ERROR (-2)
|
||||||
|
|
||||||
|
/*
|
||||||
|
You must set (CPpmd7::rc.dec.Stream) before Ppmd7*_RangeDec_Init()
|
||||||
|
|
||||||
|
Ppmd7*_DecodeSymbol()
|
||||||
|
out:
|
||||||
|
>= 0 : decoded byte
|
||||||
|
-1 : PPMD7_SYM_END : End of payload marker
|
||||||
|
-2 : PPMD7_SYM_ERROR : Data error
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Ppmd7a_* : original PPMdH */
|
||||||
|
BoolInt Ppmd7a_RangeDec_Init(CPpmd7_RangeDec *p);
|
||||||
|
#define Ppmd7a_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
|
||||||
|
int Ppmd7a_DecodeSymbol(CPpmd7 *p);
|
||||||
|
|
||||||
|
/* Ppmd7z_* : modified PPMdH with 7z Range Coder */
|
||||||
|
BoolInt Ppmd7z_RangeDec_Init(CPpmd7_RangeDec *p);
|
||||||
|
#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
|
||||||
|
int Ppmd7z_DecodeSymbol(CPpmd7 *p);
|
||||||
|
// Byte *Ppmd7z_DecodeSymbols(CPpmd7 *p, Byte *buf, const Byte *lim);
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------- Encode ---------- */
|
||||||
|
|
||||||
|
void Ppmd7z_Init_RangeEnc(CPpmd7 *p);
|
||||||
|
void Ppmd7z_Flush_RangeEnc(CPpmd7 *p);
|
||||||
|
// void Ppmd7z_EncodeSymbol(CPpmd7 *p, int symbol);
|
||||||
|
void Ppmd7z_EncodeSymbols(CPpmd7 *p, const Byte *buf, const Byte *lim);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,312 @@
|
|||||||
|
/* Ppmd7Dec.c -- Ppmd7z (PPMdH with 7z Range Coder) Decoder
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain
|
||||||
|
This code is based on:
|
||||||
|
PPMd var.H (2001): Dmitry Shkarin : Public domain */
|
||||||
|
|
||||||
|
|
||||||
|
#include "Precomp.h"
|
||||||
|
|
||||||
|
#include "Ppmd7.h"
|
||||||
|
|
||||||
|
#define kTopValue ((UInt32)1 << 24)
|
||||||
|
|
||||||
|
|
||||||
|
#define READ_BYTE(p) IByteIn_Read((p)->Stream)
|
||||||
|
|
||||||
|
BoolInt Ppmd7z_RangeDec_Init(CPpmd7_RangeDec *p)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
p->Code = 0;
|
||||||
|
p->Range = 0xFFFFFFFF;
|
||||||
|
if (READ_BYTE(p) != 0)
|
||||||
|
return False;
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
p->Code = (p->Code << 8) | READ_BYTE(p);
|
||||||
|
return (p->Code < 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RC_NORM_BASE(p) if ((p)->Range < kTopValue) \
|
||||||
|
{ (p)->Code = ((p)->Code << 8) | READ_BYTE(p); (p)->Range <<= 8;
|
||||||
|
|
||||||
|
#define RC_NORM_1(p) RC_NORM_BASE(p) }
|
||||||
|
#define RC_NORM(p) RC_NORM_BASE(p) RC_NORM_BASE(p) }}
|
||||||
|
|
||||||
|
// we must use only one type of Normalization from two: LOCAL or REMOTE
|
||||||
|
#define RC_NORM_LOCAL(p) // RC_NORM(p)
|
||||||
|
#define RC_NORM_REMOTE(p) RC_NORM(p)
|
||||||
|
|
||||||
|
#define R (&p->rc.dec)
|
||||||
|
|
||||||
|
Z7_FORCE_INLINE
|
||||||
|
// Z7_NO_INLINE
|
||||||
|
static void Ppmd7z_RD_Decode(CPpmd7 *p, UInt32 start, UInt32 size)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
R->Code -= start * R->Range;
|
||||||
|
R->Range *= size;
|
||||||
|
RC_NORM_LOCAL(R)
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RC_Decode(start, size) Ppmd7z_RD_Decode(p, start, size);
|
||||||
|
#define RC_DecodeFinal(start, size) RC_Decode(start, size) RC_NORM_REMOTE(R)
|
||||||
|
#define RC_GetThreshold(total) (R->Code / (R->Range /= (total)))
|
||||||
|
|
||||||
|
|
||||||
|
#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))
|
||||||
|
// typedef CPpmd7_Context * CTX_PTR;
|
||||||
|
#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
|
||||||
|
void Ppmd7_UpdateModel(CPpmd7 *p);
|
||||||
|
|
||||||
|
#define MASK(sym) ((unsigned char *)charMask)[sym]
|
||||||
|
// Z7_FORCE_INLINE
|
||||||
|
// static
|
||||||
|
int Ppmd7z_DecodeSymbol(CPpmd7 *p)
|
||||||
|
{
|
||||||
|
size_t charMask[256 / sizeof(size_t)];
|
||||||
|
|
||||||
|
if (p->MinContext->NumStats != 1)
|
||||||
|
{
|
||||||
|
CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
|
||||||
|
unsigned i;
|
||||||
|
UInt32 count, hiCnt;
|
||||||
|
const UInt32 summFreq = p->MinContext->Union2.SummFreq;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
count = RC_GetThreshold(summFreq);
|
||||||
|
hiCnt = count;
|
||||||
|
|
||||||
|
if ((Int32)(count -= s->Freq) < 0)
|
||||||
|
{
|
||||||
|
Byte sym;
|
||||||
|
RC_DecodeFinal(0, s->Freq)
|
||||||
|
p->FoundState = s;
|
||||||
|
sym = s->Symbol;
|
||||||
|
Ppmd7_Update1_0(p);
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->PrevSuccess = 0;
|
||||||
|
i = (unsigned)p->MinContext->NumStats - 1;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if ((Int32)(count -= (++s)->Freq) < 0)
|
||||||
|
{
|
||||||
|
Byte sym;
|
||||||
|
RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq)
|
||||||
|
p->FoundState = s;
|
||||||
|
sym = s->Symbol;
|
||||||
|
Ppmd7_Update1(p);
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (--i);
|
||||||
|
|
||||||
|
if (hiCnt >= summFreq)
|
||||||
|
return PPMD7_SYM_ERROR;
|
||||||
|
|
||||||
|
hiCnt -= count;
|
||||||
|
RC_Decode(hiCnt, summFreq - hiCnt)
|
||||||
|
|
||||||
|
p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol);
|
||||||
|
PPMD_SetAllBitsIn256Bytes(charMask)
|
||||||
|
// i = p->MinContext->NumStats - 1;
|
||||||
|
// do { MASK((--s)->Symbol) = 0; } while (--i);
|
||||||
|
{
|
||||||
|
CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext);
|
||||||
|
MASK(s->Symbol) = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
unsigned sym0 = s2[0].Symbol;
|
||||||
|
unsigned sym1 = s2[1].Symbol;
|
||||||
|
s2 += 2;
|
||||||
|
MASK(sym0) = 0;
|
||||||
|
MASK(sym1) = 0;
|
||||||
|
}
|
||||||
|
while (s2 < s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CPpmd_State *s = Ppmd7Context_OneState(p->MinContext);
|
||||||
|
UInt16 *prob = Ppmd7_GetBinSumm(p);
|
||||||
|
UInt32 pr = *prob;
|
||||||
|
UInt32 size0 = (R->Range >> 14) * pr;
|
||||||
|
pr = PPMD_UPDATE_PROB_1(pr);
|
||||||
|
|
||||||
|
if (R->Code < size0)
|
||||||
|
{
|
||||||
|
Byte sym;
|
||||||
|
*prob = (UInt16)(pr + (1 << PPMD_INT_BITS));
|
||||||
|
|
||||||
|
// RangeDec_DecodeBit0(size0);
|
||||||
|
R->Range = size0;
|
||||||
|
RC_NORM_1(R)
|
||||||
|
/* we can use single byte normalization here because of
|
||||||
|
(min(BinSumm[][]) = 95) > (1 << (14 - 8)) */
|
||||||
|
|
||||||
|
// sym = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol;
|
||||||
|
// Ppmd7_UpdateBin(p);
|
||||||
|
{
|
||||||
|
unsigned freq = s->Freq;
|
||||||
|
CPpmd7_Context *c = CTX(SUCCESSOR(s));
|
||||||
|
sym = s->Symbol;
|
||||||
|
p->FoundState = s;
|
||||||
|
p->PrevSuccess = 1;
|
||||||
|
p->RunLength++;
|
||||||
|
s->Freq = (Byte)(freq + (freq < 128));
|
||||||
|
// NextContext(p);
|
||||||
|
if (p->OrderFall == 0 && (const Byte *)c > p->Text)
|
||||||
|
p->MaxContext = p->MinContext = c;
|
||||||
|
else
|
||||||
|
Ppmd7_UpdateModel(p);
|
||||||
|
}
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
|
||||||
|
*prob = (UInt16)pr;
|
||||||
|
p->InitEsc = p->ExpEscape[pr >> 10];
|
||||||
|
|
||||||
|
// RangeDec_DecodeBit1(size0);
|
||||||
|
|
||||||
|
R->Code -= size0;
|
||||||
|
R->Range -= size0;
|
||||||
|
RC_NORM_LOCAL(R)
|
||||||
|
|
||||||
|
PPMD_SetAllBitsIn256Bytes(charMask)
|
||||||
|
MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0;
|
||||||
|
p->PrevSuccess = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
CPpmd_State *s, *s2;
|
||||||
|
UInt32 freqSum, count, hiCnt;
|
||||||
|
|
||||||
|
CPpmd_See *see;
|
||||||
|
CPpmd7_Context *mc;
|
||||||
|
unsigned numMasked;
|
||||||
|
RC_NORM_REMOTE(R)
|
||||||
|
mc = p->MinContext;
|
||||||
|
numMasked = mc->NumStats;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
p->OrderFall++;
|
||||||
|
if (!mc->Suffix)
|
||||||
|
return PPMD7_SYM_END;
|
||||||
|
mc = Ppmd7_GetContext(p, mc->Suffix);
|
||||||
|
}
|
||||||
|
while (mc->NumStats == numMasked);
|
||||||
|
|
||||||
|
s = Ppmd7_GetStats(p, mc);
|
||||||
|
|
||||||
|
{
|
||||||
|
unsigned num = mc->NumStats;
|
||||||
|
unsigned num2 = num / 2;
|
||||||
|
|
||||||
|
num &= 1;
|
||||||
|
hiCnt = (s->Freq & (unsigned)(MASK(s->Symbol))) & (0 - (UInt32)num);
|
||||||
|
s += num;
|
||||||
|
p->MinContext = mc;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
unsigned sym0 = s[0].Symbol;
|
||||||
|
unsigned sym1 = s[1].Symbol;
|
||||||
|
s += 2;
|
||||||
|
hiCnt += (s[-2].Freq & (unsigned)(MASK(sym0)));
|
||||||
|
hiCnt += (s[-1].Freq & (unsigned)(MASK(sym1)));
|
||||||
|
}
|
||||||
|
while (--num2);
|
||||||
|
}
|
||||||
|
|
||||||
|
see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum);
|
||||||
|
freqSum += hiCnt;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
count = RC_GetThreshold(freqSum);
|
||||||
|
|
||||||
|
if (count < hiCnt)
|
||||||
|
{
|
||||||
|
Byte sym;
|
||||||
|
|
||||||
|
s = Ppmd7_GetStats(p, p->MinContext);
|
||||||
|
hiCnt = count;
|
||||||
|
// count -= s->Freq & (unsigned)(MASK(s->Symbol));
|
||||||
|
// if ((Int32)count >= 0)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break;
|
||||||
|
// count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s--;
|
||||||
|
RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq)
|
||||||
|
|
||||||
|
// new (see->Summ) value can overflow over 16-bits in some rare cases
|
||||||
|
Ppmd_See_UPDATE(see)
|
||||||
|
p->FoundState = s;
|
||||||
|
sym = s->Symbol;
|
||||||
|
Ppmd7_Update2(p);
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count >= freqSum)
|
||||||
|
return PPMD7_SYM_ERROR;
|
||||||
|
|
||||||
|
RC_Decode(hiCnt, freqSum - hiCnt)
|
||||||
|
|
||||||
|
// We increase (see->Summ) for sum of Freqs of all non_Masked symbols.
|
||||||
|
// new (see->Summ) value can overflow over 16-bits in some rare cases
|
||||||
|
see->Summ = (UInt16)(see->Summ + freqSum);
|
||||||
|
|
||||||
|
s = Ppmd7_GetStats(p, p->MinContext);
|
||||||
|
s2 = s + p->MinContext->NumStats;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
MASK(s->Symbol) = 0;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
while (s != s2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Byte *Ppmd7z_DecodeSymbols(CPpmd7 *p, Byte *buf, const Byte *lim)
|
||||||
|
{
|
||||||
|
int sym = 0;
|
||||||
|
if (buf != lim)
|
||||||
|
do
|
||||||
|
{
|
||||||
|
sym = Ppmd7z_DecodeSymbol(p);
|
||||||
|
if (sym < 0)
|
||||||
|
break;
|
||||||
|
*buf = (Byte)sym;
|
||||||
|
}
|
||||||
|
while (++buf < lim);
|
||||||
|
p->LastSymbol = sym;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef kTopValue
|
||||||
|
#undef READ_BYTE
|
||||||
|
#undef RC_NORM_BASE
|
||||||
|
#undef RC_NORM_1
|
||||||
|
#undef RC_NORM
|
||||||
|
#undef RC_NORM_LOCAL
|
||||||
|
#undef RC_NORM_REMOTE
|
||||||
|
#undef R
|
||||||
|
#undef RC_Decode
|
||||||
|
#undef RC_DecodeFinal
|
||||||
|
#undef RC_GetThreshold
|
||||||
|
#undef CTX
|
||||||
|
#undef SUCCESSOR
|
||||||
|
#undef MASK
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/* Precomp.h -- StdAfx
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_PRECOMP_H
|
||||||
|
#define ZIP7_INC_PRECOMP_H
|
||||||
|
|
||||||
|
#include "Compiler.h"
|
||||||
|
/* #include "7zTypes.h" */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/* RotateDefs.h -- Rotate functions
|
||||||
|
2023-06-18 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_ROTATE_DEFS_H
|
||||||
|
#define ZIP7_INC_ROTATE_DEFS_H
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* don't use _rotl with old MINGW. It can insert slow call to function. */
|
||||||
|
|
||||||
|
/* #if (_MSC_VER >= 1200) */
|
||||||
|
#pragma intrinsic(_rotl)
|
||||||
|
#pragma intrinsic(_rotr)
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
#define rotlFixed(x, n) _rotl((x), (n))
|
||||||
|
#define rotrFixed(x, n) _rotr((x), (n))
|
||||||
|
|
||||||
|
#if (_MSC_VER >= 1300)
|
||||||
|
#define Z7_ROTL64(x, n) _rotl64((x), (n))
|
||||||
|
#define Z7_ROTR64(x, n) _rotr64((x), (n))
|
||||||
|
#else
|
||||||
|
#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n))))
|
||||||
|
#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (64 - (n))))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* new compilers can translate these macros to fast commands. */
|
||||||
|
|
||||||
|
#if defined(__clang__) && (__clang_major__ >= 4) \
|
||||||
|
|| defined(__GNUC__) && (__GNUC__ >= 5)
|
||||||
|
/* GCC 4.9.0 and clang 3.5 can recognize more correct version: */
|
||||||
|
#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (-(n) & 31)))
|
||||||
|
#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (-(n) & 31)))
|
||||||
|
#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (-(n) & 63)))
|
||||||
|
#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (-(n) & 63)))
|
||||||
|
#else
|
||||||
|
/* for old GCC / clang: */
|
||||||
|
#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||||
|
#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
|
||||||
|
#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n))))
|
||||||
|
#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (64 - (n))))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/* Sha256.h -- SHA-256 Hash
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_SHA256_H
|
||||||
|
#define ZIP7_INC_SHA256_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
#define SHA256_NUM_BLOCK_WORDS 16
|
||||||
|
#define SHA256_NUM_DIGEST_WORDS 8
|
||||||
|
|
||||||
|
#define SHA256_BLOCK_SIZE (SHA256_NUM_BLOCK_WORDS * 4)
|
||||||
|
#define SHA256_DIGEST_SIZE (SHA256_NUM_DIGEST_WORDS * 4)
|
||||||
|
|
||||||
|
typedef void (Z7_FASTCALL *SHA256_FUNC_UPDATE_BLOCKS)(UInt32 state[8], const Byte *data, size_t numBlocks);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (the system supports different SHA256 code implementations)
|
||||||
|
{
|
||||||
|
(CSha256::func_UpdateBlocks) will be used
|
||||||
|
(CSha256::func_UpdateBlocks) can be set by
|
||||||
|
Sha256_Init() - to default (fastest)
|
||||||
|
Sha256_SetFunction() - to any algo
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(CSha256::func_UpdateBlocks) is ignored.
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SHA256_FUNC_UPDATE_BLOCKS func_UpdateBlocks;
|
||||||
|
UInt64 count;
|
||||||
|
UInt64 _pad_2[2];
|
||||||
|
UInt32 state[SHA256_NUM_DIGEST_WORDS];
|
||||||
|
|
||||||
|
Byte buffer[SHA256_BLOCK_SIZE];
|
||||||
|
} CSha256;
|
||||||
|
|
||||||
|
|
||||||
|
#define SHA256_ALGO_DEFAULT 0
|
||||||
|
#define SHA256_ALGO_SW 1
|
||||||
|
#define SHA256_ALGO_HW 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
Sha256_SetFunction()
|
||||||
|
return:
|
||||||
|
0 - (algo) value is not supported, and func_UpdateBlocks was not changed
|
||||||
|
1 - func_UpdateBlocks was set according (algo) value.
|
||||||
|
*/
|
||||||
|
|
||||||
|
BoolInt Sha256_SetFunction(CSha256 *p, unsigned algo);
|
||||||
|
|
||||||
|
void Sha256_InitState(CSha256 *p);
|
||||||
|
void Sha256_Init(CSha256 *p);
|
||||||
|
void Sha256_Update(CSha256 *p, const Byte *data, size_t size);
|
||||||
|
void Sha256_Final(CSha256 *p, Byte *digest);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks);
|
||||||
|
|
||||||
|
/*
|
||||||
|
call Sha256Prepare() once at program start.
|
||||||
|
It prepares all supported implementations, and detects the fastest implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void Sha256Prepare(void);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/* Sort.h -- Sort functions
|
||||||
|
2023-03-05 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_SORT_H
|
||||||
|
#define ZIP7_INC_SORT_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
void HeapSort(UInt32 *p, size_t size);
|
||||||
|
void HeapSort64(UInt64 *p, size_t size);
|
||||||
|
|
||||||
|
/* void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size); */
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
/* SwapBytes.h -- Byte Swap conversion filter
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_SWAP_BYTES_H
|
||||||
|
#define ZIP7_INC_SWAP_BYTES_H
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
void z7_SwapBytes2(UInt16 *data, size_t numItems);
|
||||||
|
void z7_SwapBytes4(UInt32 *data, size_t numItems);
|
||||||
|
void z7_SwapBytesPrepare(void);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,240 @@
|
|||||||
|
/* Threads.h -- multithreading library
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_THREADS_H
|
||||||
|
#define ZIP7_INC_THREADS_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "7zWindows.h"
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
#if !defined(__APPLE__) && !defined(_AIX) && !defined(__ANDROID__)
|
||||||
|
#ifndef Z7_AFFINITY_DISABLE
|
||||||
|
#define Z7_AFFINITY_SUPPORTED
|
||||||
|
// #pragma message(" ==== Z7_AFFINITY_SUPPORTED")
|
||||||
|
// #define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
WRes HandlePtr_Close(HANDLE *h);
|
||||||
|
WRes Handle_WaitObject(HANDLE h);
|
||||||
|
|
||||||
|
typedef HANDLE CThread;
|
||||||
|
|
||||||
|
#define Thread_CONSTRUCT(p) { *(p) = NULL; }
|
||||||
|
#define Thread_WasCreated(p) (*(p) != NULL)
|
||||||
|
#define Thread_Close(p) HandlePtr_Close(p)
|
||||||
|
// #define Thread_Wait(p) Handle_WaitObject(*(p))
|
||||||
|
|
||||||
|
#ifdef UNDER_CE
|
||||||
|
// if (USE_THREADS_CreateThread is defined), we use _beginthreadex()
|
||||||
|
// if (USE_THREADS_CreateThread is not definned), we use CreateThread()
|
||||||
|
#define USE_THREADS_CreateThread
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef
|
||||||
|
#ifdef USE_THREADS_CreateThread
|
||||||
|
DWORD
|
||||||
|
#else
|
||||||
|
unsigned
|
||||||
|
#endif
|
||||||
|
THREAD_FUNC_RET_TYPE;
|
||||||
|
|
||||||
|
#define THREAD_FUNC_RET_ZERO 0
|
||||||
|
|
||||||
|
typedef DWORD_PTR CAffinityMask;
|
||||||
|
typedef DWORD_PTR CCpuSet;
|
||||||
|
|
||||||
|
#define CpuSet_Zero(p) *(p) = (0)
|
||||||
|
#define CpuSet_Set(p, cpu) *(p) |= ((DWORD_PTR)1 << (cpu))
|
||||||
|
|
||||||
|
#else // _WIN32
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
pthread_t _tid;
|
||||||
|
int _created;
|
||||||
|
} CThread;
|
||||||
|
|
||||||
|
#define Thread_CONSTRUCT(p) { (p)->_tid = 0; (p)->_created = 0; }
|
||||||
|
#define Thread_WasCreated(p) ((p)->_created != 0)
|
||||||
|
WRes Thread_Close(CThread *p);
|
||||||
|
// #define Thread_Wait Thread_Wait_Close
|
||||||
|
|
||||||
|
typedef void * THREAD_FUNC_RET_TYPE;
|
||||||
|
#define THREAD_FUNC_RET_ZERO NULL
|
||||||
|
|
||||||
|
|
||||||
|
typedef UInt64 CAffinityMask;
|
||||||
|
|
||||||
|
#ifdef Z7_AFFINITY_SUPPORTED
|
||||||
|
|
||||||
|
typedef cpu_set_t CCpuSet;
|
||||||
|
#define CpuSet_Zero(p) CPU_ZERO(p)
|
||||||
|
#define CpuSet_Set(p, cpu) CPU_SET(cpu, p)
|
||||||
|
#define CpuSet_IsSet(p, cpu) CPU_ISSET(cpu, p)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
typedef UInt64 CCpuSet;
|
||||||
|
#define CpuSet_Zero(p) *(p) = (0)
|
||||||
|
#define CpuSet_Set(p, cpu) *(p) |= ((UInt64)1 << (cpu))
|
||||||
|
#define CpuSet_IsSet(p, cpu) ((*(p) & ((UInt64)1 << (cpu))) != 0)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
|
||||||
|
#define THREAD_FUNC_CALL_TYPE Z7_STDCALL
|
||||||
|
|
||||||
|
#if defined(_WIN32) && defined(__GNUC__)
|
||||||
|
/* GCC compiler for x86 32-bit uses the rule:
|
||||||
|
the stack is 16-byte aligned before CALL instruction for function calling.
|
||||||
|
But only root function main() contains instructions that
|
||||||
|
set 16-byte alignment for stack pointer. And another functions
|
||||||
|
just keep alignment, if it was set in some parent function.
|
||||||
|
|
||||||
|
The problem:
|
||||||
|
if we create new thread in MinGW (GCC) 32-bit x86 via _beginthreadex() or CreateThread(),
|
||||||
|
the root function of thread doesn't set 16-byte alignment.
|
||||||
|
And stack frames in all child functions also will be unaligned in that case.
|
||||||
|
|
||||||
|
Here we set (force_align_arg_pointer) attribute for root function of new thread.
|
||||||
|
Do we need (force_align_arg_pointer) also for another systems? */
|
||||||
|
|
||||||
|
#define THREAD_FUNC_ATTRIB_ALIGN_ARG __attribute__((force_align_arg_pointer))
|
||||||
|
// #define THREAD_FUNC_ATTRIB_ALIGN_ARG // for debug : bad alignment in SSE functions
|
||||||
|
#else
|
||||||
|
#define THREAD_FUNC_ATTRIB_ALIGN_ARG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define THREAD_FUNC_DECL THREAD_FUNC_ATTRIB_ALIGN_ARG THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE
|
||||||
|
|
||||||
|
typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *);
|
||||||
|
WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param);
|
||||||
|
WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity);
|
||||||
|
WRes Thread_Wait_Close(CThread *p);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define Thread_Create_With_CpuSet(p, func, param, cs) \
|
||||||
|
Thread_Create_With_Affinity(p, func, param, *cs)
|
||||||
|
#else
|
||||||
|
WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
typedef HANDLE CEvent;
|
||||||
|
typedef CEvent CAutoResetEvent;
|
||||||
|
typedef CEvent CManualResetEvent;
|
||||||
|
#define Event_Construct(p) *(p) = NULL
|
||||||
|
#define Event_IsCreated(p) (*(p) != NULL)
|
||||||
|
#define Event_Close(p) HandlePtr_Close(p)
|
||||||
|
#define Event_Wait(p) Handle_WaitObject(*(p))
|
||||||
|
WRes Event_Set(CEvent *p);
|
||||||
|
WRes Event_Reset(CEvent *p);
|
||||||
|
WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled);
|
||||||
|
WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p);
|
||||||
|
WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled);
|
||||||
|
WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p);
|
||||||
|
|
||||||
|
typedef HANDLE CSemaphore;
|
||||||
|
#define Semaphore_Construct(p) *(p) = NULL
|
||||||
|
#define Semaphore_IsCreated(p) (*(p) != NULL)
|
||||||
|
#define Semaphore_Close(p) HandlePtr_Close(p)
|
||||||
|
#define Semaphore_Wait(p) Handle_WaitObject(*(p))
|
||||||
|
WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
|
||||||
|
WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
|
||||||
|
WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num);
|
||||||
|
WRes Semaphore_Release1(CSemaphore *p);
|
||||||
|
|
||||||
|
typedef CRITICAL_SECTION CCriticalSection;
|
||||||
|
WRes CriticalSection_Init(CCriticalSection *p);
|
||||||
|
#define CriticalSection_Delete(p) DeleteCriticalSection(p)
|
||||||
|
#define CriticalSection_Enter(p) EnterCriticalSection(p)
|
||||||
|
#define CriticalSection_Leave(p) LeaveCriticalSection(p)
|
||||||
|
|
||||||
|
|
||||||
|
#else // _WIN32
|
||||||
|
|
||||||
|
typedef struct _CEvent
|
||||||
|
{
|
||||||
|
int _created;
|
||||||
|
int _manual_reset;
|
||||||
|
int _state;
|
||||||
|
pthread_mutex_t _mutex;
|
||||||
|
pthread_cond_t _cond;
|
||||||
|
} CEvent;
|
||||||
|
|
||||||
|
typedef CEvent CAutoResetEvent;
|
||||||
|
typedef CEvent CManualResetEvent;
|
||||||
|
|
||||||
|
#define Event_Construct(p) (p)->_created = 0
|
||||||
|
#define Event_IsCreated(p) ((p)->_created)
|
||||||
|
|
||||||
|
WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled);
|
||||||
|
WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p);
|
||||||
|
WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled);
|
||||||
|
WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p);
|
||||||
|
|
||||||
|
WRes Event_Set(CEvent *p);
|
||||||
|
WRes Event_Reset(CEvent *p);
|
||||||
|
WRes Event_Wait(CEvent *p);
|
||||||
|
WRes Event_Close(CEvent *p);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _CSemaphore
|
||||||
|
{
|
||||||
|
int _created;
|
||||||
|
UInt32 _count;
|
||||||
|
UInt32 _maxCount;
|
||||||
|
pthread_mutex_t _mutex;
|
||||||
|
pthread_cond_t _cond;
|
||||||
|
} CSemaphore;
|
||||||
|
|
||||||
|
#define Semaphore_Construct(p) (p)->_created = 0
|
||||||
|
#define Semaphore_IsCreated(p) ((p)->_created)
|
||||||
|
|
||||||
|
WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
|
||||||
|
WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
|
||||||
|
WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num);
|
||||||
|
#define Semaphore_Release1(p) Semaphore_ReleaseN(p, 1)
|
||||||
|
WRes Semaphore_Wait(CSemaphore *p);
|
||||||
|
WRes Semaphore_Close(CSemaphore *p);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _CCriticalSection
|
||||||
|
{
|
||||||
|
pthread_mutex_t _mutex;
|
||||||
|
} CCriticalSection;
|
||||||
|
|
||||||
|
WRes CriticalSection_Init(CCriticalSection *p);
|
||||||
|
void CriticalSection_Delete(CCriticalSection *cs);
|
||||||
|
void CriticalSection_Enter(CCriticalSection *cs);
|
||||||
|
void CriticalSection_Leave(CCriticalSection *cs);
|
||||||
|
|
||||||
|
LONG InterlockedIncrement(LONG volatile *addend);
|
||||||
|
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
WRes AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent *p);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,535 @@
|
|||||||
|
/* Xz.h - Xz interface
|
||||||
|
2023-04-13 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_XZ_H
|
||||||
|
#define ZIP7_INC_XZ_H
|
||||||
|
|
||||||
|
#include "Sha256.h"
|
||||||
|
#include "Delta.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
#define XZ_ID_Subblock 1
|
||||||
|
#define XZ_ID_Delta 3
|
||||||
|
#define XZ_ID_X86 4
|
||||||
|
#define XZ_ID_PPC 5
|
||||||
|
#define XZ_ID_IA64 6
|
||||||
|
#define XZ_ID_ARM 7
|
||||||
|
#define XZ_ID_ARMT 8
|
||||||
|
#define XZ_ID_SPARC 9
|
||||||
|
#define XZ_ID_ARM64 0xa
|
||||||
|
#define XZ_ID_LZMA2 0x21
|
||||||
|
|
||||||
|
unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value);
|
||||||
|
unsigned Xz_WriteVarInt(Byte *buf, UInt64 v);
|
||||||
|
|
||||||
|
/* ---------- xz block ---------- */
|
||||||
|
|
||||||
|
#define XZ_BLOCK_HEADER_SIZE_MAX 1024
|
||||||
|
|
||||||
|
#define XZ_NUM_FILTERS_MAX 4
|
||||||
|
#define XZ_BF_NUM_FILTERS_MASK 3
|
||||||
|
#define XZ_BF_PACK_SIZE (1 << 6)
|
||||||
|
#define XZ_BF_UNPACK_SIZE (1 << 7)
|
||||||
|
|
||||||
|
#define XZ_FILTER_PROPS_SIZE_MAX 20
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UInt64 id;
|
||||||
|
UInt32 propsSize;
|
||||||
|
Byte props[XZ_FILTER_PROPS_SIZE_MAX];
|
||||||
|
} CXzFilter;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UInt64 packSize;
|
||||||
|
UInt64 unpackSize;
|
||||||
|
Byte flags;
|
||||||
|
CXzFilter filters[XZ_NUM_FILTERS_MAX];
|
||||||
|
} CXzBlock;
|
||||||
|
|
||||||
|
#define XzBlock_GetNumFilters(p) (((unsigned)(p)->flags & XZ_BF_NUM_FILTERS_MASK) + 1)
|
||||||
|
#define XzBlock_HasPackSize(p) (((p)->flags & XZ_BF_PACK_SIZE) != 0)
|
||||||
|
#define XzBlock_HasUnpackSize(p) (((p)->flags & XZ_BF_UNPACK_SIZE) != 0)
|
||||||
|
#define XzBlock_HasUnsupportedFlags(p) (((p)->flags & ~(XZ_BF_NUM_FILTERS_MASK | XZ_BF_PACK_SIZE | XZ_BF_UNPACK_SIZE)) != 0)
|
||||||
|
|
||||||
|
SRes XzBlock_Parse(CXzBlock *p, const Byte *header);
|
||||||
|
SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStreamPtr inStream, BoolInt *isIndex, UInt32 *headerSizeRes);
|
||||||
|
|
||||||
|
/* ---------- xz stream ---------- */
|
||||||
|
|
||||||
|
#define XZ_SIG_SIZE 6
|
||||||
|
#define XZ_FOOTER_SIG_SIZE 2
|
||||||
|
|
||||||
|
extern const Byte XZ_SIG[XZ_SIG_SIZE];
|
||||||
|
|
||||||
|
/*
|
||||||
|
extern const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE];
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define XZ_FOOTER_SIG_0 'Y'
|
||||||
|
#define XZ_FOOTER_SIG_1 'Z'
|
||||||
|
|
||||||
|
#define XZ_STREAM_FLAGS_SIZE 2
|
||||||
|
#define XZ_STREAM_CRC_SIZE 4
|
||||||
|
|
||||||
|
#define XZ_STREAM_HEADER_SIZE (XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE)
|
||||||
|
#define XZ_STREAM_FOOTER_SIZE (XZ_FOOTER_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE + 4)
|
||||||
|
|
||||||
|
#define XZ_CHECK_MASK 0xF
|
||||||
|
#define XZ_CHECK_NO 0
|
||||||
|
#define XZ_CHECK_CRC32 1
|
||||||
|
#define XZ_CHECK_CRC64 4
|
||||||
|
#define XZ_CHECK_SHA256 10
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned mode;
|
||||||
|
UInt32 crc;
|
||||||
|
UInt64 crc64;
|
||||||
|
CSha256 sha;
|
||||||
|
} CXzCheck;
|
||||||
|
|
||||||
|
void XzCheck_Init(CXzCheck *p, unsigned mode);
|
||||||
|
void XzCheck_Update(CXzCheck *p, const void *data, size_t size);
|
||||||
|
int XzCheck_Final(CXzCheck *p, Byte *digest);
|
||||||
|
|
||||||
|
typedef UInt16 CXzStreamFlags;
|
||||||
|
|
||||||
|
#define XzFlags_IsSupported(f) ((f) <= XZ_CHECK_MASK)
|
||||||
|
#define XzFlags_GetCheckType(f) ((f) & XZ_CHECK_MASK)
|
||||||
|
#define XzFlags_HasDataCrc32(f) (Xz_GetCheckType(f) == XZ_CHECK_CRC32)
|
||||||
|
unsigned XzFlags_GetCheckSize(CXzStreamFlags f);
|
||||||
|
|
||||||
|
SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf);
|
||||||
|
SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStreamPtr inStream);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UInt64 unpackSize;
|
||||||
|
UInt64 totalSize;
|
||||||
|
} CXzBlockSizes;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
CXzStreamFlags flags;
|
||||||
|
// Byte _pad[6];
|
||||||
|
size_t numBlocks;
|
||||||
|
CXzBlockSizes *blocks;
|
||||||
|
UInt64 startOffset;
|
||||||
|
} CXzStream;
|
||||||
|
|
||||||
|
void Xz_Construct(CXzStream *p);
|
||||||
|
void Xz_Free(CXzStream *p, ISzAllocPtr alloc);
|
||||||
|
|
||||||
|
#define XZ_SIZE_OVERFLOW ((UInt64)(Int64)-1)
|
||||||
|
|
||||||
|
UInt64 Xz_GetUnpackSize(const CXzStream *p);
|
||||||
|
UInt64 Xz_GetPackSize(const CXzStream *p);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
size_t num;
|
||||||
|
size_t numAllocated;
|
||||||
|
CXzStream *streams;
|
||||||
|
} CXzs;
|
||||||
|
|
||||||
|
void Xzs_Construct(CXzs *p);
|
||||||
|
void Xzs_Free(CXzs *p, ISzAllocPtr alloc);
|
||||||
|
SRes Xzs_ReadBackward(CXzs *p, ILookInStreamPtr inStream, Int64 *startOffset, ICompressProgressPtr progress, ISzAllocPtr alloc);
|
||||||
|
|
||||||
|
UInt64 Xzs_GetNumBlocks(const CXzs *p);
|
||||||
|
UInt64 Xzs_GetUnpackSize(const CXzs *p);
|
||||||
|
|
||||||
|
|
||||||
|
// ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */
|
||||||
|
CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
|
||||||
|
CODER_STATUS_NOT_FINISHED, /* stream was not finished */
|
||||||
|
CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */
|
||||||
|
} ECoderStatus;
|
||||||
|
|
||||||
|
|
||||||
|
// ECoderFinishMode values are identical to ELzmaFinishMode
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
CODER_FINISH_ANY, /* finish at any point */
|
||||||
|
CODER_FINISH_END /* block must be finished at the end */
|
||||||
|
} ECoderFinishMode;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
void *p; // state object;
|
||||||
|
void (*Free)(void *p, ISzAllocPtr alloc);
|
||||||
|
SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAllocPtr alloc);
|
||||||
|
void (*Init)(void *p);
|
||||||
|
SRes (*Code2)(void *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||||
|
int srcWasFinished, ECoderFinishMode finishMode,
|
||||||
|
// int *wasFinished,
|
||||||
|
ECoderStatus *status);
|
||||||
|
SizeT (*Filter)(void *p, Byte *data, SizeT size);
|
||||||
|
} IStateCoder;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UInt32 methodId;
|
||||||
|
UInt32 delta;
|
||||||
|
UInt32 ip;
|
||||||
|
UInt32 X86_State;
|
||||||
|
Byte delta_State[DELTA_STATE_SIZE];
|
||||||
|
} CXzBcFilterStateBase;
|
||||||
|
|
||||||
|
typedef SizeT (*Xz_Func_BcFilterStateBase_Filter)(CXzBcFilterStateBase *p, Byte *data, SizeT size);
|
||||||
|
|
||||||
|
SRes Xz_StateCoder_Bc_SetFromMethod_Func(IStateCoder *p, UInt64 id,
|
||||||
|
Xz_Func_BcFilterStateBase_Filter func, ISzAllocPtr alloc);
|
||||||
|
|
||||||
|
|
||||||
|
#define MIXCODER_NUM_FILTERS_MAX 4
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ISzAllocPtr alloc;
|
||||||
|
Byte *buf;
|
||||||
|
unsigned numCoders;
|
||||||
|
|
||||||
|
Byte *outBuf;
|
||||||
|
size_t outBufSize;
|
||||||
|
size_t outWritten; // is equal to lzmaDecoder.dicPos (in outBuf mode)
|
||||||
|
BoolInt wasFinished;
|
||||||
|
SRes res;
|
||||||
|
ECoderStatus status;
|
||||||
|
// BoolInt SingleBufMode;
|
||||||
|
|
||||||
|
int finished[MIXCODER_NUM_FILTERS_MAX - 1];
|
||||||
|
size_t pos[MIXCODER_NUM_FILTERS_MAX - 1];
|
||||||
|
size_t size[MIXCODER_NUM_FILTERS_MAX - 1];
|
||||||
|
UInt64 ids[MIXCODER_NUM_FILTERS_MAX];
|
||||||
|
SRes results[MIXCODER_NUM_FILTERS_MAX];
|
||||||
|
IStateCoder coders[MIXCODER_NUM_FILTERS_MAX];
|
||||||
|
} CMixCoder;
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
XZ_STATE_STREAM_HEADER,
|
||||||
|
XZ_STATE_STREAM_INDEX,
|
||||||
|
XZ_STATE_STREAM_INDEX_CRC,
|
||||||
|
XZ_STATE_STREAM_FOOTER,
|
||||||
|
XZ_STATE_STREAM_PADDING,
|
||||||
|
XZ_STATE_BLOCK_HEADER,
|
||||||
|
XZ_STATE_BLOCK,
|
||||||
|
XZ_STATE_BLOCK_FOOTER
|
||||||
|
} EXzState;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
EXzState state;
|
||||||
|
UInt32 pos;
|
||||||
|
unsigned alignPos;
|
||||||
|
unsigned indexPreSize;
|
||||||
|
|
||||||
|
CXzStreamFlags streamFlags;
|
||||||
|
|
||||||
|
UInt32 blockHeaderSize;
|
||||||
|
UInt64 packSize;
|
||||||
|
UInt64 unpackSize;
|
||||||
|
|
||||||
|
UInt64 numBlocks; // number of finished blocks in current stream
|
||||||
|
UInt64 indexSize;
|
||||||
|
UInt64 indexPos;
|
||||||
|
UInt64 padSize;
|
||||||
|
|
||||||
|
UInt64 numStartedStreams;
|
||||||
|
UInt64 numFinishedStreams;
|
||||||
|
UInt64 numTotalBlocks;
|
||||||
|
|
||||||
|
UInt32 crc;
|
||||||
|
CMixCoder decoder;
|
||||||
|
CXzBlock block;
|
||||||
|
CXzCheck check;
|
||||||
|
CSha256 sha;
|
||||||
|
|
||||||
|
BoolInt parseMode;
|
||||||
|
BoolInt headerParsedOk;
|
||||||
|
BoolInt decodeToStreamSignature;
|
||||||
|
unsigned decodeOnlyOneBlock;
|
||||||
|
|
||||||
|
Byte *outBuf;
|
||||||
|
size_t outBufSize;
|
||||||
|
size_t outDataWritten; // the size of data in (outBuf) that were fully unpacked
|
||||||
|
|
||||||
|
Byte shaDigest[SHA256_DIGEST_SIZE];
|
||||||
|
Byte buf[XZ_BLOCK_HEADER_SIZE_MAX];
|
||||||
|
} CXzUnpacker;
|
||||||
|
|
||||||
|
/* alloc : aligned for cache line allocation is better */
|
||||||
|
void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc);
|
||||||
|
void XzUnpacker_Init(CXzUnpacker *p);
|
||||||
|
void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize);
|
||||||
|
void XzUnpacker_Free(CXzUnpacker *p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
XzUnpacker
|
||||||
|
The sequence for decoding functions:
|
||||||
|
{
|
||||||
|
XzUnpacker_Construct()
|
||||||
|
[Decoding_Calls]
|
||||||
|
XzUnpacker_Free()
|
||||||
|
}
|
||||||
|
|
||||||
|
[Decoding_Calls]
|
||||||
|
|
||||||
|
There are 3 types of interfaces for [Decoding_Calls] calls:
|
||||||
|
|
||||||
|
Interface-1 : Partial output buffers:
|
||||||
|
{
|
||||||
|
XzUnpacker_Init()
|
||||||
|
for()
|
||||||
|
{
|
||||||
|
XzUnpacker_Code();
|
||||||
|
}
|
||||||
|
XzUnpacker_IsStreamWasFinished()
|
||||||
|
}
|
||||||
|
|
||||||
|
Interface-2 : Direct output buffer:
|
||||||
|
Use it, if you know exact size of decoded data, and you need
|
||||||
|
whole xz unpacked data in one output buffer.
|
||||||
|
xz unpacker doesn't allocate additional buffer for lzma2 dictionary in that mode.
|
||||||
|
{
|
||||||
|
XzUnpacker_Init()
|
||||||
|
XzUnpacker_SetOutBufMode(); // to set output buffer and size
|
||||||
|
for()
|
||||||
|
{
|
||||||
|
XzUnpacker_Code(); // (dest = NULL) in XzUnpacker_Code()
|
||||||
|
}
|
||||||
|
XzUnpacker_IsStreamWasFinished()
|
||||||
|
}
|
||||||
|
|
||||||
|
Interface-3 : Direct output buffer : One call full decoding
|
||||||
|
It unpacks whole input buffer to output buffer in one call.
|
||||||
|
It uses Interface-2 internally.
|
||||||
|
{
|
||||||
|
XzUnpacker_CodeFull()
|
||||||
|
XzUnpacker_IsStreamWasFinished()
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
finishMode:
|
||||||
|
It has meaning only if the decoding reaches output limit (*destLen).
|
||||||
|
CODER_FINISH_ANY - use smallest number of input bytes
|
||||||
|
CODER_FINISH_END - read EndOfStream marker after decoding
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
SZ_OK
|
||||||
|
status:
|
||||||
|
CODER_STATUS_NOT_FINISHED,
|
||||||
|
CODER_STATUS_NEEDS_MORE_INPUT - the decoder can return it in two cases:
|
||||||
|
1) it needs more input data to finish current xz stream
|
||||||
|
2) xz stream was finished successfully. But the decoder supports multiple
|
||||||
|
concatented xz streams. So it expects more input data for new xz streams.
|
||||||
|
Call XzUnpacker_IsStreamWasFinished() to check that latest xz stream was finished successfully.
|
||||||
|
|
||||||
|
SZ_ERROR_MEM - Memory allocation error
|
||||||
|
SZ_ERROR_DATA - Data error
|
||||||
|
SZ_ERROR_UNSUPPORTED - Unsupported method or method properties
|
||||||
|
SZ_ERROR_CRC - CRC error
|
||||||
|
// SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
|
||||||
|
|
||||||
|
SZ_ERROR_NO_ARCHIVE - the error with xz Stream Header with one of the following reasons:
|
||||||
|
- xz Stream Signature failure
|
||||||
|
- CRC32 of xz Stream Header is failed
|
||||||
|
- The size of Stream padding is not multiple of four bytes.
|
||||||
|
It's possible to get that error, if xz stream was finished and the stream
|
||||||
|
contains some another data. In that case you can call XzUnpacker_GetExtraSize()
|
||||||
|
function to get real size of xz stream.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
|
||||||
|
const Byte *src, SizeT *srcLen, int srcFinished,
|
||||||
|
ECoderFinishMode finishMode, ECoderStatus *status);
|
||||||
|
|
||||||
|
SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen,
|
||||||
|
const Byte *src, SizeT *srcLen,
|
||||||
|
ECoderFinishMode finishMode, ECoderStatus *status);
|
||||||
|
|
||||||
|
/*
|
||||||
|
If you decode full xz stream(s), then you can call XzUnpacker_IsStreamWasFinished()
|
||||||
|
after successful XzUnpacker_CodeFull() or after last call of XzUnpacker_Code().
|
||||||
|
*/
|
||||||
|
|
||||||
|
BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
XzUnpacker_GetExtraSize() returns then number of unconfirmed bytes,
|
||||||
|
if it's in (XZ_STATE_STREAM_HEADER) state or in (XZ_STATE_STREAM_PADDING) state.
|
||||||
|
These bytes can be some data after xz archive, or
|
||||||
|
it can be start of new xz stream.
|
||||||
|
|
||||||
|
Call XzUnpacker_GetExtraSize() after XzUnpacker_Code() function to detect real size of
|
||||||
|
xz stream in two cases, if XzUnpacker_Code() returns:
|
||||||
|
res == SZ_OK && status == CODER_STATUS_NEEDS_MORE_INPUT
|
||||||
|
res == SZ_ERROR_NO_ARCHIVE
|
||||||
|
*/
|
||||||
|
|
||||||
|
UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
for random block decoding:
|
||||||
|
XzUnpacker_Init();
|
||||||
|
set CXzUnpacker::streamFlags
|
||||||
|
XzUnpacker_PrepareToRandomBlockDecoding()
|
||||||
|
loop
|
||||||
|
{
|
||||||
|
XzUnpacker_Code()
|
||||||
|
XzUnpacker_IsBlockFinished()
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p);
|
||||||
|
BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p);
|
||||||
|
|
||||||
|
#define XzUnpacker_GetPackSizeForIndex(p) ((p)->packSize + (p)->blockHeaderSize + XzFlags_GetCheckSize((p)->streamFlags))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ---- Single-Thread and Multi-Thread xz Decoding with Input/Output Streams ---- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (CXzDecMtProps::numThreads > 1), the decoder can try to use
|
||||||
|
Multi-Threading. The decoder analyses xz block header, and if
|
||||||
|
there are pack size and unpack size values stored in xz block header,
|
||||||
|
the decoder reads compressed data of block to internal buffers,
|
||||||
|
and then it can start parallel decoding, if there are another blocks.
|
||||||
|
The decoder can switch back to Single-Thread decoding after some conditions.
|
||||||
|
|
||||||
|
The sequence of calls for xz decoding with in/out Streams:
|
||||||
|
{
|
||||||
|
XzDecMt_Create()
|
||||||
|
XzDecMtProps_Init(XzDecMtProps) to set default values of properties
|
||||||
|
// then you can change some XzDecMtProps parameters with required values
|
||||||
|
// here you can set the number of threads and (memUseMax) - the maximum
|
||||||
|
Memory usage for multithreading decoding.
|
||||||
|
for()
|
||||||
|
{
|
||||||
|
XzDecMt_Decode() // one call per one file
|
||||||
|
}
|
||||||
|
XzDecMt_Destroy()
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
size_t inBufSize_ST; // size of input buffer for Single-Thread decoding
|
||||||
|
size_t outStep_ST; // size of output buffer for Single-Thread decoding
|
||||||
|
BoolInt ignoreErrors; // if set to 1, the decoder can ignore some errors and it skips broken parts of data.
|
||||||
|
|
||||||
|
#ifndef Z7_ST
|
||||||
|
unsigned numThreads; // the number of threads for Multi-Thread decoding. if (umThreads == 1) it will use Single-thread decoding
|
||||||
|
size_t inBufSize_MT; // size of small input data buffers for Multi-Thread decoding. Big number of such small buffers can be created
|
||||||
|
size_t memUseMax; // the limit of total memory usage for Multi-Thread decoding.
|
||||||
|
// it's recommended to set (memUseMax) manually to value that is smaller of total size of RAM in computer.
|
||||||
|
#endif
|
||||||
|
} CXzDecMtProps;
|
||||||
|
|
||||||
|
void XzDecMtProps_Init(CXzDecMtProps *p);
|
||||||
|
|
||||||
|
typedef struct CXzDecMt CXzDecMt;
|
||||||
|
typedef CXzDecMt * CXzDecMtHandle;
|
||||||
|
// Z7_DECLARE_HANDLE(CXzDecMtHandle)
|
||||||
|
|
||||||
|
/*
|
||||||
|
alloc : XzDecMt uses CAlignOffsetAlloc internally for addresses allocated by (alloc).
|
||||||
|
allocMid : for big allocations, aligned allocation is better
|
||||||
|
*/
|
||||||
|
|
||||||
|
CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid);
|
||||||
|
void XzDecMt_Destroy(CXzDecMtHandle p);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Byte UnpackSize_Defined;
|
||||||
|
Byte NumStreams_Defined;
|
||||||
|
Byte NumBlocks_Defined;
|
||||||
|
|
||||||
|
Byte DataAfterEnd; // there are some additional data after good xz streams, and that data is not new xz stream.
|
||||||
|
Byte DecodingTruncated; // Decoding was Truncated, we need only partial output data
|
||||||
|
|
||||||
|
UInt64 InSize; // pack size processed. That value doesn't include the data after
|
||||||
|
// end of xz stream, if that data was not correct
|
||||||
|
UInt64 OutSize;
|
||||||
|
|
||||||
|
UInt64 NumStreams;
|
||||||
|
UInt64 NumBlocks;
|
||||||
|
|
||||||
|
SRes DecodeRes; // the error code of xz streams data decoding
|
||||||
|
SRes ReadRes; // error code from ISeqInStream:Read()
|
||||||
|
SRes ProgressRes; // error code from ICompressProgress:Progress()
|
||||||
|
|
||||||
|
SRes CombinedRes; // Combined result error code that shows main rusult
|
||||||
|
// = S_OK, if there is no error.
|
||||||
|
// but check also (DataAfterEnd) that can show additional minor errors.
|
||||||
|
|
||||||
|
SRes CombinedRes_Type; // = SZ_ERROR_READ, if error from ISeqInStream
|
||||||
|
// = SZ_ERROR_PROGRESS, if error from ICompressProgress
|
||||||
|
// = SZ_ERROR_WRITE, if error from ISeqOutStream
|
||||||
|
// = SZ_ERROR_* codes for decoding
|
||||||
|
} CXzStatInfo;
|
||||||
|
|
||||||
|
void XzStatInfo_Clear(CXzStatInfo *p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
XzDecMt_Decode()
|
||||||
|
SRes: it's combined decoding result. It also is equal to stat->CombinedRes.
|
||||||
|
|
||||||
|
SZ_OK - no error
|
||||||
|
check also output value in (stat->DataAfterEnd)
|
||||||
|
that can show additional possible error
|
||||||
|
|
||||||
|
SZ_ERROR_MEM - Memory allocation error
|
||||||
|
SZ_ERROR_NO_ARCHIVE - is not xz archive
|
||||||
|
SZ_ERROR_ARCHIVE - Headers error
|
||||||
|
SZ_ERROR_DATA - Data Error
|
||||||
|
SZ_ERROR_UNSUPPORTED - Unsupported method or method properties
|
||||||
|
SZ_ERROR_CRC - CRC Error
|
||||||
|
SZ_ERROR_INPUT_EOF - it needs more input data
|
||||||
|
SZ_ERROR_WRITE - ISeqOutStream error
|
||||||
|
(SZ_ERROR_READ) - ISeqInStream errors
|
||||||
|
(SZ_ERROR_PROGRESS) - ICompressProgress errors
|
||||||
|
// SZ_ERROR_THREAD - error in multi-threading functions
|
||||||
|
MY_SRes_HRESULT_FROM_WRes(WRes_error) - error in multi-threading function
|
||||||
|
*/
|
||||||
|
|
||||||
|
SRes XzDecMt_Decode(CXzDecMtHandle p,
|
||||||
|
const CXzDecMtProps *props,
|
||||||
|
const UInt64 *outDataSize, // NULL means undefined
|
||||||
|
int finishMode, // 0 - partial unpacking is allowed, 1 - xz stream(s) must be finished
|
||||||
|
ISeqOutStreamPtr outStream,
|
||||||
|
// Byte *outBuf, size_t *outBufSize,
|
||||||
|
ISeqInStreamPtr inStream,
|
||||||
|
// const Byte *inData, size_t inDataSize,
|
||||||
|
CXzStatInfo *stat, // out: decoding results and statistics
|
||||||
|
int *isMT, // out: 0 means that ST (Single-Thread) version was used
|
||||||
|
// 1 means that MT (Multi-Thread) version was used
|
||||||
|
ICompressProgressPtr progress);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/* XzCrc64.h -- CRC64 calculation
|
||||||
|
2023-04-02 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_XZ_CRC64_H
|
||||||
|
#define ZIP7_INC_XZ_CRC64_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "7zTypes.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
extern UInt64 g_Crc64Table[];
|
||||||
|
|
||||||
|
void Z7_FASTCALL Crc64GenerateTable(void);
|
||||||
|
|
||||||
|
#define CRC64_INIT_VAL UINT64_CONST(0xFFFFFFFFFFFFFFFF)
|
||||||
|
#define CRC64_GET_DIGEST(crc) ((crc) ^ CRC64_INIT_VAL)
|
||||||
|
#define CRC64_UPDATE_BYTE(crc, b) (g_Crc64Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||||
|
|
||||||
|
UInt64 Z7_FASTCALL Crc64Update(UInt64 crc, const void *data, size_t size);
|
||||||
|
UInt64 Z7_FASTCALL Crc64Calc(const void *data, size_t size);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/* XzEnc.h -- Xz Encode
|
||||||
|
2023-04-13 : Igor Pavlov : Public domain */
|
||||||
|
|
||||||
|
#ifndef ZIP7_INC_XZ_ENC_H
|
||||||
|
#define ZIP7_INC_XZ_ENC_H
|
||||||
|
|
||||||
|
#include "Lzma2Enc.h"
|
||||||
|
|
||||||
|
#include "Xz.h"
|
||||||
|
|
||||||
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
|
|
||||||
|
#define XZ_PROPS_BLOCK_SIZE_AUTO LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO
|
||||||
|
#define XZ_PROPS_BLOCK_SIZE_SOLID LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UInt32 id;
|
||||||
|
UInt32 delta;
|
||||||
|
UInt32 ip;
|
||||||
|
int ipDefined;
|
||||||
|
} CXzFilterProps;
|
||||||
|
|
||||||
|
void XzFilterProps_Init(CXzFilterProps *p);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
CLzma2EncProps lzma2Props;
|
||||||
|
CXzFilterProps filterProps;
|
||||||
|
unsigned checkId;
|
||||||
|
UInt64 blockSize;
|
||||||
|
int numBlockThreads_Reduced;
|
||||||
|
int numBlockThreads_Max;
|
||||||
|
int numTotalThreads;
|
||||||
|
int forceWriteSizesInHeader;
|
||||||
|
UInt64 reduceSize;
|
||||||
|
} CXzProps;
|
||||||
|
|
||||||
|
void XzProps_Init(CXzProps *p);
|
||||||
|
|
||||||
|
typedef struct CXzEnc CXzEnc;
|
||||||
|
typedef CXzEnc * CXzEncHandle;
|
||||||
|
// Z7_DECLARE_HANDLE(CXzEncHandle)
|
||||||
|
|
||||||
|
CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig);
|
||||||
|
void XzEnc_Destroy(CXzEncHandle p);
|
||||||
|
SRes XzEnc_SetProps(CXzEncHandle p, const CXzProps *props);
|
||||||
|
void XzEnc_SetDataSize(CXzEncHandle p, UInt64 expectedDataSiize);
|
||||||
|
SRes XzEnc_Encode(CXzEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, ICompressProgressPtr progress);
|
||||||
|
|
||||||
|
SRes Xz_Encode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream,
|
||||||
|
const CXzProps *props, ICompressProgressPtr progress);
|
||||||
|
|
||||||
|
SRes Xz_EncodeEmpty(ISeqOutStreamPtr outStream);
|
||||||
|
|
||||||
|
EXTERN_C_END
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user