mirror of
https://github.com/LisherSong/ps5-web-file-manager.git
synced 2026-10-06 07:00:28 +02:00
feat(7z): vendor LZMA SDK and add the 7z fixture/verification harness
Groundwork for 7z support (the second of the six format x volume
combinations). No engine code yet: this lands the vendor subset, real
fixtures and the end-to-end driver, so the engine has something to be
built and checked against.
Vendor (third_party/7z, LZMA SDK 26.03, public domain):
- decoder-only subset: 7zArcIn/7zDec container, Lzma/Lzma2/Ppmd7/Bcj2/
Bra/Delta codecs, Aes/Sha256 for the password channel to come
- the encoder half (LzmaEnc, Xz*, Sort, Threads, ...) is deliberately
not vendored; the engine never encodes
- README.md records two SDK limitations that shape the engine design:
* CSzFolder caps a folder at 4 coders / 3 bonds, so 7-Zip's own BCJ2
chain (BCJ2 + 4xLZMA2 = 5 coders) is refused by SzAr_DecodeFolder
even though SzArEx_Open parses it happily - the engine therefore
parses folder blobs and drives the codec chain itself
* the C decoder ships no 7zAES coder at all, so both -p and -mhe=on
archives are rejected until the engine implements it on top of the
vendored Aes.c / Sha256.c
Tests:
- make_sevenz_fixtures.py builds real archives with an actual 7-Zip
binary (7za from the Extra package; falls back to the reduced 7zr,
which has no PPMd encoder): store/lzma/lzma2/ppmd/bcj/delta/bcj2,
AES with plain and with encrypted headers, a 7-part -v100k volume
set, and UTF-8 entry names
- sevenz_e2e.c extracts an archive and validates every entry against
the stored CRC; it calls the wide-character file APIs on Windows, so
non-ASCII entry names are really created instead of silently failing
- run-sevenz-tests.sh builds the subset and the driver, then runs the
fixture matrix with an explicit KNOWN_GAPS list that fails loudly
when one of the gaps starts passing
Status: store, lzma, lzma2, ppmd, bcj, delta and utf8 all extract
byte-identical to the source tree (7/10). bcj2, aes, aeshe and
vol.7z.001 are the known gaps, each mapped to a specific piece of
engine work still to come.
This commit is contained in:
1 parent
da565ccb7c
commit
8bee84bd49
60 files changed
+19470
-2
No files matched your search
@@ -17,6 +17,14 @@ web-file-mgr-linux
|
||||
.build/*.c
|
||||
.build/test-out.txt
|
||||
|
||||
# 7z work area: downloaded SDK + 7-Zip binaries and local build output.
|
||||
.build/7zdl/
|
||||
.build/7zh/
|
||||
.build/sevenz-test/
|
||||
|
||||
# Generated 7z fixtures (tests/make_sevenz_fixtures.py rebuilds them).
|
||||
tests/fixtures-7z/
|
||||
|
||||
# Editor / OS noise
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
+18
-2
@@ -2,7 +2,7 @@ Third-Party Notices
|
||||
===================
|
||||
|
||||
This project vendors a minimal set of third-party source files under
|
||||
`third_party/` to provide the ZIP and RAR extraction features (the
|
||||
`third_party/` to provide the ZIP, RAR and 7z extraction features (the
|
||||
`/api/extract` endpoint). Their full license texts are included
|
||||
alongside the sources.
|
||||
|
||||
@@ -32,6 +32,21 @@ alongside the sources.
|
||||
relaxed warnings; unrar_c_api.h is project-authored and
|
||||
carries the project's license)
|
||||
|
||||
4. LZMA SDK (7z decoder)
|
||||
----------------------
|
||||
Version : 26.03 (2026-09-03)
|
||||
Source : https://www.7-zip.org/sdk.html — release `lzma2603.7z` from
|
||||
https://github.com/ip7z/7zip/releases
|
||||
License : Public domain ("LZMA SDK is written and placed in the public
|
||||
domain by Igor Pavlov", see third_party/7z/DOC/lzma-sdk.txt)
|
||||
Files : third_party/7z/** (decoder-only subset, compiled with relaxed
|
||||
warnings; see third_party/7z/README.md for the file list)
|
||||
|
||||
The LZMA SDK is the engine behind `src/sevenz_extract.c` (the v1.9.x 7z
|
||||
support: LZMA/LZMA2/PPMd/Copy plus the BCJ, BCJ2 and Delta filters). Only the
|
||||
C implementation is used — it builds with the plain PS5 C toolchain and does
|
||||
not pull in the C++ runtime. The encoder half of the SDK is not vendored.
|
||||
|
||||
unrar is the engine behind `src/rar_extract.c` (the v1.9 RAR support: RAR4,
|
||||
RAR5 including WinRAR 6/7 "v6" compression, and multi-volume archives; the
|
||||
engine can also decrypt via RARSetPassword once a password channel is wired
|
||||
@@ -46,5 +61,6 @@ replaced by the rarlab UnRAR source in v1.9; see git history under
|
||||
Libraries in sections 1 and 2 are distributed under the zlib license, which
|
||||
permits redistribution in source and binary form provided the copyright
|
||||
notice and this list of conditions are retained. unrar is distributed under
|
||||
its own freeware terms. See the individual LICENSE / license.txt files in
|
||||
its own freeware terms. The LZMA SDK (section 4) is in the public domain and
|
||||
carries no conditions. See the individual LICENSE / license.txt files in
|
||||
each `third_party/` subdirectory for the complete terms.
|
||||
@@ -0,0 +1,253 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate real .7z fixtures for the host test suite.
|
||||
|
||||
The fixtures are produced by an actual 7-Zip binary so that the archives the
|
||||
engine has to read are genuine, not hand-rolled. The tool is looked up in this
|
||||
order:
|
||||
|
||||
1. ``--tool <path>``
|
||||
2. ``$SEVENZ_TOOL``
|
||||
3. the full ``7za.exe`` from the "7-Zip Extra" package under ``.build/7zdl/``
|
||||
4. the reduced ``7zr.exe`` under ``.build/7zdl/``
|
||||
5. ``7z`` / ``7zr`` / ``7za`` on PATH
|
||||
|
||||
Both binaries come from https://github.com/ip7z/7zip/releases (7-Zip is public
|
||||
domain). The reduced ``7zr.exe`` has **no PPMd encoder**, so that fixture is
|
||||
skipped (with a warning) unless a full build is available.
|
||||
|
||||
Output goes to ``tests/fixtures-7z/``. Only files this script owns are removed
|
||||
on a re-run (identified by an ``OWN_`` prefix list), never the whole directory.
|
||||
|
||||
python tests/make_sevenz_fixtures.py [--big]
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import random
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
ROOT = os.path.dirname(HERE)
|
||||
OUT = os.path.join(HERE, "fixtures-7z")
|
||||
SRC = os.path.join(OUT, "_src")
|
||||
|
||||
# Everything this script may delete on a re-run.
|
||||
OWN_PREFIXES = (
|
||||
"store", "lzma", "lzma2", "ppmd", "bcj", "delta", "aes", "vol", "utf8",
|
||||
"big", "empty", "_src",
|
||||
)
|
||||
|
||||
PASSWORD = "Secret123"
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# tool discovery / process helpers
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
def find_tool(explicit: str | None) -> str:
|
||||
if explicit:
|
||||
if os.path.exists(explicit):
|
||||
return explicit
|
||||
raise SystemExit(f"7z tool not found: {explicit}")
|
||||
|
||||
env = os.environ.get("SEVENZ_TOOL")
|
||||
if env and os.path.exists(env):
|
||||
return env
|
||||
|
||||
# Prefer the full 7za.exe (has PPMd); fall back to the reduced 7zr.exe.
|
||||
for rel in ("7zdl/extra/x64/7za.exe", "7zdl/extra/7za.exe", "7zdl/7zr.exe"):
|
||||
local = os.path.join(ROOT, ".build", rel.replace("/", os.sep))
|
||||
if os.path.exists(local):
|
||||
return local
|
||||
|
||||
for name in ("7z", "7zr", "7za"):
|
||||
found = shutil.which(name)
|
||||
if found:
|
||||
return found
|
||||
|
||||
raise SystemExit(
|
||||
"no 7z tool found; pass --tool, set SEVENZ_TOOL, or drop 7zr.exe into "
|
||||
".build/7zdl/"
|
||||
)
|
||||
|
||||
|
||||
def run(tool: str, args: list[str], optional: bool = False) -> bool:
|
||||
"""Run the 7z tool. Returns True on success; raises unless ``optional``."""
|
||||
proc = subprocess.run(
|
||||
[tool] + args, cwd=ROOT, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
|
||||
)
|
||||
if proc.returncode == 0:
|
||||
return True
|
||||
out = proc.stdout.decode("utf-8", "replace")
|
||||
# 7-Zip writes its diagnostics in the OEM code page; try the common ones.
|
||||
for enc in ("gbk", "cp936", "utf-8"):
|
||||
try:
|
||||
out = proc.stdout.decode(enc)
|
||||
break
|
||||
except UnicodeDecodeError:
|
||||
continue
|
||||
if optional:
|
||||
print(f" !! skipped: {' '.join(args[:4])}\n {out.strip()[-200:]}")
|
||||
return False
|
||||
raise SystemExit(
|
||||
f"7z failed ({proc.returncode}): {tool} {' '.join(args)}\n{out}"
|
||||
)
|
||||
|
||||
|
||||
def win(path: str) -> str:
|
||||
"""7zr.exe is a native Windows binary: hand it a Windows path."""
|
||||
return path.replace("/", "\\")
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# source tree
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
def x86ish(size: int) -> bytes:
|
||||
"""Bytes that look like x86 code so BCJ/BCJ2 filters are actually useful."""
|
||||
out = bytearray()
|
||||
rnd = random.Random(1234)
|
||||
while len(out) < size:
|
||||
op = rnd.choice((0xE8, 0xE9, 0xE8, 0xE9, 0x0F, 0x8B, 0xC3, 0x90))
|
||||
out.append(op)
|
||||
if op in (0xE8, 0xE9):
|
||||
out += rnd.randrange(0, 1 << 24).to_bytes(4, "little")
|
||||
elif op == 0x0F:
|
||||
out.append(0x8B)
|
||||
else:
|
||||
out += bytes(rnd.randrange(256) for _ in range(rnd.randrange(1, 6)))
|
||||
return bytes(out[:size])
|
||||
|
||||
|
||||
def build_source(sizes: dict[str, int]) -> None:
|
||||
os.makedirs(os.path.join(SRC, "sub"), exist_ok=True)
|
||||
rnd = random.Random(7)
|
||||
|
||||
with open(os.path.join(SRC, "readme.txt"), "wb") as fh:
|
||||
fh.write(b"sevenz fixture\n" * 20)
|
||||
|
||||
with open(os.path.join(SRC, "binary.bin"), "wb") as fh:
|
||||
fh.write(bytes(rnd.randrange(256) for _ in range(sizes["binary"])))
|
||||
|
||||
# Highly compressible: exercises the LZMA/LZMA2/PPMd long-range paths.
|
||||
with open(os.path.join(SRC, "zeros.bin"), "wb") as fh:
|
||||
fh.write(b"\0" * sizes["zeros"])
|
||||
|
||||
with open(os.path.join(SRC, "sub", "nested.txt"), "wb") as fh:
|
||||
fh.write(b"nested entry\n" * 100)
|
||||
|
||||
with open(os.path.join(SRC, "sub", "code.bin"), "wb") as fh:
|
||||
fh.write(x86ish(sizes["code"]))
|
||||
|
||||
# Non-ASCII names must survive the UTF-16 name table round trip.
|
||||
with open(os.path.join(SRC, "sub", "\u4e2d\u6587-\u30c6\u30b9\u30c8.txt"), "wb") as fh:
|
||||
fh.write("unicode name\n".encode("utf-8") * 30)
|
||||
|
||||
|
||||
def write_big_file(path: str, size: int) -> None:
|
||||
"""A large, semi-compressible file: forces multi-chunk streaming decode."""
|
||||
rnd = random.Random(99)
|
||||
block = bytes(rnd.randrange(256) for _ in range(64 * 1024))
|
||||
with open(path, "wb") as fh:
|
||||
written = 0
|
||||
while written < size:
|
||||
n = min(len(block), size - written)
|
||||
fh.write(block[:n])
|
||||
written += n
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# archives
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
# name -> (extra 7z arguments, takes password, required)
|
||||
VARIANTS: list[tuple[str, list[str], bool, bool]] = [
|
||||
("store", ["-mx0"], False, True),
|
||||
("lzma2", ["-m0=lzma2", "-mx5"], False, True),
|
||||
("lzma", ["-m0=lzma"], False, True),
|
||||
# The reduced 7zr.exe has no PPMd encoder, so this one is best-effort.
|
||||
("ppmd", ["-m0=ppmd"], False, False),
|
||||
("bcj", ["-m0=bcj", "-m1=lzma2"], False, True),
|
||||
("delta", ["-m0=delta:4", "-m1=lzma2"], False, True),
|
||||
("bcj2", ["-m0=bcj2", "-m1=lzma2", "-m2=lzma2", "-m3=lzma2", "-m4=lzma2"], False, True),
|
||||
("aes", ["-m0=lzma2", "-mx5"], True, True),
|
||||
("utf8", ["-m0=lzma2", "-mx5"], False, True),
|
||||
]
|
||||
|
||||
|
||||
def build_archives(tool: str, big: bool) -> None:
|
||||
for name, extra, secret, required in VARIANTS:
|
||||
arch = os.path.join(OUT, f"{name}.7z")
|
||||
if os.path.exists(arch):
|
||||
os.remove(arch)
|
||||
args = ["a", "-t7z", win(arch), win(SRC), "-y"] + extra
|
||||
if secret:
|
||||
args.append(f"-p{PASSWORD}")
|
||||
if name == "aes":
|
||||
# Header stays readable: only the streams are encrypted.
|
||||
args.append("-mhe=off")
|
||||
run(tool, args, optional=not required)
|
||||
|
||||
# Encrypted header (-mhe=on): the archive cannot even be listed without
|
||||
# the password, so the engine must ask for it up front.
|
||||
run(tool, ["a", "-t7z", win(os.path.join(OUT, "aeshe.7z")), win(SRC),
|
||||
"-y", "-m0=lzma2", "-mx5", f"-p{PASSWORD}", "-mhe=on"])
|
||||
|
||||
# Multi-volume (-v): 100 KiB parts force the fixture across several files.
|
||||
vols = os.path.join(OUT, "vol.7z")
|
||||
for stale in sorted(os.listdir(OUT)):
|
||||
if stale.startswith("vol.7z"):
|
||||
os.remove(os.path.join(OUT, stale))
|
||||
run(tool, ["a", "-t7z", win(vols), win(SRC), "-y", "-m0=lzma2", "-mx5",
|
||||
"-v100k"])
|
||||
|
||||
if big:
|
||||
bigsrc = os.path.join(OUT, "_big")
|
||||
os.makedirs(bigsrc, exist_ok=True)
|
||||
write_big_file(os.path.join(bigsrc, "big.bin"), 96 * 1024 * 1024)
|
||||
run(tool, ["a", "-t7z", win(os.path.join(OUT, "big.7z")), win(bigsrc),
|
||||
"-y", "-m0=lzma2", "-mx1"])
|
||||
shutil.rmtree(bigsrc, ignore_errors=True)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
def clean() -> None:
|
||||
os.makedirs(OUT, exist_ok=True)
|
||||
for entry in os.listdir(OUT):
|
||||
if entry.startswith(OWN_PREFIXES):
|
||||
path = os.path.join(OUT, entry)
|
||||
if os.path.isdir(path):
|
||||
shutil.rmtree(path, ignore_errors=True)
|
||||
else:
|
||||
os.remove(path)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--tool", help="path to 7zr.exe / 7z.exe / 7zr")
|
||||
ap.add_argument("--big", action="store_true",
|
||||
help="also build a ~96 MiB single-file archive")
|
||||
opts = ap.parse_args()
|
||||
|
||||
tool = find_tool(opts.tool)
|
||||
print(f"7z tool: {tool}")
|
||||
|
||||
clean()
|
||||
build_source({"binary": 300_000, "zeros": 2_000_000, "code": 400_000})
|
||||
build_archives(tool, opts.big)
|
||||
|
||||
print(f"fixtures written to {OUT}")
|
||||
for name in sorted(os.listdir(OUT)):
|
||||
path = os.path.join(OUT, name)
|
||||
if os.path.isfile(path):
|
||||
print(f" {name} ({os.path.getsize(path)} bytes)")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env bash
|
||||
# Host test runner for the 7z engine (vendor subset + fixture matrix).
|
||||
#
|
||||
# ./tests/run-sevenz-tests.sh
|
||||
#
|
||||
# Builds the vendored LZMA SDK subset and the end-to-end driver, generates real
|
||||
# .7z fixtures with a 7-Zip binary, extracts every fixture and compares the
|
||||
# result byte for byte against the source tree.
|
||||
#
|
||||
# On Windows this expects MinGW gcc in PATH and must be started with the MSYS
|
||||
# bash explicitly (`/usr/bin/bash tests/run-sevenz-tests.sh`) -- a bare `bash`
|
||||
# can resolve to C:\Windows\System32\bash.exe, i.e. the WSL launcher.
|
||||
|
||||
set -e
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd -W 2>/dev/null || pwd)"
|
||||
BUILD="$ROOT/.build/sevenz-test"
|
||||
SEVENZ_DIR="$ROOT/third_party/7z"
|
||||
FIXTURES="$ROOT/tests/fixtures-7z"
|
||||
PYTHON="${PYTHON:-python3}"
|
||||
CC="${CC:-gcc}"
|
||||
|
||||
# Archives that the current engine cannot read yet. Each entry needs a reason;
|
||||
# when one of them starts passing the script says so, so the list cannot rot.
|
||||
KNOWN_GAPS="bcj2 aes aeshe vol.7z.001"
|
||||
# bcj2 - folder has 5 coders; needs the engine's own chain driver
|
||||
# aes - 7zAES coder not implemented yet
|
||||
# aeshe - encrypted header (-mhe=on), same coder
|
||||
# vol.7z.001 - multi-volume input; needs the volume-set stream
|
||||
|
||||
find "$BUILD" -maxdepth 1 -type f \( -name '*.o' -o -name '*.exe' \) -delete 2>/dev/null || true
|
||||
mkdir -p "$BUILD"
|
||||
|
||||
# ---------------------------------------------------------------- vendor
|
||||
CFLAGS_7Z=(-O2 -w -DZ7_PPMD_SUPPORT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
-DNDEBUG -D_REENTRANT)
|
||||
|
||||
for src in "$SEVENZ_DIR"/*.c; do
|
||||
name="$(basename "$src" .c)"
|
||||
"$CC" -c "${CFLAGS_7Z[@]}" -o "$BUILD/$name.o" "$src"
|
||||
done
|
||||
|
||||
# unrar-style extra libs are only needed by the Windows path of 7zFile.c.
|
||||
EXTRA_LIBS=()
|
||||
case "$(uname -s)" in
|
||||
MINGW*|MSYS*|CYGWIN*) EXTRA_LIBS=(-lole32 -loleaut32 -luuid -ladvapi32 -luser32 -lshell32) ;;
|
||||
esac
|
||||
|
||||
"$CC" -O2 -w -I"$SEVENZ_DIR" -o "$BUILD/sevenz_e2e" \
|
||||
"$ROOT/tests/sevenz_e2e.c" "$BUILD"/*.o "${EXTRA_LIBS[@]}"
|
||||
|
||||
# ---------------------------------------------------------------- fixtures
|
||||
if [ ! -f "$FIXTURES/lzma2.7z" ]; then
|
||||
echo "== generating 7z fixtures =="
|
||||
if ! "$PYTHON" "$ROOT/tests/make_sevenz_fixtures.py"; then
|
||||
echo "SKIP: no 7z tool available, cannot build fixtures" >&2
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------- matrix
|
||||
pass=0
|
||||
fail=0
|
||||
|
||||
is_gap() {
|
||||
for g in $KNOWN_GAPS; do
|
||||
[ "$g" = "$1" ] && return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
run_case() {
|
||||
local name="$1" archive="$2"
|
||||
local out="$BUILD/out/$name"
|
||||
local log="$BUILD/out/$name.log"
|
||||
|
||||
rm -rf "$out"
|
||||
mkdir -p "$out"
|
||||
|
||||
if "$BUILD/sevenz_e2e" "$archive" "$out" >"$log" 2>&1 &&
|
||||
diff -r "$FIXTURES/_src" "$out/_src" >/dev/null 2>&1; then
|
||||
if is_gap "$name"; then
|
||||
printf ' %-12s GAP CLOSED (remove from KNOWN_GAPS)\n' "$name"
|
||||
fail=$((fail + 1))
|
||||
else
|
||||
printf ' %-12s ok\n' "$name"
|
||||
pass=$((pass + 1))
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
if is_gap "$name"; then
|
||||
printf ' %-12s known gap (%s)\n' "$name" "$(head -1 "$log")"
|
||||
pass=$((pass + 1))
|
||||
else
|
||||
printf ' %-12s FAIL\n' "$name"
|
||||
sed -n '1,20p' "$log" | sed 's/^/ /'
|
||||
fail=$((fail + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
echo "== 7z fixture matrix =="
|
||||
for a in store lzma2 lzma ppmd bcj delta utf8 bcj2 aes aeshe; do
|
||||
[ -f "$FIXTURES/$a.7z" ] || continue
|
||||
run_case "$a" "$FIXTURES/$a.7z"
|
||||
done
|
||||
if [ -f "$FIXTURES/vol.7z.001" ]; then
|
||||
run_case "vol.7z.001" "$FIXTURES/vol.7z.001"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "$pass passed, $fail failed"
|
||||
[ "$fail" -eq 0 ]
|
||||
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Standalone 7z driver for host end-to-end checks.
|
||||
*
|
||||
* sevenz_e2e <archive.7z> <out-dir>
|
||||
*
|
||||
* Lists every entry, extracts the archive into <out-dir> and prints the
|
||||
* per-entry result. Exit status is non-zero if any entry fails.
|
||||
*
|
||||
* This is a *diagnostic* tool: it exercises the same container layer as the
|
||||
* real extraction path, so it is the quickest way to tell whether a failure
|
||||
* comes from the container/codec layer or from the web server around it.
|
||||
*
|
||||
* Entry names are UTF-16 inside a 7z archive; on a Windows host the file APIs
|
||||
* must therefore be called with the wide-character variants or non-ASCII names
|
||||
* silently fail to be created.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <direct.h>
|
||||
#include <wchar.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "7z.h"
|
||||
#include "7zAlloc.h"
|
||||
#include "7zCrc.h"
|
||||
#include "7zFile.h"
|
||||
|
||||
#define INPUT_BUF_SIZE (1u << 18)
|
||||
#define MAX_PATH_LEN 4096
|
||||
|
||||
static ISzAlloc g_alloc = { SzAlloc, SzFree };
|
||||
static ISzAlloc g_temp = { SzAlloc, SzFree };
|
||||
|
||||
static int g_failures = 0;
|
||||
|
||||
/* ---------------------------------------------------------------- paths */
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
/* MinGW's wchar_t is 16 bit, matching UTF-16. */
|
||||
static void utf8_to_utf16(const char *src, wchar_t *dst, size_t cap)
|
||||
{
|
||||
size_t out = 0;
|
||||
|
||||
while (*src && out + 2 < cap) {
|
||||
unsigned char c = (unsigned char)*src++;
|
||||
UInt32 cp;
|
||||
|
||||
if (c < 0x80) {
|
||||
cp = c;
|
||||
} else if ((c & 0xE0) == 0xC0 && (src[0] & 0xC0) == 0x80) {
|
||||
cp = ((UInt32)(c & 0x1F) << 6) | (UInt32)(*src++ & 0x3F);
|
||||
} else if ((c & 0xF0) == 0xE0 && (src[0] & 0xC0) == 0x80 && (src[1] & 0xC0) == 0x80) {
|
||||
cp = ((UInt32)(c & 0x0F) << 12) | ((UInt32)(src[0] & 0x3F) << 6) | (UInt32)(src[1] & 0x3F);
|
||||
src += 2;
|
||||
} else if ((c & 0xF8) == 0xF0 && (src[0] & 0xC0) == 0x80 && (src[1] & 0xC0) == 0x80 && (src[2] & 0xC0) == 0x80) {
|
||||
cp = ((UInt32)(c & 0x07) << 18) | ((UInt32)(src[0] & 0x3F) << 12) |
|
||||
((UInt32)(src[1] & 0x3F) << 6) | (UInt32)(src[2] & 0x3F);
|
||||
src += 3;
|
||||
} else {
|
||||
cp = '?';
|
||||
}
|
||||
|
||||
if (cp >= 0x10000) {
|
||||
cp -= 0x10000;
|
||||
dst[out++] = (wchar_t)(0xD800 | (cp >> 10));
|
||||
dst[out++] = (wchar_t)(0xDC00 | (cp & 0x3FF));
|
||||
} else {
|
||||
dst[out++] = (wchar_t)cp;
|
||||
}
|
||||
}
|
||||
dst[out] = 0;
|
||||
}
|
||||
|
||||
static void path_mkdir(const char *path)
|
||||
{
|
||||
wchar_t wide[MAX_PATH_LEN];
|
||||
utf8_to_utf16(path, wide, MAX_PATH_LEN);
|
||||
_wmkdir(wide);
|
||||
}
|
||||
|
||||
static FILE *path_fopen_write(const char *path)
|
||||
{
|
||||
wchar_t wide[MAX_PATH_LEN];
|
||||
utf8_to_utf16(path, wide, MAX_PATH_LEN);
|
||||
return _wfopen(wide, L"wb");
|
||||
}
|
||||
|
||||
#else /* POSIX: byte paths are UTF-8 already */
|
||||
|
||||
static void path_mkdir(const char *path) { mkdir(path, 0755); }
|
||||
static FILE *path_fopen_write(const char *path) { return fopen(path, "wb"); }
|
||||
|
||||
#endif
|
||||
|
||||
static void make_dirs(const char *path)
|
||||
{
|
||||
char tmp[MAX_PATH_LEN];
|
||||
size_t i, n = strlen(path);
|
||||
|
||||
if (n + 1 > sizeof(tmp))
|
||||
return;
|
||||
memcpy(tmp, path, n + 1);
|
||||
|
||||
for (i = 1; i < n; i++) {
|
||||
if (tmp[i] == '/' || tmp[i] == '\\') {
|
||||
char c = tmp[i];
|
||||
tmp[i] = 0;
|
||||
path_mkdir(tmp);
|
||||
tmp[i] = c;
|
||||
}
|
||||
}
|
||||
/* The final component counts too: callers hand us either a directory entry
|
||||
or the parent directory of a file. */
|
||||
path_mkdir(tmp);
|
||||
}
|
||||
|
||||
static int write_file(const char *path, const Byte *data, size_t size)
|
||||
{
|
||||
FILE *fh = path_fopen_write(path);
|
||||
if (!fh)
|
||||
return -1;
|
||||
if (size && fwrite(data, 1, size, fh) != size) {
|
||||
fclose(fh);
|
||||
return -1;
|
||||
}
|
||||
return fclose(fh) == 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
/* UTF-16 (LE, as stored by the 7z name table) to UTF-8. */
|
||||
static void utf16_to_utf8(const UInt16 *src, char *dst, size_t dst_size)
|
||||
{
|
||||
size_t out = 0;
|
||||
|
||||
while (*src) {
|
||||
UInt32 c = *src++;
|
||||
|
||||
if (c >= 0xD800 && c <= 0xDBFF && *src >= 0xDC00 && *src <= 0xDFFF)
|
||||
c = 0x10000 + ((c - 0xD800) << 10) + (*src++ - 0xDC00);
|
||||
|
||||
if (out + 5 >= dst_size)
|
||||
break;
|
||||
|
||||
if (c < 0x80) {
|
||||
dst[out++] = (char)c;
|
||||
} else if (c < 0x800) {
|
||||
dst[out++] = (char)(0xC0 | (c >> 6));
|
||||
dst[out++] = (char)(0x80 | (c & 0x3F));
|
||||
} else if (c < 0x10000) {
|
||||
dst[out++] = (char)(0xE0 | (c >> 12));
|
||||
dst[out++] = (char)(0x80 | ((c >> 6) & 0x3F));
|
||||
dst[out++] = (char)(0x80 | (c & 0x3F));
|
||||
} else {
|
||||
dst[out++] = (char)(0xF0 | (c >> 18));
|
||||
dst[out++] = (char)(0x80 | ((c >> 12) & 0x3F));
|
||||
dst[out++] = (char)(0x80 | ((c >> 6) & 0x3F));
|
||||
dst[out++] = (char)(0x80 | (c & 0x3F));
|
||||
}
|
||||
}
|
||||
dst[out] = 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- main */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CFileInStream archive_stream;
|
||||
CLookToRead2 look_stream;
|
||||
CSzArEx db;
|
||||
SRes res;
|
||||
UInt16 *name16 = NULL;
|
||||
size_t name16_cap = 0;
|
||||
UInt32 i;
|
||||
UInt32 block_index = 0xFFFFFFFF;
|
||||
Byte *out_buffer = NULL;
|
||||
size_t out_buffer_size = 0;
|
||||
const char *out_dir;
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "usage: %s <archive.7z> <out-dir>\n", argv[0]);
|
||||
return 2;
|
||||
}
|
||||
out_dir = argv[2];
|
||||
|
||||
if (InFile_Open(&archive_stream.file, argv[1]) != 0) {
|
||||
fprintf(stderr, "cannot open %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
FileInStream_CreateVTable(&archive_stream);
|
||||
archive_stream.wres = 0;
|
||||
|
||||
LookToRead2_CreateVTable(&look_stream, 0);
|
||||
look_stream.buf = (Byte *)ISzAlloc_Alloc(&g_alloc, INPUT_BUF_SIZE);
|
||||
if (!look_stream.buf) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
return 1;
|
||||
}
|
||||
look_stream.bufSize = INPUT_BUF_SIZE;
|
||||
look_stream.realStream = &archive_stream.vt;
|
||||
LookToRead2_INIT(&look_stream)
|
||||
|
||||
CrcGenerateTable();
|
||||
SzArEx_Init(&db);
|
||||
|
||||
res = SzArEx_Open(&db, &look_stream.vt, &g_alloc, &g_temp);
|
||||
if (res != SZ_OK) {
|
||||
fprintf(stderr, "SzArEx_Open failed: res=%d\n", (int)res);
|
||||
if (res == SZ_ERROR_UNSUPPORTED)
|
||||
fprintf(stderr, " (unsupported coder - encrypted header or exotic method)\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("entries: %u\n", (unsigned)db.NumFiles);
|
||||
|
||||
for (i = 0; i < db.NumFiles; i++) {
|
||||
const int is_dir = SzArEx_IsDir(&db, i);
|
||||
const size_t len = SzArEx_GetFileNameUtf16(&db, i, NULL);
|
||||
char rel[MAX_PATH_LEN];
|
||||
char full[MAX_PATH_LEN];
|
||||
size_t offset = 0;
|
||||
size_t processed = 0;
|
||||
|
||||
if (len + 1 > name16_cap) {
|
||||
UInt16 *grown = (UInt16 *)realloc(name16, (len + 1) * sizeof(UInt16));
|
||||
if (!grown) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
return 1;
|
||||
}
|
||||
name16 = grown;
|
||||
name16_cap = len + 1;
|
||||
}
|
||||
SzArEx_GetFileNameUtf16(&db, i, name16);
|
||||
utf16_to_utf8(name16, rel, sizeof(rel));
|
||||
|
||||
if (snprintf(full, sizeof(full), "%s/%s", out_dir, rel) >= (int)sizeof(full)) {
|
||||
printf(" SKIP (path too long) %s\n", rel);
|
||||
g_failures++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_dir) {
|
||||
make_dirs(full);
|
||||
printf(" dir %s\n", rel);
|
||||
continue;
|
||||
}
|
||||
|
||||
res = SzArEx_Extract(&db, &look_stream.vt, i, &block_index, &out_buffer,
|
||||
&out_buffer_size, &offset, &processed, &g_alloc, &g_temp);
|
||||
if (res != SZ_OK) {
|
||||
printf(" FAIL %s (res=%d)\n", rel, (int)res);
|
||||
g_failures++;
|
||||
/* SzArEx_Extract leaves the block cache primed with a half-decoded
|
||||
buffer when the folder decode fails; drop it so the next entry
|
||||
reports its own error instead of a bogus CRC mismatch. */
|
||||
block_index = 0xFFFFFFFF;
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
char *slash = strrchr(full, '/');
|
||||
if (slash) {
|
||||
*slash = 0;
|
||||
make_dirs(full);
|
||||
*slash = '/';
|
||||
}
|
||||
}
|
||||
if (write_file(full, out_buffer + offset, processed) != 0) {
|
||||
printf(" FAIL %s (write error)\n", rel);
|
||||
g_failures++;
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 crc = 0;
|
||||
if (SzBitWithVals_Check(&db.CRCs, i)) {
|
||||
crc = CrcCalc(out_buffer + offset, processed);
|
||||
if (crc != db.CRCs.Vals[i]) {
|
||||
printf(" FAIL %s (crc mismatch)\n", rel);
|
||||
g_failures++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf(" ok %s (%lu bytes)\n", rel, (unsigned long)processed);
|
||||
}
|
||||
|
||||
ISzAlloc_Free(&g_alloc, out_buffer);
|
||||
ISzAlloc_Free(&g_alloc, look_stream.buf);
|
||||
SzArEx_Free(&db, &g_alloc);
|
||||
File_Close(&archive_stream.file);
|
||||
free(name16);
|
||||
|
||||
printf("%s: %d failure(s)\n", argv[1], g_failures);
|
||||
return g_failures ? 1 : 0;
|
||||
}
|
||||
Vendored
+204
@@ -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
|
||||
Vendored
+89
@@ -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);
|
||||
}
|
||||
Vendored
+19
@@ -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
|
||||
Vendored
+1701
File diff suppressed because it is too large.
Load diff
Vendored
+36
@@ -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;
|
||||
}
|
||||
Vendored
+35
@@ -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
|
||||
Vendored
+52
@@ -0,0 +1,52 @@
|
||||
/* 7zBuf2.c -- Byte Buffer
|
||||
2017-04-03 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "7zBuf.h"
|
||||
|
||||
void DynBuf_Construct(CDynBuf *p)
|
||||
{
|
||||
p->data = 0;
|
||||
p->size = 0;
|
||||
p->pos = 0;
|
||||
}
|
||||
|
||||
void DynBuf_SeekToBeg(CDynBuf *p)
|
||||
{
|
||||
p->pos = 0;
|
||||
}
|
||||
|
||||
int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc)
|
||||
{
|
||||
if (size > p->size - p->pos)
|
||||
{
|
||||
size_t newSize = p->pos + size;
|
||||
Byte *data;
|
||||
newSize += newSize / 4;
|
||||
data = (Byte *)ISzAlloc_Alloc(alloc, newSize);
|
||||
if (!data)
|
||||
return 0;
|
||||
p->size = newSize;
|
||||
if (p->pos != 0)
|
||||
memcpy(data, p->data, p->pos);
|
||||
ISzAlloc_Free(alloc, p->data);
|
||||
p->data = data;
|
||||
}
|
||||
if (size != 0)
|
||||
{
|
||||
memcpy(p->data + p->pos, buf, size);
|
||||
p->pos += size;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc)
|
||||
{
|
||||
ISzAlloc_Free(alloc, p->data);
|
||||
p->data = 0;
|
||||
p->size = 0;
|
||||
p->pos = 0;
|
||||
}
|
||||
Vendored
+420
@@ -0,0 +1,420 @@
|
||||
/* 7zCrc.c -- CRC32 calculation and init
|
||||
2024-03-01 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "7zCrc.h"
|
||||
#include "CpuArch.h"
|
||||
|
||||
// for debug:
|
||||
// #define __ARM_FEATURE_CRC32 1
|
||||
|
||||
#ifdef __ARM_FEATURE_CRC32
|
||||
// #pragma message("__ARM_FEATURE_CRC32")
|
||||
#define Z7_CRC_HW_FORCE
|
||||
#endif
|
||||
|
||||
// #define Z7_CRC_DEBUG_BE
|
||||
#ifdef Z7_CRC_DEBUG_BE
|
||||
#undef MY_CPU_LE
|
||||
#define MY_CPU_BE
|
||||
#endif
|
||||
|
||||
#ifdef Z7_CRC_HW_FORCE
|
||||
#define Z7_CRC_NUM_TABLES_USE 1
|
||||
#else
|
||||
#ifdef Z7_CRC_NUM_TABLES
|
||||
#define Z7_CRC_NUM_TABLES_USE Z7_CRC_NUM_TABLES
|
||||
#else
|
||||
#define Z7_CRC_NUM_TABLES_USE 12
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if Z7_CRC_NUM_TABLES_USE < 1
|
||||
#error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_LE) || (Z7_CRC_NUM_TABLES_USE == 1)
|
||||
#define Z7_CRC_NUM_TABLES_TOTAL Z7_CRC_NUM_TABLES_USE
|
||||
#else
|
||||
#define Z7_CRC_NUM_TABLES_TOTAL (Z7_CRC_NUM_TABLES_USE + 1)
|
||||
#endif
|
||||
|
||||
#ifndef Z7_CRC_HW_FORCE
|
||||
|
||||
#if Z7_CRC_NUM_TABLES_USE == 1 \
|
||||
|| (!defined(MY_CPU_LE) && !defined(MY_CPU_BE))
|
||||
#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
#define Z7_CRC_UPDATE_T1_FUNC_NAME CrcUpdateGT1
|
||||
static UInt32 Z7_FASTCALL Z7_CRC_UPDATE_T1_FUNC_NAME(UInt32 v, const void *data, size_t size)
|
||||
{
|
||||
const UInt32 *table = g_CrcTable;
|
||||
const Byte *p = (const Byte *)data;
|
||||
const Byte *lim = p + size;
|
||||
for (; p != lim; p++)
|
||||
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||
return v;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if Z7_CRC_NUM_TABLES_USE != 1
|
||||
#ifndef MY_CPU_BE
|
||||
#define FUNC_NAME_LE_2(s) CrcUpdateT ## s
|
||||
#define FUNC_NAME_LE_1(s) FUNC_NAME_LE_2(s)
|
||||
#define FUNC_NAME_LE FUNC_NAME_LE_1(Z7_CRC_NUM_TABLES_USE)
|
||||
UInt32 Z7_FASTCALL FUNC_NAME_LE (UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
#endif
|
||||
#ifndef MY_CPU_LE
|
||||
#define FUNC_NAME_BE_2(s) CrcUpdateT1_BeT ## s
|
||||
#define FUNC_NAME_BE_1(s) FUNC_NAME_BE_2(s)
|
||||
#define FUNC_NAME_BE FUNC_NAME_BE_1(Z7_CRC_NUM_TABLES_USE)
|
||||
UInt32 Z7_FASTCALL FUNC_NAME_BE (UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // Z7_CRC_HW_FORCE
|
||||
|
||||
/* ---------- hardware CRC ---------- */
|
||||
|
||||
#ifdef MY_CPU_LE
|
||||
|
||||
#if defined(MY_CPU_ARM_OR_ARM64)
|
||||
// #pragma message("ARM*")
|
||||
|
||||
#if (defined(__clang__) && (__clang_major__ >= 3)) \
|
||||
|| defined(__GNUC__) && (__GNUC__ >= 6) && defined(MY_CPU_ARM64) \
|
||||
|| defined(__GNUC__) && (__GNUC__ >= 8)
|
||||
#if !defined(__ARM_FEATURE_CRC32)
|
||||
// #pragma message("!defined(__ARM_FEATURE_CRC32)")
|
||||
Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
|
||||
#define __ARM_FEATURE_CRC32 1
|
||||
Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
|
||||
#define Z7_ARM_FEATURE_CRC32_WAS_SET
|
||||
#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)
|
||||
#if !defined(Z7_GCC_VERSION) || (Z7_GCC_VERSION >= 60000)
|
||||
#define ATTRIB_CRC __attribute__((__target__("+crc")))
|
||||
#endif
|
||||
#else
|
||||
#if !defined(Z7_GCC_VERSION) || (__GNUC__ >= 8)
|
||||
#if defined(__ARM_FP) && __GNUC__ >= 8
|
||||
// for -mfloat-abi=hard: similar to <arm_acle.h>
|
||||
#define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc+simd")))
|
||||
#else
|
||||
#define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc")))
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#if defined(__ARM_FEATURE_CRC32)
|
||||
// #pragma message("<arm_acle.h>")
|
||||
/*
|
||||
arm_acle.h (GGC):
|
||||
before Nov 17, 2017:
|
||||
#ifdef __ARM_FEATURE_CRC32
|
||||
|
||||
Nov 17, 2017: gcc10.0 (gcc 9.2.0) checked"
|
||||
#if __ARM_ARCH >= 8
|
||||
#pragma GCC target ("arch=armv8-a+crc")
|
||||
|
||||
Aug 22, 2019: GCC 8.4?, 9.2.1, 10.1:
|
||||
#ifdef __ARM_FEATURE_CRC32
|
||||
#ifdef __ARM_FP
|
||||
#pragma GCC target ("arch=armv8-a+crc+simd")
|
||||
#else
|
||||
#pragma GCC target ("arch=armv8-a+crc")
|
||||
#endif
|
||||
*/
|
||||
#if defined(__ARM_ARCH) && __ARM_ARCH < 8
|
||||
#if defined(Z7_GCC_VERSION) && (__GNUC__ == 8) && (Z7_GCC_VERSION < 80400) \
|
||||
|| defined(Z7_GCC_VERSION) && (__GNUC__ == 9) && (Z7_GCC_VERSION < 90201) \
|
||||
|| defined(Z7_GCC_VERSION) && (__GNUC__ == 10) && (Z7_GCC_VERSION < 100100)
|
||||
Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
|
||||
// #pragma message("#define __ARM_ARCH 8")
|
||||
#undef __ARM_ARCH
|
||||
#define __ARM_ARCH 8
|
||||
Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
|
||||
#endif
|
||||
#endif
|
||||
#define Z7_CRC_HW_USE
|
||||
#include <arm_acle.h>
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#if defined(MY_CPU_ARM64)
|
||||
#if (_MSC_VER >= 1910)
|
||||
#ifdef __clang__
|
||||
// #define Z7_CRC_HW_USE
|
||||
// #include <arm_acle.h>
|
||||
#else
|
||||
#define Z7_CRC_HW_USE
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else // non-ARM*
|
||||
|
||||
// #define Z7_CRC_HW_USE // for debug : we can test HW-branch of code
|
||||
#ifdef Z7_CRC_HW_USE
|
||||
#include "7zCrcEmu.h"
|
||||
#endif
|
||||
|
||||
#endif // non-ARM*
|
||||
|
||||
|
||||
|
||||
#if defined(Z7_CRC_HW_USE)
|
||||
|
||||
// #pragma message("USE ARM HW CRC")
|
||||
|
||||
#ifdef MY_CPU_64BIT
|
||||
#define CRC_HW_WORD_TYPE UInt64
|
||||
#define CRC_HW_WORD_FUNC __crc32d
|
||||
#else
|
||||
#define CRC_HW_WORD_TYPE UInt32
|
||||
#define CRC_HW_WORD_FUNC __crc32w
|
||||
#endif
|
||||
|
||||
#define CRC_HW_UNROLL_BYTES (sizeof(CRC_HW_WORD_TYPE) * 4)
|
||||
|
||||
#ifdef ATTRIB_CRC
|
||||
ATTRIB_CRC
|
||||
#endif
|
||||
Z7_NO_INLINE
|
||||
#ifdef Z7_CRC_HW_FORCE
|
||||
UInt32 Z7_FASTCALL CrcUpdate
|
||||
#else
|
||||
static UInt32 Z7_FASTCALL CrcUpdate_HW
|
||||
#endif
|
||||
(UInt32 v, const void *data, size_t size)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
for (; size != 0 && ((unsigned)(ptrdiff_t)p & (CRC_HW_UNROLL_BYTES - 1)) != 0; size--)
|
||||
v = __crc32b(v, *p++);
|
||||
if (size >= CRC_HW_UNROLL_BYTES)
|
||||
{
|
||||
const Byte *lim = p + size;
|
||||
size &= CRC_HW_UNROLL_BYTES - 1;
|
||||
lim -= size;
|
||||
do
|
||||
{
|
||||
v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p));
|
||||
v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p + sizeof(CRC_HW_WORD_TYPE)));
|
||||
p += 2 * sizeof(CRC_HW_WORD_TYPE);
|
||||
v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p));
|
||||
v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p + sizeof(CRC_HW_WORD_TYPE)));
|
||||
p += 2 * sizeof(CRC_HW_WORD_TYPE);
|
||||
}
|
||||
while (p != lim);
|
||||
}
|
||||
|
||||
for (; size != 0; size--)
|
||||
v = __crc32b(v, *p++);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
#ifdef Z7_ARM_FEATURE_CRC32_WAS_SET
|
||||
Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
|
||||
#undef __ARM_FEATURE_CRC32
|
||||
Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
|
||||
#undef Z7_ARM_FEATURE_CRC32_WAS_SET
|
||||
#endif
|
||||
|
||||
#endif // defined(Z7_CRC_HW_USE)
|
||||
#endif // MY_CPU_LE
|
||||
|
||||
|
||||
|
||||
#ifndef Z7_CRC_HW_FORCE
|
||||
|
||||
#if defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME)
|
||||
/*
|
||||
typedef UInt32 (Z7_FASTCALL *Z7_CRC_UPDATE_WITH_TABLE_FUNC)
|
||||
(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
Z7_CRC_UPDATE_WITH_TABLE_FUNC g_CrcUpdate;
|
||||
*/
|
||||
static unsigned g_Crc_Algo;
|
||||
#if (!defined(MY_CPU_LE) && !defined(MY_CPU_BE))
|
||||
static unsigned g_Crc_Be;
|
||||
#endif
|
||||
#endif // defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME)
|
||||
|
||||
|
||||
|
||||
Z7_NO_INLINE
|
||||
#ifdef Z7_CRC_HW_USE
|
||||
static UInt32 Z7_FASTCALL CrcUpdate_Base
|
||||
#else
|
||||
UInt32 Z7_FASTCALL CrcUpdate
|
||||
#endif
|
||||
(UInt32 crc, const void *data, size_t size)
|
||||
{
|
||||
#if Z7_CRC_NUM_TABLES_USE == 1
|
||||
return Z7_CRC_UPDATE_T1_FUNC_NAME(crc, data, size);
|
||||
#else // Z7_CRC_NUM_TABLES_USE != 1
|
||||
#ifdef Z7_CRC_UPDATE_T1_FUNC_NAME
|
||||
if (g_Crc_Algo == 1)
|
||||
return Z7_CRC_UPDATE_T1_FUNC_NAME(crc, data, size);
|
||||
#endif
|
||||
|
||||
#ifdef MY_CPU_LE
|
||||
return FUNC_NAME_LE(crc, data, size, g_CrcTable);
|
||||
#elif defined(MY_CPU_BE)
|
||||
return FUNC_NAME_BE(crc, data, size, g_CrcTable);
|
||||
#else
|
||||
if (g_Crc_Be)
|
||||
return FUNC_NAME_BE(crc, data, size, g_CrcTable);
|
||||
else
|
||||
return FUNC_NAME_LE(crc, data, size, g_CrcTable);
|
||||
#endif
|
||||
#endif // Z7_CRC_NUM_TABLES_USE != 1
|
||||
}
|
||||
|
||||
|
||||
#ifdef Z7_CRC_HW_USE
|
||||
Z7_NO_INLINE
|
||||
UInt32 Z7_FASTCALL CrcUpdate(UInt32 crc, const void *data, size_t size)
|
||||
{
|
||||
if (g_Crc_Algo == 0)
|
||||
return CrcUpdate_HW(crc, data, size);
|
||||
return CrcUpdate_Base(crc, data, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // !defined(Z7_CRC_HW_FORCE)
|
||||
|
||||
|
||||
|
||||
UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size)
|
||||
{
|
||||
return CrcUpdate(CRC_INIT_VAL, data, size) ^ CRC_INIT_VAL;
|
||||
}
|
||||
|
||||
|
||||
MY_ALIGN(64)
|
||||
UInt32 g_CrcTable[256 * Z7_CRC_NUM_TABLES_TOTAL];
|
||||
|
||||
|
||||
void Z7_FASTCALL CrcGenerateTable(void)
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
#if defined(Z7_CRC_HW_FORCE)
|
||||
g_CrcTable[i] = __crc32b(i, 0);
|
||||
#else
|
||||
#define kCrcPoly 0xEDB88320
|
||||
UInt32 r = i;
|
||||
unsigned j;
|
||||
for (j = 0; j < 8; j++)
|
||||
r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1)));
|
||||
g_CrcTable[i] = r;
|
||||
#endif
|
||||
}
|
||||
for (i = 256; i < 256 * Z7_CRC_NUM_TABLES_USE; i++)
|
||||
{
|
||||
const UInt32 r = g_CrcTable[(size_t)i - 256];
|
||||
g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
|
||||
}
|
||||
|
||||
#if !defined(Z7_CRC_HW_FORCE) && \
|
||||
(defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME) || defined(MY_CPU_BE))
|
||||
|
||||
#if Z7_CRC_NUM_TABLES_USE <= 1
|
||||
g_Crc_Algo = 1;
|
||||
#else // Z7_CRC_NUM_TABLES_USE <= 1
|
||||
|
||||
#if defined(MY_CPU_LE)
|
||||
g_Crc_Algo = Z7_CRC_NUM_TABLES_USE;
|
||||
#else // !defined(MY_CPU_LE)
|
||||
{
|
||||
#ifndef MY_CPU_BE
|
||||
UInt32 k = 0x01020304;
|
||||
const Byte *p = (const Byte *)&k;
|
||||
if (p[0] == 4 && p[1] == 3)
|
||||
g_Crc_Algo = Z7_CRC_NUM_TABLES_USE;
|
||||
else if (p[0] != 1 || p[1] != 2)
|
||||
g_Crc_Algo = 1;
|
||||
else
|
||||
#endif // MY_CPU_BE
|
||||
{
|
||||
for (i = 256 * Z7_CRC_NUM_TABLES_TOTAL - 1; i >= 256; i--)
|
||||
{
|
||||
const UInt32 x = g_CrcTable[(size_t)i - 256];
|
||||
g_CrcTable[i] = Z7_BSWAP32(x);
|
||||
}
|
||||
#if defined(Z7_CRC_UPDATE_T1_FUNC_NAME)
|
||||
g_Crc_Algo = Z7_CRC_NUM_TABLES_USE;
|
||||
#endif
|
||||
#if (!defined(MY_CPU_LE) && !defined(MY_CPU_BE))
|
||||
g_Crc_Be = 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif // !defined(MY_CPU_LE)
|
||||
|
||||
#ifdef MY_CPU_LE
|
||||
#ifdef Z7_CRC_HW_USE
|
||||
if (CPU_IsSupported_CRC32())
|
||||
g_Crc_Algo = 0;
|
||||
#endif // Z7_CRC_HW_USE
|
||||
#endif // MY_CPU_LE
|
||||
|
||||
#endif // Z7_CRC_NUM_TABLES_USE <= 1
|
||||
#endif // g_Crc_Algo was declared
|
||||
}
|
||||
|
||||
Z7_CRC_UPDATE_FUNC z7_GetFunc_CrcUpdate(unsigned algo)
|
||||
{
|
||||
if (algo == 0)
|
||||
return &CrcUpdate;
|
||||
|
||||
#if defined(Z7_CRC_HW_USE)
|
||||
if (algo == sizeof(CRC_HW_WORD_TYPE) * 8)
|
||||
{
|
||||
#ifdef Z7_CRC_HW_FORCE
|
||||
return &CrcUpdate;
|
||||
#else
|
||||
if (g_Crc_Algo == 0)
|
||||
return &CrcUpdate_HW;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef Z7_CRC_HW_FORCE
|
||||
if (algo == Z7_CRC_NUM_TABLES_USE)
|
||||
return
|
||||
#ifdef Z7_CRC_HW_USE
|
||||
&CrcUpdate_Base;
|
||||
#else
|
||||
&CrcUpdate;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#undef kCrcPoly
|
||||
#undef Z7_CRC_NUM_TABLES_USE
|
||||
#undef Z7_CRC_NUM_TABLES_TOTAL
|
||||
#undef CRC_UPDATE_BYTE_2
|
||||
#undef FUNC_NAME_LE_2
|
||||
#undef FUNC_NAME_LE_1
|
||||
#undef FUNC_NAME_LE
|
||||
#undef FUNC_NAME_BE_2
|
||||
#undef FUNC_NAME_BE_1
|
||||
#undef FUNC_NAME_BE
|
||||
|
||||
#undef CRC_HW_UNROLL_BYTES
|
||||
#undef CRC_HW_WORD_FUNC
|
||||
#undef CRC_HW_WORD_TYPE
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
/* 7zCrc.h -- CRC32 calculation
|
||||
2024-01-22 : 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 *Z7_CRC_UPDATE_FUNC)(UInt32 v, const void *data, size_t size);
|
||||
Z7_CRC_UPDATE_FUNC z7_GetFunc_CrcUpdate(unsigned algo);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
Vendored
+199
@@ -0,0 +1,199 @@
|
||||
/* 7zCrcOpt.c -- CRC32 calculation (optimized functions)
|
||||
2023-12-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "CpuArch.h"
|
||||
|
||||
#if !defined(Z7_CRC_NUM_TABLES) || Z7_CRC_NUM_TABLES > 1
|
||||
|
||||
// for debug only : define Z7_CRC_DEBUG_BE to test big-endian code in little-endian cpu
|
||||
// #define Z7_CRC_DEBUG_BE
|
||||
#ifdef Z7_CRC_DEBUG_BE
|
||||
#undef MY_CPU_LE
|
||||
#define MY_CPU_BE
|
||||
#endif
|
||||
|
||||
// the value Z7_CRC_NUM_TABLES_USE must be defined to same value as in 7zCrc.c
|
||||
#ifdef Z7_CRC_NUM_TABLES
|
||||
#define Z7_CRC_NUM_TABLES_USE Z7_CRC_NUM_TABLES
|
||||
#else
|
||||
#define Z7_CRC_NUM_TABLES_USE 12
|
||||
#endif
|
||||
|
||||
#if Z7_CRC_NUM_TABLES_USE % 4 || \
|
||||
Z7_CRC_NUM_TABLES_USE < 4 * 1 || \
|
||||
Z7_CRC_NUM_TABLES_USE > 4 * 6
|
||||
#error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef MY_CPU_BE
|
||||
|
||||
#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
|
||||
#define Q(n, d) \
|
||||
( (table + ((n) * 4 + 3) * 0x100)[(Byte)(d)] \
|
||||
^ (table + ((n) * 4 + 2) * 0x100)[((d) >> 1 * 8) & 0xFF] \
|
||||
^ (table + ((n) * 4 + 1) * 0x100)[((d) >> 2 * 8) & 0xFF] \
|
||||
^ (table + ((n) * 4 + 0) * 0x100)[((d) >> 3 * 8)] )
|
||||
|
||||
#define R(a) *((const UInt32 *)(const void *)p + (a))
|
||||
|
||||
#define CRC_FUNC_PRE_LE2(step) \
|
||||
UInt32 Z7_FASTCALL CrcUpdateT ## step (UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||
|
||||
#define CRC_FUNC_PRE_LE(step) \
|
||||
CRC_FUNC_PRE_LE2(step); \
|
||||
CRC_FUNC_PRE_LE2(step)
|
||||
|
||||
CRC_FUNC_PRE_LE(Z7_CRC_NUM_TABLES_USE)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
const Byte *lim;
|
||||
for (; size && ((unsigned)(ptrdiff_t)p & (7 - (Z7_CRC_NUM_TABLES_USE & 4))) != 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||
lim = p + size;
|
||||
if (size >= Z7_CRC_NUM_TABLES_USE)
|
||||
{
|
||||
lim -= Z7_CRC_NUM_TABLES_USE;
|
||||
do
|
||||
{
|
||||
v ^= R(0);
|
||||
{
|
||||
#if Z7_CRC_NUM_TABLES_USE == 1 * 4
|
||||
v = Q(0, v);
|
||||
#else
|
||||
#define U2(r, op) \
|
||||
{ d = R(r); x op Q(Z7_CRC_NUM_TABLES_USE / 4 - 1 - (r), d); }
|
||||
UInt32 d, x;
|
||||
U2(1, =)
|
||||
#if Z7_CRC_NUM_TABLES_USE >= 3 * 4
|
||||
#define U(r) U2(r, ^=)
|
||||
U(2)
|
||||
#if Z7_CRC_NUM_TABLES_USE >= 4 * 4
|
||||
U(3)
|
||||
#if Z7_CRC_NUM_TABLES_USE >= 5 * 4
|
||||
U(4)
|
||||
#if Z7_CRC_NUM_TABLES_USE >= 6 * 4
|
||||
U(5)
|
||||
#if Z7_CRC_NUM_TABLES_USE >= 7 * 4
|
||||
#error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#undef U
|
||||
#undef U2
|
||||
v = x ^ Q(Z7_CRC_NUM_TABLES_USE / 4 - 1, v);
|
||||
#endif
|
||||
}
|
||||
p += Z7_CRC_NUM_TABLES_USE;
|
||||
}
|
||||
while (p <= lim);
|
||||
lim += Z7_CRC_NUM_TABLES_USE;
|
||||
}
|
||||
for (; p < lim; p++)
|
||||
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||
return v;
|
||||
}
|
||||
|
||||
#undef CRC_UPDATE_BYTE_2
|
||||
#undef R
|
||||
#undef Q
|
||||
#undef CRC_FUNC_PRE_LE
|
||||
#undef CRC_FUNC_PRE_LE2
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef MY_CPU_LE
|
||||
|
||||
#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[((crc) >> 24) ^ (b)] ^ ((crc) << 8))
|
||||
|
||||
#define Q(n, d) \
|
||||
( (table + ((n) * 4 + 0) * 0x100)[((d)) & 0xFF] \
|
||||
^ (table + ((n) * 4 + 1) * 0x100)[((d) >> 1 * 8) & 0xFF] \
|
||||
^ (table + ((n) * 4 + 2) * 0x100)[((d) >> 2 * 8) & 0xFF] \
|
||||
^ (table + ((n) * 4 + 3) * 0x100)[((d) >> 3 * 8)] )
|
||||
|
||||
#ifdef Z7_CRC_DEBUG_BE
|
||||
#define R(a) GetBe32a((const UInt32 *)(const void *)p + (a))
|
||||
#else
|
||||
#define R(a) *((const UInt32 *)(const void *)p + (a))
|
||||
#endif
|
||||
|
||||
|
||||
#define CRC_FUNC_PRE_BE2(step) \
|
||||
UInt32 Z7_FASTCALL CrcUpdateT1_BeT ## step (UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||
|
||||
#define CRC_FUNC_PRE_BE(step) \
|
||||
CRC_FUNC_PRE_BE2(step); \
|
||||
CRC_FUNC_PRE_BE2(step)
|
||||
|
||||
CRC_FUNC_PRE_BE(Z7_CRC_NUM_TABLES_USE)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
const Byte *lim;
|
||||
table += 0x100;
|
||||
v = Z7_BSWAP32(v);
|
||||
for (; size && ((unsigned)(ptrdiff_t)p & (7 - (Z7_CRC_NUM_TABLES_USE & 4))) != 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2_BE(v, *p);
|
||||
lim = p + size;
|
||||
if (size >= Z7_CRC_NUM_TABLES_USE)
|
||||
{
|
||||
lim -= Z7_CRC_NUM_TABLES_USE;
|
||||
do
|
||||
{
|
||||
v ^= R(0);
|
||||
{
|
||||
#if Z7_CRC_NUM_TABLES_USE == 1 * 4
|
||||
v = Q(0, v);
|
||||
#else
|
||||
#define U2(r, op) \
|
||||
{ d = R(r); x op Q(Z7_CRC_NUM_TABLES_USE / 4 - 1 - (r), d); }
|
||||
UInt32 d, x;
|
||||
U2(1, =)
|
||||
#if Z7_CRC_NUM_TABLES_USE >= 3 * 4
|
||||
#define U(r) U2(r, ^=)
|
||||
U(2)
|
||||
#if Z7_CRC_NUM_TABLES_USE >= 4 * 4
|
||||
U(3)
|
||||
#if Z7_CRC_NUM_TABLES_USE >= 5 * 4
|
||||
U(4)
|
||||
#if Z7_CRC_NUM_TABLES_USE >= 6 * 4
|
||||
U(5)
|
||||
#if Z7_CRC_NUM_TABLES_USE >= 7 * 4
|
||||
#error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#undef U
|
||||
#undef U2
|
||||
v = x ^ Q(Z7_CRC_NUM_TABLES_USE / 4 - 1, v);
|
||||
#endif
|
||||
}
|
||||
p += Z7_CRC_NUM_TABLES_USE;
|
||||
}
|
||||
while (p <= lim);
|
||||
lim += Z7_CRC_NUM_TABLES_USE;
|
||||
}
|
||||
for (; p < lim; p++)
|
||||
v = CRC_UPDATE_BYTE_2_BE(v, *p);
|
||||
return Z7_BSWAP32(v);
|
||||
}
|
||||
|
||||
#undef CRC_UPDATE_BYTE_2_BE
|
||||
#undef R
|
||||
#undef Q
|
||||
#undef CRC_FUNC_PRE_BE
|
||||
#undef CRC_FUNC_PRE_BE2
|
||||
|
||||
#endif
|
||||
#undef Z7_CRC_NUM_TABLES_USE
|
||||
#endif
|
||||
Vendored
+672
@@ -0,0 +1,672 @@
|
||||
/* 7zDec.c -- Decoding from 7z folder
|
||||
: 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_RISCV 0xb
|
||||
#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;
|
||||
SRes res;
|
||||
unsigned order;
|
||||
UInt32 memSize;
|
||||
|
||||
if (propsSize != 5)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
order = props[0];
|
||||
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;
|
||||
if ((ppmd = (CPpmd7 *)ISzAlloc_Alloc(allocMain, sizeof(CPpmd7))) == NULL)
|
||||
return SZ_ERROR_MEM;
|
||||
Ppmd7_Construct(ppmd);
|
||||
res = SZ_ERROR_MEM;
|
||||
if (Ppmd7_Alloc(ppmd, memSize, allocMain))
|
||||
{
|
||||
CByteInToLook s;
|
||||
s.vt.Read = ReadByte;
|
||||
s.inStream = inStream;
|
||||
s.begin = s.end = s.cur = NULL;
|
||||
s.extra = False;
|
||||
s.res = SZ_OK;
|
||||
s.processed = 0;
|
||||
|
||||
Ppmd7_Init(ppmd, order);
|
||||
ppmd->rc.dec.Stream = &s.vt;
|
||||
res = SZ_ERROR_DATA;
|
||||
if (Ppmd7z_RangeDec_Init(&ppmd->rc.dec) && !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)
|
||||
if (Ppmd7z_RangeDec_IsFinishedOK(&ppmd->rc.dec)
|
||||
// || (Ppmd7z_DecodeSymbol(&ppmd) == PPMD7_SYM_END && Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec))
|
||||
)
|
||||
res = SZ_OK;
|
||||
}
|
||||
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);
|
||||
}
|
||||
ISzAlloc_Free(allocMain, ppmd);
|
||||
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;
|
||||
default:
|
||||
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:
|
||||
case k_RISCV:
|
||||
#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);
|
||||
if (pc & 3)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
else if (coder->PropsSize != 0)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
z7_BranchConv_ARM64_Dec(outBuffer, outSize, pc);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(Z7_NO_METHODS_FILTERS)
|
||||
if (coder->MethodID == k_RISCV)
|
||||
{
|
||||
UInt32 pc = 0;
|
||||
if (coder->PropsSize == 4)
|
||||
{
|
||||
pc = GetUi32(propsData + coder->PropsOffset);
|
||||
if (pc & 1)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
else if (coder->PropsSize != 0)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
z7_BranchConv_RISCV_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 k_PPC: Z7_BRANCH_CONV_DEC_2(BranchConv_PPC)(outBuffer, outSize, 0); break; // pc = 0;
|
||||
// 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 // Z7_USE_BRANCH_FILTER
|
||||
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;
|
||||
}
|
||||
}
|
||||
Vendored
+443
@@ -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;
|
||||
}
|
||||
Vendored
+91
@@ -0,0 +1,91 @@
|
||||
/* 7zFile.h -- File IO
|
||||
: Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef ZIP7_INC_FILE_H
|
||||
#define ZIP7_INC_FILE_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#define USE_WINDOWS_FILE
|
||||
#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
|
||||
Vendored
+199
@@ -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;
|
||||
}
|
||||
Vendored
+600
@@ -0,0 +1,600 @@
|
||||
/* 7zTypes.h -- Basic types
|
||||
: 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
|
||||
#define MY_ALIGN_IN_STRUCT(n) __declspec(align(n))
|
||||
#if _MSC_VER > 1200
|
||||
#define MY_ALIGN(n) MY_ALIGN_IN_STRUCT(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)))
|
||||
#define MY_ALIGN_IN_STRUCT(n) MY_ALIGN(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_DIAGNOSTIC_IGNORE_BEGIN_CAST_QUAL \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
|
||||
#define Z7_DIAGNOSTIC_IGNORE_END_CAST_QUAL \
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#else
|
||||
#define Z7_DIAGNOSTIC_IGNORE_BEGIN_CAST_QUAL
|
||||
#define Z7_DIAGNOSTIC_IGNORE_END_CAST_QUAL
|
||||
#endif
|
||||
|
||||
#define Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR(ptr, type, m, p) \
|
||||
Z7_DIAGNOSTIC_IGNORE_BEGIN_CAST_QUAL \
|
||||
type *p = Z7_CONTAINER_FROM_VTBL(ptr, type, m); \
|
||||
Z7_DIAGNOSTIC_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))
|
||||
#define Z7_memset_0_VAR(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
|
||||
*/
|
||||
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
#define MY_VER_MAJOR 26
|
||||
#define MY_VER_MINOR 3
|
||||
#define MY_VER_BUILD 0
|
||||
#define MY_VERSION_NUMBERS "26.03"
|
||||
#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 "2026-09-03"
|
||||
#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-2026 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
|
||||
Vendored
+107
@@ -0,0 +1,107 @@
|
||||
/* 7zWindows.h -- Windows.h and related code
|
||||
Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef ZIP7_INC_7Z_WINDOWS_H
|
||||
#define ZIP7_INC_7Z_WINDOWS_H
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1950 && !defined(__clang__) // VS2026
|
||||
// <Windows.h> and some another windows files need that option
|
||||
// VS2026: wtypesbase.h: warning C4865: 'tagCLSCTX': the underlying type will change from 'int' to 'unsigned int' when '/Zc:enumTypes' is specified on the command line
|
||||
#pragma warning(disable : 4865)
|
||||
#endif
|
||||
|
||||
#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
|
||||
Vendored
+360
@@ -0,0 +1,360 @@
|
||||
|
||||
MY_ARCH_2 = $(MY_ARCH)
|
||||
|
||||
MY_ASM = jwasm
|
||||
MY_ASM = asmc
|
||||
|
||||
ifndef RC
|
||||
#RC=windres.exe --target=pe-x86-64
|
||||
#RC=windres.exe -F pe-i386
|
||||
RC=windres.exe
|
||||
endif
|
||||
|
||||
PROGPATH = $(O)/$(PROG)
|
||||
PROGPATH_STATIC = $(O)/$(PROG)s
|
||||
|
||||
ifneq ($(CC), xlc)
|
||||
CFLAGS_WARN_WALL = -Wall -Werror -Wextra
|
||||
endif
|
||||
|
||||
# for object file
|
||||
CFLAGS_BASE_LIST = -c
|
||||
# for ASM file
|
||||
# CFLAGS_BASE_LIST = -S
|
||||
|
||||
FLAGS_FLTO = -flto
|
||||
FLAGS_FLTO =
|
||||
|
||||
CFLAGS_BASE = $(MY_ARCH_2) -O2 $(CFLAGS_BASE_LIST) $(CFLAGS_WARN_WALL) $(CFLAGS_WARN) \
|
||||
-DNDEBUG -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
|
||||
|
||||
ifdef SystemDrive
|
||||
IS_MINGW = 1
|
||||
else
|
||||
ifdef SYSTEMDRIVE
|
||||
# ifdef OS
|
||||
IS_MINGW = 1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef IS_MINGW
|
||||
LDFLAGS_STATIC_2 = -static
|
||||
else
|
||||
ifndef DEF_FILE
|
||||
ifndef IS_NOT_STANDALONE
|
||||
ifndef MY_DYNAMIC_LINK
|
||||
ifneq ($(CC), clang)
|
||||
LDFLAGS_STATIC_2 =
|
||||
# -static
|
||||
# -static-libstdc++ -static-libgcc
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
LDFLAGS_STATIC = -DNDEBUG $(LDFLAGS_STATIC_2)
|
||||
|
||||
ifdef DEF_FILE
|
||||
|
||||
|
||||
ifdef IS_MINGW
|
||||
SHARED_EXT=.dll
|
||||
LDFLAGS = -shared -DEF $(DEF_FILE) $(LDFLAGS_STATIC)
|
||||
else
|
||||
SHARED_EXT=.so
|
||||
LDFLAGS = -shared -fPIC $(LDFLAGS_STATIC)
|
||||
CC_SHARED=-fPIC
|
||||
endif
|
||||
|
||||
|
||||
else
|
||||
|
||||
LDFLAGS = $(LDFLAGS_STATIC)
|
||||
# -s is not required for clang, do we need it for GGC ???
|
||||
# -s
|
||||
|
||||
#-static -static-libgcc -static-libstdc++
|
||||
|
||||
ifdef IS_MINGW
|
||||
SHARED_EXT=.exe
|
||||
else
|
||||
SHARED_EXT=
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
|
||||
PROGPATH = $(O)/$(PROG)$(SHARED_EXT)
|
||||
PROGPATH_STATIC = $(O)/$(PROG)s$(SHARED_EXT)
|
||||
|
||||
ifndef O
|
||||
O=_o
|
||||
endif
|
||||
|
||||
ifdef IS_MINGW
|
||||
|
||||
ifdef MSYSTEM
|
||||
RM = rm -f
|
||||
MY_MKDIR=mkdir -p
|
||||
DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS)
|
||||
else
|
||||
RM = del
|
||||
MY_MKDIR=mkdir
|
||||
DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll
|
||||
endif
|
||||
|
||||
|
||||
LIB2 = -lole32 -loleaut32 -luuid -ladvapi32 -luser32 -lshell32
|
||||
|
||||
CFLAGS_EXTRA = -DUNICODE -D_UNICODE
|
||||
# -Wno-delete-non-virtual-dtor
|
||||
|
||||
|
||||
else
|
||||
|
||||
RM = rm -f
|
||||
MY_MKDIR=mkdir -p
|
||||
# CFLAGS_BASE := $(CFLAGS_BASE) -DZ7_ST
|
||||
# CFLAGS_EXTRA = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
|
||||
# LOCAL_LIBS=-lpthread
|
||||
# LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
|
||||
LIB2 = -lpthread -ldl
|
||||
|
||||
DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS)
|
||||
|
||||
endif
|
||||
|
||||
|
||||
ifdef IS_X64
|
||||
AFLAGS_ABI = -elf64 -DABI_LINUX
|
||||
else
|
||||
AFLAGS_ABI = -elf -DABI_LINUX -DABI_CDECL
|
||||
# -DABI_CDECL
|
||||
# -DABI_LINUX
|
||||
# -DABI_CDECL
|
||||
endif
|
||||
AFLAGS = $(AFLAGS_ABI) -Fo$(O)/
|
||||
|
||||
C_WARN_FLAGS =
|
||||
|
||||
CFLAGS = $(LOCAL_FLAGS) $(CFLAGS_BASE2) $(CFLAGS_BASE) $(CFLAGS_EXTRA) $(C_WARN_FLAGS) $(FLAGS_FLTO) $(CC_SHARED) -o $@
|
||||
|
||||
STATIC_TARGET=
|
||||
ifdef COMPL_STATIC
|
||||
STATIC_TARGET=$(PROGPATH_STATIC)
|
||||
endif
|
||||
|
||||
|
||||
all: $(O) $(PROGPATH) $(STATIC_TARGET)
|
||||
|
||||
$(O):
|
||||
$(MY_MKDIR) $(O)
|
||||
|
||||
ifneq ($(CC), $(CROSS_COMPILE)clang)
|
||||
LFLAGS_STRIP = -s
|
||||
endif
|
||||
|
||||
LFLAGS_ALL = $(LFLAGS_STRIP) $(MY_ARCH_2) $(LDFLAGS) $(FLAGS_FLTO) $(LD_arch) $(OBJS) $(MY_LIBS) $(LIB2)
|
||||
$(PROGPATH): $(OBJS)
|
||||
$(CC) -o $(PROGPATH) $(LFLAGS_ALL)
|
||||
|
||||
$(PROGPATH_STATIC): $(OBJS)
|
||||
$(CC) -static -o $(PROGPATH_STATIC) $(LFLAGS_ALL)
|
||||
|
||||
|
||||
ifndef NO_DEFAULT_RES
|
||||
# old mingw without -FO
|
||||
# windres.exe $(RFLAGS) resource.rc $O/resource.o
|
||||
$O/resource.o: resource.rc
|
||||
$(RC) $(RFLAGS) resource.rc $(O)/resource.o
|
||||
endif
|
||||
# windres.exe $(RFLAGS) resource.rc $(O)\resource.o
|
||||
# windres.exe $(RFLAGS) resource.rc -FO $(O)/resource.o
|
||||
# $(RC) $(RFLAGS) resource.rc -FO $(O)/resource.o
|
||||
|
||||
|
||||
|
||||
$O/7zAlloc.o: ../../../C/7zAlloc.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/7zArcIn.o: ../../../C/7zArcIn.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/7zBuf.o: ../../../C/7zBuf.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/7zBuf2.o: ../../../C/7zBuf2.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/7zCrc.o: ../../../C/7zCrc.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/7zDec.o: ../../../C/7zDec.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/7zFile.o: ../../../C/7zFile.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/7zStream.o: ../../../C/7zStream.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Aes.o: ../../../C/Aes.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Alloc.o: ../../../C/Alloc.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Bcj2.o: ../../../C/Bcj2.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Bcj2Enc.o: ../../../C/Bcj2Enc.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Blake2s.o: ../../../C/Blake2s.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Bra.o: ../../../C/Bra.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Bra86.o: ../../../C/Bra86.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/BraIA64.o: ../../../C/BraIA64.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/BwtSort.o: ../../../C/BwtSort.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
|
||||
$O/CpuArch.o: ../../../C/CpuArch.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Delta.o: ../../../C/Delta.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/DllSecur.o: ../../../C/DllSecur.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/HuffEnc.o: ../../../C/HuffEnc.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/LzFind.o: ../../../C/LzFind.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
|
||||
# ifdef MT_FILES
|
||||
$O/LzFindMt.o: ../../../C/LzFindMt.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/LzFindOpt.o: ../../../C/LzFindOpt.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
|
||||
$O/Threads.o: ../../../C/Threads.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
# endif
|
||||
|
||||
$O/LzmaEnc.o: ../../../C/LzmaEnc.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Lzma86Dec.o: ../../../C/Lzma86Dec.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Lzma86Enc.o: ../../../C/Lzma86Enc.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Lzma2Dec.o: ../../../C/Lzma2Dec.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Lzma2DecMt.o: ../../../C/Lzma2DecMt.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Lzma2Enc.o: ../../../C/Lzma2Enc.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/LzmaLib.o: ../../../C/LzmaLib.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/MtCoder.o: ../../../C/MtCoder.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/MtDec.o: ../../../C/MtDec.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Ppmd7.o: ../../../C/Ppmd7.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Ppmd7aDec.o: ../../../C/Ppmd7aDec.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Ppmd7Dec.o: ../../../C/Ppmd7Dec.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Ppmd7Enc.o: ../../../C/Ppmd7Enc.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Ppmd8.o: ../../../C/Ppmd8.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Ppmd8Dec.o: ../../../C/Ppmd8Dec.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Ppmd8Enc.o: ../../../C/Ppmd8Enc.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Sha1.o: ../../../C/Sha1.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Sha256.o: ../../../C/Sha256.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Sort.o: ../../../C/Sort.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/SwapBytes.o: ../../../C/SwapBytes.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Xz.o: ../../../C/Xz.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/XzCrc64.o: ../../../C/XzCrc64.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/XzDec.o: ../../../C/XzDec.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/XzEnc.o: ../../../C/XzEnc.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/XzIn.o: ../../../C/XzIn.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
|
||||
|
||||
ifdef USE_ASM
|
||||
ifdef IS_X64
|
||||
USE_X86_ASM=1
|
||||
else
|
||||
ifdef IS_X86
|
||||
USE_X86_ASM=1
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef USE_X86_ASM
|
||||
$O/7zCrcOpt.o: ../../../Asm/x86/7zCrcOpt.asm
|
||||
$(MY_ASM) $(AFLAGS) $<
|
||||
$O/XzCrc64Opt.o: ../../../Asm/x86/XzCrc64Opt.asm
|
||||
$(MY_ASM) $(AFLAGS) $<
|
||||
$O/AesOpt.o: ../../../Asm/x86/AesOpt.asm
|
||||
$(MY_ASM) $(AFLAGS) $<
|
||||
$O/Sha1Opt.o: ../../../Asm/x86/Sha1Opt.asm
|
||||
$(MY_ASM) $(AFLAGS) $<
|
||||
$O/Sha256Opt.o: ../../../Asm/x86/Sha256Opt.asm
|
||||
$(MY_ASM) $(AFLAGS) $<
|
||||
else
|
||||
$O/7zCrcOpt.o: ../../7zCrcOpt.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/XzCrc64Opt.o: ../../XzCrc64Opt.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Sha1Opt.o: ../../Sha1Opt.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/Sha256Opt.o: ../../Sha256Opt.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/AesOpt.o: ../../AesOpt.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
endif
|
||||
|
||||
|
||||
ifdef USE_LZMA_DEC_ASM
|
||||
|
||||
ifdef IS_X64
|
||||
$O/LzmaDecOpt.o: ../../../Asm/x86/LzmaDecOpt.asm
|
||||
$(MY_ASM) $(AFLAGS) $<
|
||||
endif
|
||||
|
||||
ifdef IS_ARM64
|
||||
$O/LzmaDecOpt.o: ../../../Asm/arm64/LzmaDecOpt.S ../../../Asm/arm64/7zAsm.S
|
||||
$(CC) $(CFLAGS) $(ASM_FLAGS) $<
|
||||
endif
|
||||
|
||||
$O/LzmaDec.o: ../../LzmaDec.c
|
||||
$(CC) $(CFLAGS) -DZ7_LZMA_DEC_OPT $<
|
||||
|
||||
else
|
||||
|
||||
$O/LzmaDec.o: ../../LzmaDec.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
|
||||
endif
|
||||
|
||||
|
||||
|
||||
$O/7zMain.o: ../../../C/Util/7z/7zMain.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/7zipInstall.o: ../../../C/Util/7zipInstall/7zipInstall.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/7zipUninstall.o: ../../../C/Util/7zipUninstall/7zipUninstall.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/LzmaUtil.o: ../../../C/Util/Lzma/LzmaUtil.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
$O/XzUtil.o: ../../../C/Util/Xz/XzUtil.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
|
||||
|
||||
clean:
|
||||
-$(DEL_OBJ_EXE)
|
||||
Vendored
+429
@@ -0,0 +1,429 @@
|
||||
/* Aes.c -- AES encryption / decryption
|
||||
2024-03-01 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "CpuArch.h"
|
||||
#include "Aes.h"
|
||||
|
||||
AES_CODE_FUNC g_AesCbc_Decode;
|
||||
#ifndef Z7_SFX
|
||||
AES_CODE_FUNC g_AesCbc_Encode;
|
||||
AES_CODE_FUNC g_AesCtr_Code;
|
||||
UInt32 g_Aes_SupportedFunctions_Flags;
|
||||
#endif
|
||||
|
||||
MY_ALIGN(64)
|
||||
static UInt32 T[256 * 4];
|
||||
MY_ALIGN(64)
|
||||
static const Byte Sbox[256] = {
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
|
||||
|
||||
|
||||
MY_ALIGN(64)
|
||||
static UInt32 D[256 * 4];
|
||||
MY_ALIGN(64)
|
||||
static Byte InvS[256];
|
||||
|
||||
#define xtime(x) ((((x) << 1) ^ (((x) & 0x80) != 0 ? 0x1B : 0)) & 0xFF)
|
||||
|
||||
#define Ui32(a0, a1, a2, a3) ((UInt32)(a0) | ((UInt32)(a1) << 8) | ((UInt32)(a2) << 16) | ((UInt32)(a3) << 24))
|
||||
|
||||
#define gb0(x) ( (x) & 0xFF)
|
||||
#define gb1(x) (((x) >> ( 8)) & 0xFF)
|
||||
#define gb2(x) (((x) >> (16)) & 0xFF)
|
||||
#define gb3(x) (((x) >> (24)))
|
||||
|
||||
#define gb(n, x) gb ## n(x)
|
||||
|
||||
#define TT(x) (T + (x << 8))
|
||||
#define DD(x) (D + (x << 8))
|
||||
|
||||
|
||||
// #define Z7_SHOW_AES_STATUS
|
||||
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
|
||||
#if defined(__INTEL_COMPILER)
|
||||
#if (__INTEL_COMPILER >= 1110)
|
||||
#define USE_HW_AES
|
||||
#if (__INTEL_COMPILER >= 1900)
|
||||
#define USE_HW_VAES
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \
|
||||
|| defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40400)
|
||||
#define USE_HW_AES
|
||||
#if defined(__clang__) && (__clang_major__ >= 8) \
|
||||
|| defined(__GNUC__) && (__GNUC__ >= 8)
|
||||
#define USE_HW_VAES
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#define USE_HW_AES
|
||||
#define USE_HW_VAES
|
||||
#endif
|
||||
|
||||
#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE)
|
||||
|
||||
#if defined(__ARM_FEATURE_AES) \
|
||||
|| defined(__ARM_FEATURE_CRYPTO)
|
||||
#define USE_HW_AES
|
||||
#else
|
||||
#if defined(MY_CPU_ARM64) \
|
||||
|| defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \
|
||||
|| defined(Z7_MSC_VER_ORIGINAL)
|
||||
#if defined(__ARM_FP) && \
|
||||
( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \
|
||||
|| defined(__GNUC__) && (__GNUC__ >= 6) \
|
||||
) \
|
||||
|| defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910)
|
||||
#if defined(MY_CPU_ARM64) \
|
||||
|| !defined(Z7_CLANG_VERSION) \
|
||||
|| defined(__ARM_NEON) && \
|
||||
(Z7_CLANG_VERSION < 170000 || \
|
||||
Z7_CLANG_VERSION > 170001)
|
||||
#define USE_HW_AES
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_HW_AES
|
||||
// #pragma message("=== Aes.c USE_HW_AES === ")
|
||||
#ifdef Z7_SHOW_AES_STATUS
|
||||
#include <stdio.h>
|
||||
#define PRF(x) x
|
||||
#else
|
||||
#define PRF(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
void AesGenTables(void)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < 256; i++)
|
||||
InvS[Sbox[i]] = (Byte)i;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
{
|
||||
const UInt32 a1 = Sbox[i];
|
||||
const UInt32 a2 = xtime(a1);
|
||||
const UInt32 a3 = a2 ^ a1;
|
||||
TT(0)[i] = Ui32(a2, a1, a1, a3);
|
||||
TT(1)[i] = Ui32(a3, a2, a1, a1);
|
||||
TT(2)[i] = Ui32(a1, a3, a2, a1);
|
||||
TT(3)[i] = Ui32(a1, a1, a3, a2);
|
||||
}
|
||||
{
|
||||
const UInt32 a1 = InvS[i];
|
||||
const UInt32 a2 = xtime(a1);
|
||||
const UInt32 a4 = xtime(a2);
|
||||
const UInt32 a8 = xtime(a4);
|
||||
const UInt32 a9 = a8 ^ a1;
|
||||
const UInt32 aB = a8 ^ a2 ^ a1;
|
||||
const UInt32 aD = a8 ^ a4 ^ a1;
|
||||
const UInt32 aE = a8 ^ a4 ^ a2;
|
||||
DD(0)[i] = Ui32(aE, a9, aD, aB);
|
||||
DD(1)[i] = Ui32(aB, aE, a9, aD);
|
||||
DD(2)[i] = Ui32(aD, aB, aE, a9);
|
||||
DD(3)[i] = Ui32(a9, aD, aB, aE);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
AES_CODE_FUNC d = AesCbc_Decode;
|
||||
#ifndef Z7_SFX
|
||||
AES_CODE_FUNC e = AesCbc_Encode;
|
||||
AES_CODE_FUNC c = AesCtr_Code;
|
||||
UInt32 flags = 0;
|
||||
#endif
|
||||
|
||||
#ifdef USE_HW_AES
|
||||
if (CPU_IsSupported_AES())
|
||||
{
|
||||
// #pragma message ("AES HW")
|
||||
PRF(printf("\n===AES HW\n"));
|
||||
d = AesCbc_Decode_HW;
|
||||
|
||||
#ifndef Z7_SFX
|
||||
e = AesCbc_Encode_HW;
|
||||
c = AesCtr_Code_HW;
|
||||
flags = k_Aes_SupportedFunctions_HW;
|
||||
#endif
|
||||
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
#ifdef USE_HW_VAES
|
||||
if (CPU_IsSupported_VAES_AVX2())
|
||||
{
|
||||
PRF(printf("\n===vaes avx2\n"));
|
||||
d = AesCbc_Decode_HW_256;
|
||||
#ifndef Z7_SFX
|
||||
c = AesCtr_Code_HW_256;
|
||||
flags |= k_Aes_SupportedFunctions_HW_256;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
g_AesCbc_Decode = d;
|
||||
#ifndef Z7_SFX
|
||||
g_AesCbc_Encode = e;
|
||||
g_AesCtr_Code = c;
|
||||
g_Aes_SupportedFunctions_Flags = flags;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define HT(i, x, s) TT(x)[gb(x, s[(i + x) & 3])]
|
||||
|
||||
#define HT4(m, i, s, p) m[i] = \
|
||||
HT(i, 0, s) ^ \
|
||||
HT(i, 1, s) ^ \
|
||||
HT(i, 2, s) ^ \
|
||||
HT(i, 3, s) ^ w[p + i]
|
||||
|
||||
#define HT16(m, s, p) \
|
||||
HT4(m, 0, s, p); \
|
||||
HT4(m, 1, s, p); \
|
||||
HT4(m, 2, s, p); \
|
||||
HT4(m, 3, s, p); \
|
||||
|
||||
#define FT(i, x) Sbox[gb(x, m[(i + x) & 3])]
|
||||
#define FT4(i) dest[i] = Ui32(FT(i, 0), FT(i, 1), FT(i, 2), FT(i, 3)) ^ w[i];
|
||||
|
||||
|
||||
#define HD(i, x, s) DD(x)[gb(x, s[(i - x) & 3])]
|
||||
|
||||
#define HD4(m, i, s, p) m[i] = \
|
||||
HD(i, 0, s) ^ \
|
||||
HD(i, 1, s) ^ \
|
||||
HD(i, 2, s) ^ \
|
||||
HD(i, 3, s) ^ w[p + i];
|
||||
|
||||
#define HD16(m, s, p) \
|
||||
HD4(m, 0, s, p); \
|
||||
HD4(m, 1, s, p); \
|
||||
HD4(m, 2, s, p); \
|
||||
HD4(m, 3, s, p); \
|
||||
|
||||
#define FD(i, x) InvS[gb(x, m[(i - x) & 3])]
|
||||
#define FD4(i) dest[i] = Ui32(FD(i, 0), FD(i, 1), FD(i, 2), FD(i, 3)) ^ w[i];
|
||||
|
||||
void Z7_FASTCALL Aes_SetKey_Enc(UInt32 *w, const Byte *key, unsigned keySize)
|
||||
{
|
||||
unsigned i, m;
|
||||
const UInt32 *wLim;
|
||||
UInt32 t;
|
||||
UInt32 rcon = 1;
|
||||
|
||||
keySize /= 4;
|
||||
w[0] = ((UInt32)keySize / 2) + 3;
|
||||
w += 4;
|
||||
|
||||
for (i = 0; i < keySize; i++, key += 4)
|
||||
w[i] = GetUi32(key);
|
||||
|
||||
t = w[(size_t)keySize - 1];
|
||||
wLim = w + (size_t)keySize * 3 + 28;
|
||||
m = 0;
|
||||
do
|
||||
{
|
||||
if (m == 0)
|
||||
{
|
||||
t = Ui32(Sbox[gb1(t)] ^ rcon, Sbox[gb2(t)], Sbox[gb3(t)], Sbox[gb0(t)]);
|
||||
rcon <<= 1;
|
||||
if (rcon & 0x100)
|
||||
rcon = 0x1b;
|
||||
m = keySize;
|
||||
}
|
||||
else if (m == 4 && keySize > 6)
|
||||
t = Ui32(Sbox[gb0(t)], Sbox[gb1(t)], Sbox[gb2(t)], Sbox[gb3(t)]);
|
||||
m--;
|
||||
t ^= w[0];
|
||||
w[keySize] = t;
|
||||
}
|
||||
while (++w != wLim);
|
||||
}
|
||||
|
||||
void Z7_FASTCALL Aes_SetKey_Dec(UInt32 *w, const Byte *key, unsigned keySize)
|
||||
{
|
||||
unsigned i, num;
|
||||
Aes_SetKey_Enc(w, key, keySize);
|
||||
num = keySize + 20;
|
||||
w += 8;
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
UInt32 r = w[i];
|
||||
w[i] =
|
||||
DD(0)[Sbox[gb0(r)]] ^
|
||||
DD(1)[Sbox[gb1(r)]] ^
|
||||
DD(2)[Sbox[gb2(r)]] ^
|
||||
DD(3)[Sbox[gb3(r)]];
|
||||
}
|
||||
}
|
||||
|
||||
/* Aes_Encode and Aes_Decode functions work with little-endian words.
|
||||
src and dest are pointers to 4 UInt32 words.
|
||||
src and dest can point to same block */
|
||||
|
||||
// Z7_FORCE_INLINE
|
||||
static void Aes_Encode(const UInt32 *w, UInt32 *dest, const UInt32 *src)
|
||||
{
|
||||
UInt32 s[4];
|
||||
UInt32 m[4];
|
||||
UInt32 numRounds2 = w[0];
|
||||
w += 4;
|
||||
s[0] = src[0] ^ w[0];
|
||||
s[1] = src[1] ^ w[1];
|
||||
s[2] = src[2] ^ w[2];
|
||||
s[3] = src[3] ^ w[3];
|
||||
w += 4;
|
||||
for (;;)
|
||||
{
|
||||
HT16(m, s, 0)
|
||||
if (--numRounds2 == 0)
|
||||
break;
|
||||
HT16(s, m, 4)
|
||||
w += 8;
|
||||
}
|
||||
w += 4;
|
||||
FT4(0)
|
||||
FT4(1)
|
||||
FT4(2)
|
||||
FT4(3)
|
||||
}
|
||||
|
||||
Z7_FORCE_INLINE
|
||||
static void Aes_Decode(const UInt32 *w, UInt32 *dest, const UInt32 *src)
|
||||
{
|
||||
UInt32 s[4];
|
||||
UInt32 m[4];
|
||||
UInt32 numRounds2 = w[0];
|
||||
w += 4 + numRounds2 * 8;
|
||||
s[0] = src[0] ^ w[0];
|
||||
s[1] = src[1] ^ w[1];
|
||||
s[2] = src[2] ^ w[2];
|
||||
s[3] = src[3] ^ w[3];
|
||||
for (;;)
|
||||
{
|
||||
w -= 8;
|
||||
HD16(m, s, 4)
|
||||
if (--numRounds2 == 0)
|
||||
break;
|
||||
HD16(s, m, 0)
|
||||
}
|
||||
FD4(0)
|
||||
FD4(1)
|
||||
FD4(2)
|
||||
FD4(3)
|
||||
}
|
||||
|
||||
void AesCbc_Init(UInt32 *p, const Byte *iv)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < 4; i++)
|
||||
p[i] = GetUi32(iv + i * 4);
|
||||
}
|
||||
|
||||
void Z7_FASTCALL AesCbc_Encode(UInt32 *p, Byte *data, size_t numBlocks)
|
||||
{
|
||||
for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE)
|
||||
{
|
||||
p[0] ^= GetUi32(data);
|
||||
p[1] ^= GetUi32(data + 4);
|
||||
p[2] ^= GetUi32(data + 8);
|
||||
p[3] ^= GetUi32(data + 12);
|
||||
|
||||
Aes_Encode(p + 4, p, p);
|
||||
|
||||
SetUi32(data, p[0])
|
||||
SetUi32(data + 4, p[1])
|
||||
SetUi32(data + 8, p[2])
|
||||
SetUi32(data + 12, p[3])
|
||||
}
|
||||
}
|
||||
|
||||
void Z7_FASTCALL AesCbc_Decode(UInt32 *p, Byte *data, size_t numBlocks)
|
||||
{
|
||||
UInt32 in[4], out[4];
|
||||
for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE)
|
||||
{
|
||||
in[0] = GetUi32(data);
|
||||
in[1] = GetUi32(data + 4);
|
||||
in[2] = GetUi32(data + 8);
|
||||
in[3] = GetUi32(data + 12);
|
||||
|
||||
Aes_Decode(p + 4, out, in);
|
||||
|
||||
SetUi32(data, p[0] ^ out[0])
|
||||
SetUi32(data + 4, p[1] ^ out[1])
|
||||
SetUi32(data + 8, p[2] ^ out[2])
|
||||
SetUi32(data + 12, p[3] ^ out[3])
|
||||
|
||||
p[0] = in[0];
|
||||
p[1] = in[1];
|
||||
p[2] = in[2];
|
||||
p[3] = in[3];
|
||||
}
|
||||
}
|
||||
|
||||
void Z7_FASTCALL AesCtr_Code(UInt32 *p, Byte *data, size_t numBlocks)
|
||||
{
|
||||
for (; numBlocks != 0; numBlocks--)
|
||||
{
|
||||
UInt32 temp[4];
|
||||
unsigned i;
|
||||
|
||||
if (++p[0] == 0)
|
||||
p[1]++;
|
||||
|
||||
Aes_Encode(p + 4, temp, p);
|
||||
|
||||
for (i = 0; i < 4; i++, data += 4)
|
||||
{
|
||||
const UInt32 t = temp[i];
|
||||
|
||||
#ifdef MY_CPU_LE_UNALIGN
|
||||
*((UInt32 *)(void *)data) ^= t;
|
||||
#else
|
||||
data[0] = (Byte)(data[0] ^ (t & 0xFF));
|
||||
data[1] = (Byte)(data[1] ^ ((t >> 8) & 0xFF));
|
||||
data[2] = (Byte)(data[2] ^ ((t >> 16) & 0xFF));
|
||||
data[3] = (Byte)(data[3] ^ ((t >> 24)));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef xtime
|
||||
#undef Ui32
|
||||
#undef gb0
|
||||
#undef gb1
|
||||
#undef gb2
|
||||
#undef gb3
|
||||
#undef gb
|
||||
#undef TT
|
||||
#undef DD
|
||||
#undef USE_HW_AES
|
||||
#undef PRF
|
||||
Vendored
+60
@@ -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
|
||||
Vendored
+1002
File diff suppressed because it is too large.
Load diff
Vendored
+774
@@ -0,0 +1,774 @@
|
||||
/* Alloc.c -- Memory allocation functions
|
||||
: Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "7zWindows.h"
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Alloc.h"
|
||||
|
||||
#if defined(Z7_LARGE_PAGES) && defined(_WIN32) && \
|
||||
(!defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0502) // < Win2003 (xp-64)
|
||||
#define Z7_USE_DYN_GetLargePageMinimum
|
||||
#endif
|
||||
|
||||
// for debug:
|
||||
#if 0
|
||||
#if defined(__CHERI__) && defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 16)
|
||||
// #pragma message("=== Z7_ALLOC_NO_OFFSET_ALLOCATOR === ")
|
||||
#define Z7_ALLOC_NO_OFFSET_ALLOCATOR
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #define SZ_ALLOC_DEBUG
|
||||
/* use SZ_ALLOC_DEBUG to debug alloc/free operations */
|
||||
#ifdef SZ_ALLOC_DEBUG
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
static int g_allocCount = 0;
|
||||
#ifdef _WIN32
|
||||
static int g_allocCountMid = 0;
|
||||
#ifdef Z7_LARGE_PAGES
|
||||
static int g_allocCountBig = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define CONVERT_INT_TO_STR(charType, tempSize) \
|
||||
char temp[tempSize]; unsigned i = 0; \
|
||||
while (val >= 10) { temp[i++] = (char)('0' + (unsigned)(val % 10)); val /= 10; } \
|
||||
*s++ = (charType)('0' + (unsigned)val); \
|
||||
while (i != 0) { i--; *s++ = temp[i]; } \
|
||||
*s = 0;
|
||||
|
||||
static void ConvertUInt64ToString(UInt64 val, char *s)
|
||||
{
|
||||
CONVERT_INT_TO_STR(char, 24)
|
||||
}
|
||||
|
||||
#define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))
|
||||
|
||||
static void ConvertUInt64ToHex(UInt64 val, char *s)
|
||||
{
|
||||
UInt64 v = val;
|
||||
unsigned i;
|
||||
for (i = 1;; i++)
|
||||
{
|
||||
v >>= 4;
|
||||
if (v == 0)
|
||||
break;
|
||||
}
|
||||
s[i] = 0;
|
||||
do
|
||||
{
|
||||
unsigned t = (unsigned)(val & 0xF);
|
||||
val >>= 4;
|
||||
s[--i] = GET_HEX_CHAR(t);
|
||||
}
|
||||
while (i);
|
||||
}
|
||||
|
||||
#define DEBUG_OUT_STREAM stderr
|
||||
|
||||
static void Print(const char *s)
|
||||
{
|
||||
fputs(s, DEBUG_OUT_STREAM);
|
||||
}
|
||||
|
||||
static void PrintAligned(const char *s, size_t align)
|
||||
{
|
||||
size_t len = strlen(s);
|
||||
for(;;)
|
||||
{
|
||||
fputc(' ', DEBUG_OUT_STREAM);
|
||||
if (len >= align)
|
||||
break;
|
||||
++len;
|
||||
}
|
||||
Print(s);
|
||||
}
|
||||
|
||||
static void PrintLn(void)
|
||||
{
|
||||
Print("\n");
|
||||
}
|
||||
|
||||
static void PrintHex(UInt64 v, size_t align)
|
||||
{
|
||||
char s[32];
|
||||
ConvertUInt64ToHex(v, s);
|
||||
PrintAligned(s, align);
|
||||
}
|
||||
|
||||
static void PrintDec(int v, size_t align)
|
||||
{
|
||||
char s[32];
|
||||
ConvertUInt64ToString((unsigned)v, s);
|
||||
PrintAligned(s, align);
|
||||
}
|
||||
|
||||
static void PrintAddr(void *p)
|
||||
{
|
||||
PrintHex((UInt64)(size_t)(ptrdiff_t)p, 12);
|
||||
}
|
||||
|
||||
|
||||
#define PRINT_REALLOC(name, cnt, size, ptr) { \
|
||||
Print(name " "); \
|
||||
if (!ptr) PrintDec(cnt++, 10); \
|
||||
PrintHex(size, 10); \
|
||||
PrintAddr(ptr); \
|
||||
PrintLn(); }
|
||||
|
||||
#define PRINT_ALLOC(name, cnt, size, ptr) { \
|
||||
Print(name " "); \
|
||||
PrintDec(cnt++, 10); \
|
||||
PrintHex(size, 10); \
|
||||
PrintAddr(ptr); \
|
||||
PrintLn(); }
|
||||
|
||||
#define PRINT_FREE(name, cnt, ptr) if (ptr) { \
|
||||
Print(name " "); \
|
||||
PrintDec(--cnt, 10); \
|
||||
PrintAddr(ptr); \
|
||||
PrintLn(); }
|
||||
|
||||
#else
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef Z7_LARGE_PAGES
|
||||
#define PRINT_ALLOC(name, cnt, size, ptr)
|
||||
#endif
|
||||
#endif
|
||||
#define PRINT_FREE(name, cnt, ptr)
|
||||
#define Print(s)
|
||||
#define PrintLn()
|
||||
#ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR
|
||||
#define PrintHex(v, align)
|
||||
#endif
|
||||
#define PrintAddr(p)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
by specification:
|
||||
malloc(non_NULL, 0) : returns NULL or a unique pointer value that can later be successfully passed to free()
|
||||
realloc(NULL, size) : the call is equivalent to malloc(size)
|
||||
realloc(non_NULL, 0) : the call is equivalent to free(ptr)
|
||||
|
||||
in main compilers:
|
||||
malloc(0) : returns non_NULL
|
||||
realloc(NULL, 0) : returns non_NULL
|
||||
realloc(non_NULL, 0) : returns NULL
|
||||
*/
|
||||
|
||||
|
||||
void *MyAlloc(size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
// PRINT_ALLOC("Alloc ", g_allocCount, size, NULL)
|
||||
#ifdef SZ_ALLOC_DEBUG
|
||||
{
|
||||
void *p = malloc(size);
|
||||
if (p)
|
||||
{
|
||||
PRINT_ALLOC("Alloc ", g_allocCount, size, p)
|
||||
}
|
||||
return p;
|
||||
}
|
||||
#else
|
||||
return malloc(size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MyFree(void *address)
|
||||
{
|
||||
PRINT_FREE("Free ", g_allocCount, address)
|
||||
|
||||
free(address);
|
||||
}
|
||||
|
||||
void *MyRealloc(void *address, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
MyFree(address);
|
||||
return NULL;
|
||||
}
|
||||
// PRINT_REALLOC("Realloc ", g_allocCount, size, address)
|
||||
#ifdef SZ_ALLOC_DEBUG
|
||||
{
|
||||
void *p = realloc(address, size);
|
||||
if (p)
|
||||
{
|
||||
PRINT_REALLOC("Realloc ", g_allocCount, size, address)
|
||||
}
|
||||
return p;
|
||||
}
|
||||
#else
|
||||
return realloc(address, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void *MidAlloc(size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
#ifdef SZ_ALLOC_DEBUG
|
||||
{
|
||||
void *p = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
if (p)
|
||||
{
|
||||
PRINT_ALLOC("Alloc-Mid", g_allocCountMid, size, p)
|
||||
}
|
||||
return p;
|
||||
}
|
||||
#else
|
||||
return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MidFree(void *address)
|
||||
{
|
||||
PRINT_FREE("Free-Mid", g_allocCountMid, address)
|
||||
|
||||
if (!address)
|
||||
return;
|
||||
VirtualFree(address, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
#ifdef Z7_LARGE_PAGES
|
||||
// #pragma message("Z7_LARGE_PAGES")
|
||||
|
||||
#ifdef MEM_LARGE_PAGES
|
||||
#define MY_MEM_LARGE_PAGES MEM_LARGE_PAGES
|
||||
#else
|
||||
#define MY_MEM_LARGE_PAGES 0x20000000
|
||||
#endif
|
||||
|
||||
extern
|
||||
size_t g_LargePageSize;
|
||||
size_t g_LargePageSize = 0;
|
||||
extern
|
||||
size_t g_LargePageThresholdMin;
|
||||
size_t g_LargePageThresholdMin = 0;
|
||||
extern
|
||||
UInt32 g_LargePageFlags;
|
||||
UInt32 g_LargePageFlags = 0;
|
||||
|
||||
void *BigAlloc(size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
PRINT_ALLOC("Alloc-Big", g_allocCountBig, size, NULL)
|
||||
|
||||
#ifdef Z7_LARGE_PAGES
|
||||
{
|
||||
const size_t ps = g_LargePageSize - 1;
|
||||
if (ps < (1u << 30) && size > g_LargePageThresholdMin)
|
||||
{
|
||||
const size_t size2 = (size + ps) & ~ps;
|
||||
if (size2 >= size)
|
||||
{
|
||||
void *p = VirtualAlloc(NULL, size2, MEM_COMMIT | MY_MEM_LARGE_PAGES, PAGE_READWRITE);
|
||||
if (p)
|
||||
{
|
||||
PRINT_ALLOC("Alloc-BM ", g_allocCountMid, size2, p)
|
||||
return p;
|
||||
}
|
||||
if (g_LargePageFlags & Z7_LARGE_PAGES_FLAG_FAIL_STOP)
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return MidAlloc(size);
|
||||
}
|
||||
|
||||
void BigFree(void *address)
|
||||
{
|
||||
PRINT_FREE("Free-Big", g_allocCountBig, address)
|
||||
MidFree(address);
|
||||
}
|
||||
|
||||
#endif // Z7_LARGE_PAGES
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
static void *SzAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return MyAlloc(size); }
|
||||
static void SzFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) MyFree(address); }
|
||||
const ISzAlloc g_Alloc = { SzAlloc, SzFree };
|
||||
|
||||
#ifdef _WIN32
|
||||
static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return MidAlloc(size); }
|
||||
static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) MidFree(address); }
|
||||
const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree };
|
||||
#endif
|
||||
|
||||
#if defined(Z7_LARGE_PAGES)
|
||||
static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return BigAlloc(size); }
|
||||
static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) BigFree(address); }
|
||||
const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
|
||||
#endif
|
||||
|
||||
#ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR
|
||||
|
||||
#define ADJUST_ALLOC_SIZE 0
|
||||
/*
|
||||
#define ADJUST_ALLOC_SIZE (sizeof(void *) - 1)
|
||||
*/
|
||||
/*
|
||||
Use (ADJUST_ALLOC_SIZE = (sizeof(void *) - 1)), if
|
||||
MyAlloc() can return address that is NOT multiple of sizeof(void *).
|
||||
*/
|
||||
|
||||
/*
|
||||
uintptr_t : <stdint.h> C99 (optional)
|
||||
: unsupported in VS6
|
||||
*/
|
||||
typedef
|
||||
#ifdef _WIN32
|
||||
UINT_PTR
|
||||
#elif 1
|
||||
uintptr_t
|
||||
#else
|
||||
ptrdiff_t
|
||||
#endif
|
||||
MY_uintptr_t;
|
||||
|
||||
#if 0 \
|
||||
|| (defined(__CHERI__) \
|
||||
|| defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ > 8))
|
||||
// for 128-bit pointers (cheri):
|
||||
#define MY_ALIGN_PTR_DOWN(p, align) \
|
||||
((void *)((char *)(p) - ((size_t)(MY_uintptr_t)(p) & ((align) - 1))))
|
||||
#else
|
||||
#define MY_ALIGN_PTR_DOWN(p, align) \
|
||||
((void *)((((MY_uintptr_t)(p)) & ~((MY_uintptr_t)(align) - 1))))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h> // for _POSIX_ADVISORY_INFO : for some linux
|
||||
#if (defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR) \
|
||||
|| defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L) \
|
||||
|| defined(_POSIX_ADVISORY_INFO) && (_POSIX_ADVISORY_INFO >= 200112L) \
|
||||
|| defined(__APPLE__) \
|
||||
/* || defined(__linux__) */)
|
||||
#define USE_posix_memalign
|
||||
// #pragma message("USE_posix_memalign")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef USE_posix_memalign
|
||||
#define MY_ALIGN_PTR_UP_PLUS(p, align) MY_ALIGN_PTR_DOWN(((char *)(p) + (align) + ADJUST_ALLOC_SIZE), align)
|
||||
#endif
|
||||
|
||||
/*
|
||||
This posix_memalign() is for test purposes only.
|
||||
We also need special Free() function instead of free(),
|
||||
if this posix_memalign() is used.
|
||||
*/
|
||||
|
||||
/*
|
||||
static int posix_memalign(void **ptr, size_t align, size_t size)
|
||||
{
|
||||
size_t newSize = size + align;
|
||||
void *p;
|
||||
void *pAligned;
|
||||
*ptr = NULL;
|
||||
if (newSize < size)
|
||||
return 12; // ENOMEM
|
||||
p = MyAlloc(newSize);
|
||||
if (!p)
|
||||
return 12; // ENOMEM
|
||||
pAligned = MY_ALIGN_PTR_UP_PLUS(p, align);
|
||||
((void **)pAligned)[-1] = p;
|
||||
*ptr = pAligned;
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
ALLOC_ALIGN_SIZE >= sizeof(void *)
|
||||
ALLOC_ALIGN_SIZE >= cache_line_size
|
||||
*/
|
||||
|
||||
#define ALLOC_ALIGN_SIZE ((size_t)1 << 7)
|
||||
|
||||
void *z7_AlignedAlloc(size_t size)
|
||||
{
|
||||
#ifndef USE_posix_memalign
|
||||
|
||||
void *p;
|
||||
void *pAligned;
|
||||
size_t newSize;
|
||||
|
||||
/* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned
|
||||
block to prevent cache line sharing with another allocated blocks */
|
||||
|
||||
newSize = size + ALLOC_ALIGN_SIZE * 1 + ADJUST_ALLOC_SIZE;
|
||||
if (newSize < size)
|
||||
return NULL;
|
||||
|
||||
p = MyAlloc(newSize);
|
||||
|
||||
if (!p)
|
||||
return NULL;
|
||||
pAligned = MY_ALIGN_PTR_UP_PLUS(p, ALLOC_ALIGN_SIZE);
|
||||
|
||||
Print(" size="); PrintHex(size, 8);
|
||||
Print(" a_size="); PrintHex(newSize, 8);
|
||||
Print(" ptr="); PrintAddr(p);
|
||||
Print(" a_ptr="); PrintAddr(pAligned);
|
||||
PrintLn();
|
||||
|
||||
((void **)pAligned)[-1] = p;
|
||||
|
||||
return pAligned;
|
||||
|
||||
#else
|
||||
|
||||
void *p;
|
||||
if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size))
|
||||
return NULL;
|
||||
|
||||
Print(" posix_memalign="); PrintAddr(p);
|
||||
PrintLn();
|
||||
|
||||
return p;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void z7_AlignedFree(void *address)
|
||||
{
|
||||
#ifndef USE_posix_memalign
|
||||
if (address)
|
||||
MyFree(((void **)address)[-1]);
|
||||
#else
|
||||
free(address);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size)
|
||||
{
|
||||
UNUSED_VAR(pp)
|
||||
return z7_AlignedAlloc(size);
|
||||
}
|
||||
|
||||
|
||||
static void SzAlignedFree(ISzAllocPtr pp, void *address)
|
||||
{
|
||||
UNUSED_VAR(pp)
|
||||
#ifndef USE_posix_memalign
|
||||
if (address)
|
||||
MyFree(((void **)address)[-1]);
|
||||
#else
|
||||
free(address);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#ifdef Z7_LARGE_PAGES
|
||||
|
||||
#if 0 // 1 for debug
|
||||
#include <stdio.h>
|
||||
#include <string.h> // for strerror()
|
||||
#define PRF(x) x
|
||||
#else
|
||||
#define PRF(x)
|
||||
#endif
|
||||
|
||||
#ifdef USE_posix_memalign
|
||||
/* madvise():
|
||||
glibc <= 2.19 : _BSD_SOURCE
|
||||
glibc > 2.19 : _DEFAULT_SOURCE
|
||||
*/
|
||||
/* && (defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE)) */
|
||||
#if 1 && !defined(Z7_NO_MADVISE) && \
|
||||
(defined(__linux__) || defined(__unix__) || defined(__APPLE__))
|
||||
#include <sys/mman.h> // for madvise
|
||||
// #pragma message("sys/mman.h")
|
||||
#if (defined(MADV_HUGEPAGE) && defined(MADV_NOHUGEPAGE))
|
||||
#define Z7_USE_BIG_ALLOC_MADVISE
|
||||
// #pragma message("Z7_USE_BIG_ALLOC_MADVISE")
|
||||
#endif
|
||||
#endif
|
||||
#endif // USE_posix_memalign
|
||||
|
||||
#ifdef Z7_USE_BIG_ALLOC_MADVISE
|
||||
#define LARGE_PAGE_SIZE_DEFAULT (1 << 21)
|
||||
#else
|
||||
#define LARGE_PAGE_SIZE_DEFAULT 0
|
||||
#endif
|
||||
|
||||
extern
|
||||
size_t g_LargePageSize;
|
||||
size_t g_LargePageSize = LARGE_PAGE_SIZE_DEFAULT;
|
||||
extern
|
||||
size_t g_LargePageThresholdMin;
|
||||
size_t g_LargePageThresholdMin = LARGE_PAGE_SIZE_DEFAULT / 2;
|
||||
extern
|
||||
UInt32 g_LargePageFlags;
|
||||
UInt32 g_LargePageFlags = 0;
|
||||
|
||||
void *BigAlloc(size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
#ifdef USE_posix_memalign
|
||||
{
|
||||
const size_t pageSize = g_LargePageSize;
|
||||
void *buf = NULL; // on Linux (and other systems), posix_memalign() does not modify memptr on failure (POSIX.1-2008 TC2).
|
||||
PRF(printf("\nBigAlloc 0x%08x=%5uMB", (unsigned)(size), (unsigned)(size >> 20));)
|
||||
if (pageSize && size > g_LargePageThresholdMin)
|
||||
{
|
||||
int res;
|
||||
const size_t mask = pageSize - 1;
|
||||
/* we can allocate aligned size, so data at the end of buffer also will use huge page
|
||||
if (size2 for madvise() is not aligned for huge page size)
|
||||
{ Last data block will use small pages. It reduces memory allocation,
|
||||
but last data block with small pages can work slower.
|
||||
It's useful, if we have very large HUGE_PAGE: 32MB or 512MB. }
|
||||
*/
|
||||
size_t size2 = (size + mask) & ~mask;
|
||||
if (size2 < size || (size & mask) <= g_LargePageThresholdMin)
|
||||
size2 = size;
|
||||
res = posix_memalign(&buf, pageSize, size2);
|
||||
PRF(printf(" posix_memalign size=0x%08x=%5uMB align=%u",
|
||||
(unsigned)(size2), (unsigned)(size2 >> 20), (unsigned)pageSize);)
|
||||
PRF(printf(" buf=%p", (void *)buf);)
|
||||
if (res == 0)
|
||||
{
|
||||
#ifdef Z7_USE_BIG_ALLOC_MADVISE
|
||||
if ((g_LargePageFlags & Z7_LARGE_PAGES_FLAG_NO_MADVISE) == 0)
|
||||
{
|
||||
// Advise the kernel to use huge pages for this memory range
|
||||
// MADV_HUGEPAGE / MADV_NOHUGEPAGE : since Linux 2.6.38
|
||||
// madvise() only operates on whole pages, therefore addr must be page-aligned (4KB/8KB/16KB/64KB).
|
||||
// The value of size is rounded up to a multiple of page size.
|
||||
PRF(printf(" madvise g_LargePageFlags=%x", (unsigned)g_LargePageFlags);)
|
||||
res = madvise(buf, size2, (g_LargePageFlags & Z7_LARGE_PAGES_FLAG_NO_HUGEPAGE) ? MADV_NOHUGEPAGE : MADV_HUGEPAGE);
|
||||
if (res)
|
||||
{
|
||||
PRF(printf("\nERROR res=%d, errno=%d=%s\n", res, (int)errno, strerror(errno));)
|
||||
if (g_LargePageFlags & Z7_LARGE_PAGES_FLAG_FAIL_STOP)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // Z7_USE_BIG_ALLOC_MADVISE
|
||||
PRF(printf("\n");)
|
||||
return buf;
|
||||
}
|
||||
PRF(printf("\nERROR res=%d=%s\n", res, strerror(res));)
|
||||
if (g_LargePageFlags & Z7_LARGE_PAGES_FLAG_FAIL_STOP)
|
||||
return NULL;
|
||||
// (res == ENOMEM) "Out of memory" is possible, if pageSize is too big.
|
||||
// so we do second attempt with smaller alignment
|
||||
}
|
||||
}
|
||||
#endif // !USE_posix_memalign
|
||||
PRF(printf(" z7_AlignedAlloc size=0x%08x=%5uMB\n", (unsigned)(size), (unsigned)(size >> 20));)
|
||||
return z7_AlignedAlloc(size);
|
||||
}
|
||||
|
||||
|
||||
void BigFree(void *address)
|
||||
{
|
||||
z7_AlignedFree(address);
|
||||
}
|
||||
#endif // Z7_LARGE_PAGES
|
||||
#endif // !_WIN32
|
||||
|
||||
|
||||
#ifdef Z7_LARGE_PAGES
|
||||
void z7_LargePage_Set(UInt32 flags, size_t pageSize, size_t threshold)
|
||||
{
|
||||
g_LargePageFlags = flags;
|
||||
|
||||
#ifdef _WIN32
|
||||
if ((flags & Z7_LARGE_PAGES_FLAG_USE_HUGEPAGE) == 0)
|
||||
{
|
||||
g_LargePageSize = 0;
|
||||
g_LargePageThresholdMin = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((flags & Z7_LARGE_PAGES_FLAG_DIRECT_PAGE_SIZE) == 0)
|
||||
{
|
||||
#ifdef Z7_USE_DYN_GetLargePageMinimum
|
||||
Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
|
||||
typedef SIZE_T (WINAPI *Func_GetLargePageMinimum)(VOID);
|
||||
const
|
||||
Func_GetLargePageMinimum fn =
|
||||
(Func_GetLargePageMinimum) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
|
||||
"GetLargePageMinimum");
|
||||
if (fn)
|
||||
pageSize = fn();
|
||||
else
|
||||
pageSize = 0;
|
||||
#else
|
||||
pageSize = GetLargePageMinimum();
|
||||
#endif
|
||||
if (pageSize & (pageSize - 1))
|
||||
pageSize = 0;
|
||||
}
|
||||
g_LargePageSize = pageSize;
|
||||
if ((flags & Z7_LARGE_PAGES_FLAG_DIRECT_THRESHOLD) == 0)
|
||||
threshold = pageSize / 2;
|
||||
g_LargePageThresholdMin = threshold;
|
||||
}
|
||||
|
||||
#else // !_WIN32
|
||||
|
||||
if (flags & Z7_LARGE_PAGES_FLAG_NO_PAGECODE)
|
||||
{
|
||||
g_LargePageSize = 0;
|
||||
g_LargePageThresholdMin = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((flags & Z7_LARGE_PAGES_FLAG_DIRECT_PAGE_SIZE) == 0)
|
||||
pageSize = LARGE_PAGE_SIZE_DEFAULT;
|
||||
g_LargePageSize = pageSize;
|
||||
if ((flags & Z7_LARGE_PAGES_FLAG_DIRECT_THRESHOLD) == 0)
|
||||
threshold = pageSize / 2;
|
||||
g_LargePageThresholdMin = threshold;
|
||||
}
|
||||
// PRF(printf("\ng_LargePageSize=%x g_LargePageThresholdMin = %x g_LargePageFlags = %x", (unsigned)g_LargePageSize, (unsigned)g_LargePageThresholdMin, (unsigned)g_LargePageFlags);)
|
||||
#endif // !_WIN32
|
||||
}
|
||||
#endif // Z7_LARGE_PAGES
|
||||
|
||||
const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree };
|
||||
|
||||
|
||||
|
||||
/* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */
|
||||
#ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR
|
||||
#if 1
|
||||
#define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *))
|
||||
#define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1]
|
||||
#else
|
||||
// we can use this simplified code,
|
||||
// if (CAlignOffsetAlloc::offset == (k * sizeof(void *))
|
||||
#define REAL_BLOCK_PTR_VAR(p) (((void **)(p))[-1])
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
#ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR
|
||||
#include <stdio.h>
|
||||
static void PrintPtr(const char *s, const void *p)
|
||||
{
|
||||
const Byte *p2 = (const Byte *)&p;
|
||||
unsigned i;
|
||||
printf("%s %p ", s, p);
|
||||
for (i = sizeof(p); i != 0;)
|
||||
{
|
||||
i--;
|
||||
printf("%02x", p2[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size)
|
||||
{
|
||||
#if defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR)
|
||||
UNUSED_VAR(pp)
|
||||
return z7_AlignedAlloc(size);
|
||||
#else
|
||||
const CAlignOffsetAlloc *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CAlignOffsetAlloc, vt);
|
||||
void *adr;
|
||||
void *pAligned;
|
||||
size_t newSize;
|
||||
size_t extra;
|
||||
size_t alignSize = (size_t)1 << p->numAlignBits;
|
||||
|
||||
if (alignSize < sizeof(void *))
|
||||
alignSize = sizeof(void *);
|
||||
|
||||
if (p->offset >= alignSize)
|
||||
return NULL;
|
||||
|
||||
/* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned
|
||||
block to prevent cache line sharing with another allocated blocks */
|
||||
extra = p->offset & (sizeof(void *) - 1);
|
||||
newSize = size + alignSize + extra + ADJUST_ALLOC_SIZE;
|
||||
if (newSize < size)
|
||||
return NULL;
|
||||
|
||||
adr = ISzAlloc_Alloc(p->baseAlloc, newSize);
|
||||
|
||||
if (!adr)
|
||||
return NULL;
|
||||
|
||||
pAligned = (char *)MY_ALIGN_PTR_DOWN((char *)adr +
|
||||
alignSize - p->offset + extra + ADJUST_ALLOC_SIZE, alignSize) + p->offset;
|
||||
|
||||
#if 0
|
||||
printf("\nalignSize = %6x, offset=%6x, size=%8x \n", (unsigned)alignSize, (unsigned)p->offset, (unsigned)size);
|
||||
PrintPtr("base", adr);
|
||||
PrintPtr("alig", pAligned);
|
||||
#endif
|
||||
|
||||
PrintLn();
|
||||
Print("- Aligned: ");
|
||||
Print(" size="); PrintHex(size, 8);
|
||||
Print(" a_size="); PrintHex(newSize, 8);
|
||||
Print(" ptr="); PrintAddr(adr);
|
||||
Print(" a_ptr="); PrintAddr(pAligned);
|
||||
PrintLn();
|
||||
|
||||
REAL_BLOCK_PTR_VAR(pAligned) = adr;
|
||||
|
||||
return pAligned;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address)
|
||||
{
|
||||
#if defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR)
|
||||
UNUSED_VAR(pp)
|
||||
z7_AlignedFree(address);
|
||||
#else
|
||||
if (address)
|
||||
{
|
||||
const CAlignOffsetAlloc *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CAlignOffsetAlloc, vt);
|
||||
PrintLn();
|
||||
Print("- Aligned Free: ");
|
||||
PrintLn();
|
||||
ISzAlloc_Free(p->baseAlloc, REAL_BLOCK_PTR_VAR(address));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p)
|
||||
{
|
||||
p->vt.Alloc = AlignOffsetAlloc_Alloc;
|
||||
p->vt.Free = AlignOffsetAlloc_Free;
|
||||
}
|
||||
Vendored
+76
@@ -0,0 +1,76 @@
|
||||
/* Alloc.h -- Memory allocation functions
|
||||
: 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);
|
||||
|
||||
void *z7_AlignedAlloc(size_t size);
|
||||
void z7_AlignedFree(void *p);
|
||||
|
||||
extern const ISzAlloc g_Alloc;
|
||||
extern const ISzAlloc g_AlignedAlloc;
|
||||
|
||||
#ifdef _WIN32
|
||||
void *MidAlloc(size_t size);
|
||||
void MidFree(void *address);
|
||||
extern const ISzAlloc g_MidAlloc;
|
||||
#else
|
||||
#define MidAlloc(size) z7_AlignedAlloc(size)
|
||||
#define MidFree(address) z7_AlignedFree(address)
|
||||
#define g_MidAlloc g_AlignedAlloc
|
||||
#endif
|
||||
|
||||
#ifdef Z7_LARGE_PAGES
|
||||
|
||||
#define Z7_LARGE_PAGES_FLAG_USE_HUGEPAGE (1 << 0) // PAGE_ALIGNED / MADV_HUGEPAGE
|
||||
#define Z7_LARGE_PAGES_FLAG_NO_PAGECODE (1 << 1) // no PAGE_ALIGNED / no madvise
|
||||
#define Z7_LARGE_PAGES_FLAG_NO_MADVISE (1 << 2) // PAGE_ALIGNED / no madvise : for THP=always
|
||||
#define Z7_LARGE_PAGES_FLAG_NO_HUGEPAGE (1 << 3) // PAGE_ALIGNED / MADV_NOHUGEPAGE
|
||||
#define Z7_LARGE_PAGES_FLAG_FAIL_STOP (1 << 15) // for benchmarks
|
||||
#define Z7_LARGE_PAGES_FLAG_DIRECT_PAGE_SIZE (1 << 16)
|
||||
#define Z7_LARGE_PAGES_FLAG_DIRECT_THRESHOLD (1 << 17)
|
||||
|
||||
void z7_LargePage_Set(UInt32 flags, size_t pageSize, size_t threshold);
|
||||
|
||||
void *BigAlloc(size_t size);
|
||||
void BigFree(void *address);
|
||||
extern const ISzAlloc g_BigAlloc;
|
||||
#else
|
||||
#define BigAlloc(size) MidAlloc(size)
|
||||
#define BigFree(address) MidFree(address)
|
||||
#define g_BigAlloc g_MidAlloc
|
||||
#endif
|
||||
|
||||
|
||||
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
|
||||
Vendored
+290
@@ -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
|
||||
Vendored
+332
@@ -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
|
||||
Vendored
+709
@@ -0,0 +1,709 @@
|
||||
/* Bra.c -- Branch converters for RISC code
|
||||
2024-01-20 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "Bra.h"
|
||||
#include "RotateDefs.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;
|
||||
#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_ ## 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_2, 0)
|
||||
#else
|
||||
#define Z7_BRANCH_FUNCS_IMP(name) \
|
||||
Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_DEC_2, 0) \
|
||||
Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_ENC_2, 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(BranchConv_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(BranchConv_ARM64)
|
||||
|
||||
|
||||
Z7_BRANCH_FUNC_MAIN(BranchConv_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(BranchConv_ARM)
|
||||
|
||||
|
||||
Z7_BRANCH_FUNC_MAIN(BranchConv_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(BranchConv_PPC)
|
||||
|
||||
|
||||
#ifdef Z7_CPU_FAST_ROTATE_SUPPORTED
|
||||
#define BR_SPARC_USE_ROTATE
|
||||
#endif
|
||||
|
||||
Z7_BRANCH_FUNC_MAIN(BranchConv_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(BranchConv_SPARC)
|
||||
|
||||
|
||||
Z7_BRANCH_FUNC_MAIN(BranchConv_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(BranchConv_ARMT)
|
||||
|
||||
|
||||
// #define BR_IA64_NO_INLINE
|
||||
|
||||
Z7_BRANCH_FUNC_MAIN(BranchConv_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(BranchConv_IA64)
|
||||
|
||||
|
||||
#define BR_CONVERT_VAL_ENC(v) v += BR_PC_GET;
|
||||
#define BR_CONVERT_VAL_DEC(v) v -= BR_PC_GET;
|
||||
|
||||
#if 1 && defined(MY_CPU_LE_UNALIGN)
|
||||
#define RISCV_USE_UNALIGNED_LOAD
|
||||
#endif
|
||||
|
||||
#ifdef RISCV_USE_UNALIGNED_LOAD
|
||||
#define RISCV_GET_UI32(p) GetUi32(p)
|
||||
#define RISCV_SET_UI32(p, v) { SetUi32(p, v) }
|
||||
#else
|
||||
#define RISCV_GET_UI32(p) \
|
||||
((UInt32)GetUi16a(p) + \
|
||||
((UInt32)GetUi16a((p) + 2) << 16))
|
||||
#define RISCV_SET_UI32(p, v) { \
|
||||
SetUi16a(p, (UInt16)(v)) \
|
||||
SetUi16a((p) + 2, (UInt16)(v >> 16)) }
|
||||
#endif
|
||||
|
||||
#if 1 && defined(MY_CPU_LE)
|
||||
#define RISCV_USE_16BIT_LOAD
|
||||
#endif
|
||||
|
||||
#ifdef RISCV_USE_16BIT_LOAD
|
||||
#define RISCV_LOAD_VAL(p) GetUi16a(p)
|
||||
#else
|
||||
#define RISCV_LOAD_VAL(p) (*(p))
|
||||
#endif
|
||||
|
||||
#define RISCV_INSTR_SIZE 2
|
||||
#define RISCV_STEP_1 (4 + RISCV_INSTR_SIZE)
|
||||
#define RISCV_STEP_2 4
|
||||
#define RISCV_REG_VAL (2 << 7)
|
||||
#define RISCV_CMD_VAL 3
|
||||
#if 1
|
||||
// for code size optimization:
|
||||
#define RISCV_DELTA_7F 0x7f
|
||||
#else
|
||||
#define RISCV_DELTA_7F 0
|
||||
#endif
|
||||
|
||||
#define RISCV_CHECK_1(v, b) \
|
||||
(((((b) - RISCV_CMD_VAL) ^ ((v) << 8)) & (0xf8000 + RISCV_CMD_VAL)) == 0)
|
||||
|
||||
#if 1
|
||||
#define RISCV_CHECK_2(v, r) \
|
||||
((((v) - ((RISCV_CMD_VAL << 12) | RISCV_REG_VAL | 8)) \
|
||||
<< 18) \
|
||||
< ((r) & 0x1d))
|
||||
#else
|
||||
// this branch gives larger code, because
|
||||
// compilers generate larger code for big constants.
|
||||
#define RISCV_CHECK_2(v, r) \
|
||||
((((v) - ((RISCV_CMD_VAL << 12) | RISCV_REG_VAL)) \
|
||||
& ((RISCV_CMD_VAL << 12) | RISCV_REG_VAL)) \
|
||||
< ((r) & 0x1d))
|
||||
#endif
|
||||
|
||||
|
||||
#define RISCV_SCAN_LOOP \
|
||||
Byte *lim; \
|
||||
size &= ~(SizeT)(RISCV_INSTR_SIZE - 1); \
|
||||
if (size <= 6) return p; \
|
||||
size -= 6; \
|
||||
lim = p + size; \
|
||||
BR_PC_INIT \
|
||||
for (;;) \
|
||||
{ \
|
||||
UInt32 a, v; \
|
||||
/* Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE */ \
|
||||
for (;;) \
|
||||
{ \
|
||||
if Z7_UNLIKELY(p >= lim) { return p; } \
|
||||
a = (RISCV_LOAD_VAL(p) ^ 0x10u) + 1; \
|
||||
if ((a & 0x77) == 0) break; \
|
||||
a = (RISCV_LOAD_VAL(p + RISCV_INSTR_SIZE) ^ 0x10u) + 1; \
|
||||
p += RISCV_INSTR_SIZE * 2; \
|
||||
if ((a & 0x77) == 0) \
|
||||
{ \
|
||||
p -= RISCV_INSTR_SIZE; \
|
||||
if Z7_UNLIKELY(p >= lim) { return p; } \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
// (xx6f ^ 10) + 1 = xx7f + 1 = xx80 : JAL
|
||||
// (xxef ^ 10) + 1 = xxff + 1 = xx00 + 100 : JAL
|
||||
// (xx17 ^ 10) + 1 = xx07 + 1 = xx08 : AUIPC
|
||||
// (xx97 ^ 10) + 1 = xx87 + 1 = xx88 : AUIPC
|
||||
|
||||
Byte * Z7_BRANCH_CONV_ENC(RISCV)(Byte *p, SizeT size, UInt32 pc)
|
||||
{
|
||||
RISCV_SCAN_LOOP
|
||||
v = a;
|
||||
a = RISCV_GET_UI32(p);
|
||||
#ifndef RISCV_USE_16BIT_LOAD
|
||||
v += (UInt32)p[1] << 8;
|
||||
#endif
|
||||
|
||||
if ((v & 8) == 0) // JAL
|
||||
{
|
||||
if ((v - (0x100 /* - RISCV_DELTA_7F */)) & 0xd80)
|
||||
{
|
||||
p += RISCV_INSTR_SIZE;
|
||||
continue;
|
||||
}
|
||||
{
|
||||
v = ((a & 1u << 31) >> 11)
|
||||
| ((a & 0x3ff << 21) >> 20)
|
||||
| ((a & 1 << 20) >> 9)
|
||||
| (a & 0xff << 12);
|
||||
BR_CONVERT_VAL_ENC(v)
|
||||
// ((v & 1) == 0)
|
||||
// v: bits [1 : 20] contain offset bits
|
||||
#if 0 && defined(RISCV_USE_UNALIGNED_LOAD)
|
||||
a &= 0xfff;
|
||||
a |= ((UInt32)(v << 23))
|
||||
| ((UInt32)(v << 7) & ((UInt32)0xff << 16))
|
||||
| ((UInt32)(v >> 5) & ((UInt32)0xf0 << 8));
|
||||
RISCV_SET_UI32(p, a)
|
||||
#else // aligned
|
||||
#if 0
|
||||
SetUi16a(p, (UInt16)(((v >> 5) & 0xf000) | (a & 0xfff)))
|
||||
#else
|
||||
p[1] = (Byte)(((v >> 13) & 0xf0) | ((a >> 8) & 0xf));
|
||||
#endif
|
||||
|
||||
#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE)
|
||||
v <<= 15;
|
||||
v = Z7_BSWAP32(v);
|
||||
SetUi16a(p + 2, (UInt16)v)
|
||||
#else
|
||||
p[2] = (Byte)(v >> 9);
|
||||
p[3] = (Byte)(v >> 1);
|
||||
#endif
|
||||
#endif // aligned
|
||||
}
|
||||
p += 4;
|
||||
continue;
|
||||
} // JAL
|
||||
|
||||
{
|
||||
// AUIPC
|
||||
if (v & 0xe80) // (not x0) and (not x2)
|
||||
{
|
||||
const UInt32 b = RISCV_GET_UI32(p + 4);
|
||||
if (RISCV_CHECK_1(v, b))
|
||||
{
|
||||
{
|
||||
const UInt32 temp = (b << 12) | (0x17 + RISCV_REG_VAL);
|
||||
RISCV_SET_UI32(p, temp)
|
||||
}
|
||||
a &= 0xfffff000;
|
||||
{
|
||||
#if 1
|
||||
const int t = -1 >> 1;
|
||||
if (t != -1)
|
||||
a += (b >> 20) - ((b >> 19) & 0x1000); // arithmetic right shift emulation
|
||||
else
|
||||
#endif
|
||||
a += (UInt32)((Int32)b >> 20); // arithmetic right shift (sign-extension).
|
||||
}
|
||||
BR_CONVERT_VAL_ENC(a)
|
||||
#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE)
|
||||
a = Z7_BSWAP32(a);
|
||||
RISCV_SET_UI32(p + 4, a)
|
||||
#else
|
||||
SetBe32(p + 4, a)
|
||||
#endif
|
||||
p += 8;
|
||||
}
|
||||
else
|
||||
p += RISCV_STEP_1;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 r = a >> 27;
|
||||
if (RISCV_CHECK_2(v, r))
|
||||
{
|
||||
v = RISCV_GET_UI32(p + 4);
|
||||
r = (r << 7) + 0x17 + (v & 0xfffff000);
|
||||
a = (a >> 12) | (v << 20);
|
||||
RISCV_SET_UI32(p, r)
|
||||
RISCV_SET_UI32(p + 4, a)
|
||||
p += 8;
|
||||
}
|
||||
else
|
||||
p += RISCV_STEP_2;
|
||||
}
|
||||
}
|
||||
} // for
|
||||
}
|
||||
|
||||
|
||||
Byte * Z7_BRANCH_CONV_DEC(RISCV)(Byte *p, SizeT size, UInt32 pc)
|
||||
{
|
||||
RISCV_SCAN_LOOP
|
||||
#ifdef RISCV_USE_16BIT_LOAD
|
||||
if ((a & 8) == 0)
|
||||
{
|
||||
#else
|
||||
v = a;
|
||||
a += (UInt32)p[1] << 8;
|
||||
if ((v & 8) == 0)
|
||||
{
|
||||
#endif
|
||||
// JAL
|
||||
a -= 0x100 - RISCV_DELTA_7F;
|
||||
if (a & 0xd80)
|
||||
{
|
||||
p += RISCV_INSTR_SIZE;
|
||||
continue;
|
||||
}
|
||||
{
|
||||
const UInt32 a_old = (a + (0xef - RISCV_DELTA_7F)) & 0xfff;
|
||||
#if 0 // unaligned
|
||||
a = GetUi32(p);
|
||||
v = (UInt32)(a >> 23) & ((UInt32)0xff << 1)
|
||||
| (UInt32)(a >> 7) & ((UInt32)0xff << 9)
|
||||
#elif 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE)
|
||||
v = GetUi16a(p + 2);
|
||||
v = Z7_BSWAP32(v) >> 15
|
||||
#else
|
||||
v = (UInt32)p[3] << 1
|
||||
| (UInt32)p[2] << 9
|
||||
#endif
|
||||
| (UInt32)((a & 0xf000) << 5);
|
||||
BR_CONVERT_VAL_DEC(v)
|
||||
a = a_old
|
||||
| (v << 11 & 1u << 31)
|
||||
| (v << 20 & 0x3ff << 21)
|
||||
| (v << 9 & 1 << 20)
|
||||
| (v & 0xff << 12);
|
||||
RISCV_SET_UI32(p, a)
|
||||
}
|
||||
p += 4;
|
||||
continue;
|
||||
} // JAL
|
||||
|
||||
{
|
||||
// AUIPC
|
||||
v = a;
|
||||
#if 1 && defined(RISCV_USE_UNALIGNED_LOAD)
|
||||
a = GetUi32(p);
|
||||
#else
|
||||
a |= (UInt32)GetUi16a(p + 2) << 16;
|
||||
#endif
|
||||
if ((v & 0xe80) == 0) // x0/x2
|
||||
{
|
||||
const UInt32 r = a >> 27;
|
||||
if (RISCV_CHECK_2(v, r))
|
||||
{
|
||||
UInt32 b;
|
||||
#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE)
|
||||
b = RISCV_GET_UI32(p + 4);
|
||||
b = Z7_BSWAP32(b);
|
||||
#else
|
||||
b = GetBe32(p + 4);
|
||||
#endif
|
||||
v = a >> 12;
|
||||
BR_CONVERT_VAL_DEC(b)
|
||||
a = (r << 7) + 0x17;
|
||||
a += (b + 0x800) & 0xfffff000;
|
||||
v |= b << 20;
|
||||
RISCV_SET_UI32(p, a)
|
||||
RISCV_SET_UI32(p + 4, v)
|
||||
p += 8;
|
||||
}
|
||||
else
|
||||
p += RISCV_STEP_2;
|
||||
}
|
||||
else
|
||||
{
|
||||
const UInt32 b = RISCV_GET_UI32(p + 4);
|
||||
if (!RISCV_CHECK_1(v, b))
|
||||
p += RISCV_STEP_1;
|
||||
else
|
||||
{
|
||||
v = (a & 0xfffff000) | (b >> 20);
|
||||
a = (b << 12) | (0x17 + RISCV_REG_VAL);
|
||||
RISCV_SET_UI32(p, a)
|
||||
RISCV_SET_UI32(p + 4, v)
|
||||
p += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // for
|
||||
}
|
||||
Vendored
+105
@@ -0,0 +1,105 @@
|
||||
/* Bra.h -- Branch converters for executables
|
||||
2024-01-20 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef ZIP7_INC_BRA_H
|
||||
#define ZIP7_INC_BRA_H
|
||||
|
||||
#include "7zTypes.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
/* #define PPC BAD_PPC_11 // for debug */
|
||||
|
||||
#define Z7_BRANCH_CONV_DEC_2(name) z7_ ## name ## _Dec
|
||||
#define Z7_BRANCH_CONV_ENC_2(name) z7_ ## name ## _Enc
|
||||
#define Z7_BRANCH_CONV_DEC(name) Z7_BRANCH_CONV_DEC_2(BranchConv_ ## name)
|
||||
#define Z7_BRANCH_CONV_ENC(name) Z7_BRANCH_CONV_ENC_2(BranchConv_ ## name)
|
||||
#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_2(name)); \
|
||||
Z7_BRANCH_CONV_DECL (Z7_BRANCH_CONV_ENC_2(name));
|
||||
|
||||
Z7_BRANCH_FUNCS_DECL (BranchConv_ARM64)
|
||||
Z7_BRANCH_FUNCS_DECL (BranchConv_ARM)
|
||||
Z7_BRANCH_FUNCS_DECL (BranchConv_ARMT)
|
||||
Z7_BRANCH_FUNCS_DECL (BranchConv_PPC)
|
||||
Z7_BRANCH_FUNCS_DECL (BranchConv_SPARC)
|
||||
Z7_BRANCH_FUNCS_DECL (BranchConv_IA64)
|
||||
Z7_BRANCH_FUNCS_DECL (BranchConv_RISCV)
|
||||
|
||||
/*
|
||||
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 Pointer) 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
|
||||
RISCV little 2 6
|
||||
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
|
||||
Vendored
+187
@@ -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
|
||||
Vendored
+14
@@ -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
|
||||
Vendored
+287
@@ -0,0 +1,287 @@
|
||||
/* Compiler.h : Compiler specific defines and pragmas
|
||||
: 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
|
||||
|
||||
#if defined(__LCC__) && (defined(__MCST__) || defined(__e2k__))
|
||||
#define Z7_MCST_LCC
|
||||
#define Z7_MCST_LCC_VERSION (__LCC__ * 100 + __LCC_MINOR__)
|
||||
#endif
|
||||
|
||||
/*
|
||||
#if defined(__AVX2__) \
|
||||
|| defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) \
|
||||
|| defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 40600) \
|
||||
|| defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30100) \
|
||||
|| defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1800) \
|
||||
|| defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1400)
|
||||
#define Z7_COMPILER_AVX2_SUPPORTED
|
||||
#endif
|
||||
#endif
|
||||
*/
|
||||
|
||||
// #pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||
|
||||
#ifdef __clang__
|
||||
// padding size of '' with 4 bytes to alignment boundary
|
||||
#pragma GCC diagnostic ignored "-Wpadded"
|
||||
|
||||
#if defined(Z7_LLVM_CLANG_VERSION) && (__clang_major__ == 13) \
|
||||
&& defined(__FreeBSD__)
|
||||
// freebsd:
|
||||
#pragma GCC diagnostic ignored "-Wexcess-padding"
|
||||
#endif
|
||||
|
||||
#if defined(Z7_APPLE_CLANG_VERSION) && __clang_major__ >= 21
|
||||
// warning: function MyAlloc might be an allocator wrapper
|
||||
// clang in xcode: clang 21.0.0
|
||||
#pragma GCC diagnostic ignored "-Wallocator-wrappers"
|
||||
#endif
|
||||
|
||||
#if __clang_major__ >= 16
|
||||
#pragma GCC diagnostic ignored "-Wunsafe-buffer-usage"
|
||||
#endif
|
||||
|
||||
#if __clang_major__ == 13
|
||||
#if defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 16)
|
||||
// cheri
|
||||
#pragma GCC diagnostic ignored "-Wcapability-to-integer-cast"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if __clang_major__ == 13
|
||||
// for <arm_neon.h>
|
||||
#pragma GCC diagnostic ignored "-Wreserved-identifier"
|
||||
#endif
|
||||
|
||||
#if __clang_major__ >= 22
|
||||
// for "StdAfx.h" and "Precomp.h"
|
||||
#pragma GCC diagnostic ignored "-Wshadow-header"
|
||||
#endif
|
||||
|
||||
#endif // __clang__
|
||||
|
||||
#if defined(__clang__) && __clang_major__ >= 16
|
||||
// #pragma GCC diagnostic ignored "-Wcast-function-type-strict"
|
||||
#define Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION \
|
||||
_Pragma("GCC diagnostic ignored \"-Wcast-function-type-strict\"")
|
||||
#else
|
||||
#define Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
|
||||
#endif
|
||||
|
||||
typedef void (*Z7_void_Function)(void);
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#define Z7_CAST_FUNC_C (Z7_void_Function)
|
||||
#elif defined(_MSC_VER) && _MSC_VER > 1920
|
||||
#define Z7_CAST_FUNC_C (void *)
|
||||
// #pragma warning(disable : 4191) // 'type cast': unsafe conversion from 'FARPROC' to 'void (__cdecl *)()'
|
||||
#else
|
||||
#define Z7_CAST_FUNC_C
|
||||
#endif
|
||||
/*
|
||||
#if (defined(__GNUC__) && (__GNUC__ >= 8)) || defined(__clang__)
|
||||
// #pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
#endif
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
#if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40000) && (Z7_GCC_VERSION < 70000)
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
#endif
|
||||
#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
|
||||
|
||||
// #define Z7_ANALYZE_MODE
|
||||
#if defined(Z7_ANALYZE_MODE) // && defined(Z7_MSC_VER_ORIGINAL)
|
||||
// for -analyze switch:
|
||||
#if _MSC_VER >= 1900
|
||||
#pragma warning(disable : 6001) // Using uninitialized memory 'ps'.
|
||||
#pragma warning(disable : 6031) // Return value ignored: 'CoInitialize'
|
||||
#pragma warning(disable : 6553) // The annotation for function 'RegOpenKeyExW' on _Param_(3) does not apply to a value type.
|
||||
#pragma warning(disable : 28159) // Random.cpp(21) : Consider using 'GetTickCount64' instead of 'GetTickCount'
|
||||
#pragma warning(disable : 28160) // ProcessUtils.h(92) : Error annotation: Passing MEM_RELEASE and a non-zero dwSize parameter to VirtualFree is not allowed. This results in the failure of this call
|
||||
#pragma warning(disable : 28251) // Inconsistent annotation for 'WinMain': this instance has no annotations. See c:\program files (x86)\windows kits\10\include\10.0.26100.0\um\winbase.h(1062).
|
||||
#pragma warning(disable : 28286) // um\consoleapi.h(236) : For function 'ReadConsoleW', error near the end of 'SAL_readableTo(byteCount(*__formal(3,lpNumberOfCharsRead) * sizeof(TCHAR%)))'.
|
||||
#pragma warning(disable : 28301) // No annotations for first declaration of 'PNTSTATUS'. See c:\program files (x86)\windows kits\10\include\10.0.26100.0\shared\bcrypt.h(40).
|
||||
#endif
|
||||
#if _MSC_VER >= 1600
|
||||
#pragma warning(disable : 6011) // Dereferencing NULL pointer 'p->IsDirs'
|
||||
#pragma warning(disable : 6255) // `_alloca` indicates failure by raising a stack overflow exception. Consider using _malloca instead.
|
||||
#pragma warning(disable : 6258) // Using TerminateThread does not allow proper thread clean up.
|
||||
// #pragma warning(disable : 6262) // SfxSetup.c : Function uses '32808' bytes of stack.
|
||||
#pragma warning(disable : 6320) // Threads.c : Exception-filter expression is the constant EXCEPTION_EXECUTE_HANDLER. This might mask exceptions that were not intended to be handled.
|
||||
#pragma warning(disable : 6385) // createcoder.cpp : Invalid data: accessing 'struct CCodecInfo const * * g_Codecs', the readable size is '256' bytes, but '4194244' bytes might be read: Lines: 338, 339, 340, 342, 344
|
||||
#pragma warning(disable : 6387) // MyString.cpp : 's' could be '0': this does not adhere to the specification for the function 'wmemcpy'
|
||||
#endif
|
||||
#if _MSC_VER == 1600
|
||||
#pragma warning(disable : 6200) // compressdialog.cpp : Index '31' is out of valid index range '0' to '9' for non-stack buffer 'g_Levels'
|
||||
#pragma warning(disable : 6204) // Possible buffer overrun in call to 'memset': use of unchecked parameter 'size'
|
||||
#pragma warning(disable : 6309) // Argument '1' is null: this does not adhere to function specification of 'GetProcAddress'
|
||||
#pragma warning(disable : 6386) // myvector.h : Buffer overrun: accessing 'argument 1', the writable size is 'newCapacity*4' bytes, but '8' bytes might be written
|
||||
#endif
|
||||
#endif // Z7_ANALYZE_MODE
|
||||
|
||||
// == 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) \
|
||||
&& (!defined(Z7_MCST_LCC_VERSION) || (Z7_MCST_LCC_VERSION >= 12610))
|
||||
#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(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1920)
|
||||
#define Z7_PRAGMA_OPTIMIZE_FOR_CODE_SIZE _Pragma("optimize ( \"s\", on )")
|
||||
#define Z7_PRAGMA_OPTIMIZE_DEFAULT _Pragma("optimize ( \"\", on )")
|
||||
#else
|
||||
#define Z7_PRAGMA_OPTIMIZE_FOR_CODE_SIZE
|
||||
#define Z7_PRAGMA_OPTIMIZE_DEFAULT
|
||||
#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 >= 30600))
|
||||
|
||||
#if (Z7_CLANG_VERSION < 130000)
|
||||
#define Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wreserved-id-macro\"")
|
||||
#else
|
||||
#define Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wreserved-macro-identifier\"")
|
||||
#endif
|
||||
|
||||
#define Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER \
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#else
|
||||
#define Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
|
||||
#define Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
|
||||
#endif
|
||||
|
||||
#define UNUSED_VAR(x) (void)x;
|
||||
/* #define UNUSED_VAR(x) x=x; */
|
||||
|
||||
#endif
|
||||
Vendored
+970
@@ -0,0 +1,970 @@
|
||||
/* CpuArch.c -- CPU specific code
|
||||
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.
|
||||
most functions 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__))
|
||||
|
||||
/* "=&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"(subFun) : 2 is (zero-based) index in the output constraint list "=c" (ECX). */
|
||||
|
||||
#define x86_cpuid_MACRO_2(p, func, subFunc) { \
|
||||
__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"(subFunc)); }
|
||||
|
||||
#elif defined(MY_CPU_X86) && defined(__PIC__) \
|
||||
&& ((defined (__GNUC__) && (__GNUC__ < 5)) || defined(__clang__))
|
||||
|
||||
#define x86_cpuid_MACRO_2(p, func, subFunc) { \
|
||||
__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"(subFunc)); }
|
||||
|
||||
#else
|
||||
|
||||
#define x86_cpuid_MACRO_2(p, func, subFunc) { \
|
||||
__asm__ __volatile__ ( \
|
||||
ASM_LN "cpuid" \
|
||||
: "=a" ((p)[0]), "=b" ((p)[1]), "=c" ((p)[2]), "=d" ((p)[3]) : "0" (func), "2"(subFunc)); }
|
||||
|
||||
#endif
|
||||
|
||||
#define x86_cpuid_MACRO(p, func) x86_cpuid_MACRO_2(p, func, 0)
|
||||
|
||||
void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func)
|
||||
{
|
||||
x86_cpuid_MACRO(p, func)
|
||||
}
|
||||
|
||||
static
|
||||
void Z7_FASTCALL z7_x86_cpuid_subFunc(UInt32 p[4], UInt32 func, UInt32 subFunc)
|
||||
{
|
||||
x86_cpuid_MACRO_2(p, func, subFunc)
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
static
|
||||
void __declspec(naked) Z7_FASTCALL z7_x86_cpuid_subFunc(UInt32 p[4], UInt32 func, UInt32 subFunc)
|
||||
{
|
||||
UNUSED_VAR(p)
|
||||
UNUSED_VAR(func)
|
||||
UNUSED_VAR(subFunc)
|
||||
__asm push ebx
|
||||
__asm push edi
|
||||
__asm mov edi, ecx // p
|
||||
__asm mov eax, edx // func
|
||||
__asm mov ecx, [esp + 12] // subFunc
|
||||
__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 4
|
||||
}
|
||||
|
||||
#else // MY_CPU_AMD64
|
||||
|
||||
#if _MSC_VER >= 1600
|
||||
#include <intrin.h>
|
||||
#define MY_cpuidex __cpuidex
|
||||
|
||||
static
|
||||
void Z7_FASTCALL z7_x86_cpuid_subFunc(UInt32 p[4], UInt32 func, UInt32 subFunc)
|
||||
{
|
||||
__cpuidex((int *)p, func, subFunc);
|
||||
}
|
||||
|
||||
#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(Int32 subFunction, Int32 func, Int32 *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 ========")
|
||||
static
|
||||
void Z7_FASTCALL z7_x86_cpuid_subFunc(UInt32 p[4], UInt32 func, UInt32 subFunc)
|
||||
{
|
||||
MY_cpuidex_HACK(subFunc, func, (Int32 *)p);
|
||||
}
|
||||
#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((Int32 *)p, (Int32)func, 0);
|
||||
}
|
||||
|
||||
Z7_NO_INLINE
|
||||
UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void)
|
||||
{
|
||||
Int32 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 (BoolInt)(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 (BoolInt)(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 (BoolInt)(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 (BoolInt)(x86cpuid_Func_1_ECX() >> 25) & 1;
|
||||
}
|
||||
|
||||
BoolInt CPU_IsSupported_SSSE3(void)
|
||||
{
|
||||
return (BoolInt)(x86cpuid_Func_1_ECX() >> 9) & 1;
|
||||
}
|
||||
|
||||
BoolInt CPU_IsSupported_SSE41(void)
|
||||
{
|
||||
return (BoolInt)(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 (BoolInt)(d[1] >> 29) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BoolInt CPU_IsSupported_SHA512(void)
|
||||
{
|
||||
if (!CPU_IsSupported_AVX2()) return False; // maybe CPU_IsSupported_AVX() is enough here
|
||||
|
||||
if (z7_x86_cpuid_GetMaxFunc() < 7)
|
||||
return False;
|
||||
{
|
||||
UInt32 d[4];
|
||||
z7_x86_cpuid_subFunc(d, 7, 0);
|
||||
if (d[0] < 1) // d[0] - is max supported subleaf value
|
||||
return False;
|
||||
z7_x86_cpuid_subFunc(d, 7, 1);
|
||||
return (BoolInt)(d[0]) & 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=0x%x\n", bm);
|
||||
return 1
|
||||
& (BoolInt)(bm >> 1) // SSE state is supported (set by OS) for storing/restoring
|
||||
& (BoolInt)(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
|
||||
& (BoolInt)(d[1] >> 5); // avx2
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
BoolInt CPU_IsSupported_AVX512F_AVX512VL(void)
|
||||
{
|
||||
if (!CPU_IsSupported_AVX())
|
||||
return False;
|
||||
if (z7_x86_cpuid_GetMaxFunc() < 7)
|
||||
return False;
|
||||
{
|
||||
UInt32 d[4];
|
||||
BoolInt v;
|
||||
z7_x86_cpuid(d, 7);
|
||||
// printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]);
|
||||
v = 1
|
||||
& (BoolInt)(d[1] >> 16) // avx512f
|
||||
& (BoolInt)(d[1] >> 31); // avx512vl
|
||||
if (!v)
|
||||
return False;
|
||||
}
|
||||
{
|
||||
const UInt32 bm = (UInt32)x86_xgetbv_0(MY_XCR_XFEATURE_ENABLED_MASK);
|
||||
// printf("\n=== XGetBV=0x%x\n", bm);
|
||||
return 1
|
||||
& (BoolInt)(bm >> 5) // OPMASK
|
||||
& (BoolInt)(bm >> 6) // ZMM upper 256-bit
|
||||
& (BoolInt)(bm >> 7); // ZMM16 ... ZMM31
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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
|
||||
& (BoolInt)(d[1] >> 5) // avx2
|
||||
// & (d[1] >> 31) // avx512vl
|
||||
& (BoolInt)(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 (BoolInt)(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");
|
||||
}
|
||||
|
||||
BoolInt CPU_IsSupported_SHA512(void)
|
||||
{
|
||||
return z7_sysctlbyname_Get_BoolInt("hw.optional.armv8_2_sha512");
|
||||
}
|
||||
|
||||
/*
|
||||
BoolInt CPU_IsSupported_SHA3(void)
|
||||
{
|
||||
return z7_sysctlbyname_Get_BoolInt("hw.optional.armv8_2_sha3");
|
||||
}
|
||||
*/
|
||||
|
||||
#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__
|
||||
|
||||
#if defined(__GLIBC__) && (__GLIBC__ * 100 + __GLIBC_MINOR__ >= 216)
|
||||
#define Z7_GETAUXV_AVAILABLE
|
||||
#elif !defined(__QNXNTO__)
|
||||
// #pragma message("=== is not NEW GLIBC === ")
|
||||
#if defined __has_include
|
||||
#if __has_include (<sys/auxv.h>)
|
||||
// #pragma message("=== sys/auxv.h is avail=== ")
|
||||
#define Z7_GETAUXV_AVAILABLE
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef Z7_GETAUXV_AVAILABLE
|
||||
// #pragma message("=== Z7_GETAUXV_AVAILABLE === ")
|
||||
#include <sys/auxv.h>
|
||||
#define USE_HWCAP
|
||||
#endif
|
||||
|
||||
#ifdef USE_HWCAP
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
static unsigned long MY_getauxval(int aux)
|
||||
{
|
||||
unsigned long val;
|
||||
if (elf_aux_info(aux, &val, sizeof(val)))
|
||||
return 0;
|
||||
return val;
|
||||
}
|
||||
#else
|
||||
#define MY_getauxval getauxval
|
||||
#if defined __has_include
|
||||
#if __has_include (<asm/hwcap.h>)
|
||||
#include <asm/hwcap.h>
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define MY_HWCAP_CHECK_FUNC_2(name1, name2) \
|
||||
BoolInt CPU_IsSupported_ ## name1(void) { return (MY_getauxval(AT_HWCAP) & (HWCAP_ ## name2)); }
|
||||
|
||||
#ifdef MY_CPU_ARM64
|
||||
#define MY_HWCAP_CHECK_FUNC(name) \
|
||||
MY_HWCAP_CHECK_FUNC_2(name, name)
|
||||
#if 1 || defined(__ARM_NEON)
|
||||
BoolInt CPU_IsSupported_NEON(void) { return True; }
|
||||
#else
|
||||
MY_HWCAP_CHECK_FUNC_2(NEON, ASIMD)
|
||||
#endif
|
||||
// MY_HWCAP_CHECK_FUNC (ASIMD)
|
||||
#elif defined(MY_CPU_ARM)
|
||||
#define MY_HWCAP_CHECK_FUNC(name) \
|
||||
BoolInt CPU_IsSupported_ ## name(void) { return (MY_getauxval(AT_HWCAP2) & (HWCAP2_ ## name)); }
|
||||
MY_HWCAP_CHECK_FUNC_2(NEON, NEON)
|
||||
#endif
|
||||
|
||||
#else // USE_HWCAP
|
||||
|
||||
#define MY_HWCAP_CHECK_FUNC(name) \
|
||||
BoolInt CPU_IsSupported_ ## name(void) { return 0; }
|
||||
#if defined(__ARM_NEON)
|
||||
BoolInt CPU_IsSupported_NEON(void) { return True; }
|
||||
#else
|
||||
MY_HWCAP_CHECK_FUNC(NEON)
|
||||
#endif
|
||||
|
||||
#endif // USE_HWCAP
|
||||
|
||||
MY_HWCAP_CHECK_FUNC (CRC32)
|
||||
MY_HWCAP_CHECK_FUNC (SHA1)
|
||||
MY_HWCAP_CHECK_FUNC (SHA2)
|
||||
MY_HWCAP_CHECK_FUNC (AES)
|
||||
#ifdef MY_CPU_ARM64
|
||||
// <hwcap.h> supports HWCAP_SHA512 and HWCAP_SHA3 since 2017.
|
||||
// we define them here, if they are not defined
|
||||
#ifndef HWCAP_SHA3
|
||||
// #define HWCAP_SHA3 (1 << 17)
|
||||
#endif
|
||||
#ifndef HWCAP_SHA512
|
||||
// #pragma message("=== HWCAP_SHA512 define === ")
|
||||
#define HWCAP_SHA512 (1 << 21)
|
||||
#endif
|
||||
MY_HWCAP_CHECK_FUNC (SHA512)
|
||||
// MY_HWCAP_CHECK_FUNC (SHA3)
|
||||
#endif
|
||||
|
||||
#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
|
||||
Vendored
+715
@@ -0,0 +1,715 @@
|
||||
/* CpuArch.h -- CPU specific code
|
||||
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_ARM64EC)
|
||||
#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
|
||||
#if defined(__APX_EGPR__) || defined(__EGPR__)
|
||||
#define MY_CPU_NAME "x64-apx"
|
||||
#define MY_CPU_AMD64_APX
|
||||
#else
|
||||
#define MY_CPU_NAME "x64"
|
||||
#endif
|
||||
#define MY_CPU_SIZEOF_POINTER 8
|
||||
#endif
|
||||
#define MY_CPU_64BIT
|
||||
#endif
|
||||
#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(__SSE2__) \
|
||||
|| defined(MY_CPU_AMD64) \
|
||||
|| defined(_M_IX86_FP) && (_M_IX86_FP >= 2)
|
||||
#define MY_CPU_SSE2
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_M_ARM64) \
|
||||
|| defined(_M_ARM64EC) \
|
||||
|| defined(__AARCH64EL__) \
|
||||
|| defined(__AARCH64EB__) \
|
||||
|| defined(__aarch64__)
|
||||
#define MY_CPU_ARM64
|
||||
#if defined(__ILP32__) \
|
||||
|| defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 4)
|
||||
#define MY_CPU_NAME "arm64-32"
|
||||
#define MY_CPU_SIZEOF_POINTER 4
|
||||
#elif defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 16)
|
||||
#define MY_CPU_NAME "arm64-128"
|
||||
#define MY_CPU_SIZEOF_POINTER 16
|
||||
#else
|
||||
#if defined(_M_ARM64EC)
|
||||
#define MY_CPU_NAME "arm64ec"
|
||||
#else
|
||||
#define MY_CPU_NAME "arm64"
|
||||
#endif
|
||||
#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(__sparc__) \
|
||||
|| defined(__sparc)
|
||||
#define MY_CPU_SPARC
|
||||
#if defined(__LP64__) \
|
||||
|| defined(_LP64) \
|
||||
|| defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 8)
|
||||
#define MY_CPU_NAME "sparcv9"
|
||||
#define MY_CPU_SIZEOF_POINTER 8
|
||||
#define MY_CPU_64BIT
|
||||
#elif defined(__sparc_v9__) \
|
||||
|| defined(__sparcv9)
|
||||
#define MY_CPU_64BIT
|
||||
#if defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 4)
|
||||
#define MY_CPU_NAME "sparcv9-32"
|
||||
#else
|
||||
#define MY_CPU_NAME "sparcv9m"
|
||||
#endif
|
||||
#elif defined(__sparc_v8__) \
|
||||
|| defined(__sparcv8)
|
||||
#define MY_CPU_NAME "sparcv8"
|
||||
#define MY_CPU_SIZEOF_POINTER 4
|
||||
#else
|
||||
#define MY_CPU_NAME "sparc"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__riscv) \
|
||||
|| defined(__riscv__)
|
||||
#define MY_CPU_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(__loongarch__)
|
||||
#define MY_CPU_LOONGARCH
|
||||
#if defined(__loongarch64) || defined(__loongarch_grlen) && (__loongarch_grlen == 64)
|
||||
#define MY_CPU_64BIT
|
||||
#endif
|
||||
#if defined(__loongarch64)
|
||||
#define MY_CPU_NAME "loongarch64"
|
||||
#define MY_CPU_LOONGARCH64
|
||||
#else
|
||||
#define MY_CPU_NAME "loongarch"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__s390__)
|
||||
#if defined(__s390x__) || defined(__LP64__) || (defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8)
|
||||
#define MY_CPU_NAME "s390x"
|
||||
#define MY_CPU_SIZEOF_POINTER 8
|
||||
#else
|
||||
#define MY_CPU_NAME "s390"
|
||||
#define MY_CPU_SIZEOF_POINTER 4
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// #undef MY_CPU_NAME
|
||||
// #undef MY_CPU_SIZEOF_POINTER
|
||||
// #define __e2k__
|
||||
// #define __SIZEOF_POINTER__ 4
|
||||
#if defined(__e2k__)
|
||||
#define MY_CPU_E2K
|
||||
#if defined(__ILP32__) || defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 4)
|
||||
#define MY_CPU_NAME "e2k-32"
|
||||
#define MY_CPU_SIZEOF_POINTER 4
|
||||
#else
|
||||
#define MY_CPU_NAME "e2k"
|
||||
#if defined(__LP64__) || defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 8)
|
||||
#define MY_CPU_SIZEOF_POINTER 8
|
||||
#endif
|
||||
#endif
|
||||
#define MY_CPU_64BIT
|
||||
#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
|
||||
|
||||
|
||||
// _LITTLE_ENDIAN macro can be defined for big-endian platform with some compilers
|
||||
|
||||
#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
|
||||
// #define MY_CPU_IS_UNKNOWN
|
||||
#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
|
||||
|
||||
/* GCC can generate slow code that calls function for __builtin_bswap32() for:
|
||||
- GCC for RISCV, if Zbb/XTHeadBb extension is not used.
|
||||
- GCC for SPARC.
|
||||
The code from CLANG for SPARC also is not fastest.
|
||||
So we don't define Z7_CPU_FAST_BSWAP_SUPPORTED in some cases.
|
||||
*/
|
||||
#elif (!defined(MY_CPU_RISCV) || defined (__riscv_zbb) || defined(__riscv_xtheadbb)) \
|
||||
&& !defined(MY_CPU_SPARC) \
|
||||
&& ( \
|
||||
(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) \
|
||||
|| defined(MY_CPU_RISCV) && defined(__riscv_misaligned_fast) \
|
||||
|| defined(MY_CPU_E2K) && defined(__iset__) && (__iset__ >= 6)
|
||||
#define MY_CPU_LE_UNALIGN
|
||||
#define MY_CPU_LE_UNALIGN_64
|
||||
#elif defined(__ARM_FEATURE_UNALIGNED)
|
||||
/* === ALIGNMENT on 32-bit arm and LDRD/STRD/LDM/STM instructions.
|
||||
Description of problems:
|
||||
problem-1 : 32-bit ARM architecture:
|
||||
multi-access (pair of 32-bit accesses) instructions (LDRD/STRD/LDM/STM)
|
||||
require 32-bit (WORD) alignment (by 32-bit ARM architecture).
|
||||
So there is "Alignment fault exception", if data is not aligned for 32-bit.
|
||||
|
||||
problem-2 : 32-bit kernels and arm64 kernels:
|
||||
32-bit linux kernels provide fixup for these "paired" instruction "Alignment fault exception".
|
||||
So unaligned paired-access instructions work via exception handler in kernel in 32-bit linux.
|
||||
|
||||
But some arm64 kernels do not handle these faults in 32-bit programs.
|
||||
So we have unhandled exception for such instructions.
|
||||
Probably some new arm64 kernels have fixed it, and unaligned
|
||||
paired-access instructions work in new kernels?
|
||||
|
||||
problem-3 : compiler for 32-bit arm:
|
||||
Compilers use LDRD/STRD/LDM/STM for UInt64 accesses
|
||||
and for another cases where two 32-bit accesses are fused
|
||||
to one multi-access instruction.
|
||||
So UInt64 variables must be aligned for 32-bit, and each
|
||||
32-bit access must be aligned for 32-bit, if we want to
|
||||
avoid "Alignment fault" exception (handled or unhandled).
|
||||
|
||||
problem-4 : performace:
|
||||
Even if unaligned access is handled by kernel, it will be slow.
|
||||
So if we allow unaligned access, we can get fast unaligned
|
||||
single-access, and slow unaligned paired-access.
|
||||
|
||||
We don't allow unaligned access on 32-bit arm, because compiler
|
||||
genarates paired-access instructions that require 32-bit alignment,
|
||||
and some arm64 kernels have no handler for these instructions.
|
||||
Also unaligned paired-access instructions will be slow, if kernel handles them.
|
||||
*/
|
||||
// it must be disabled:
|
||||
// #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)
|
||||
|
||||
#if 0
|
||||
// Z7_BSWAP16 can be slow for x86-msvc
|
||||
#define GetBe16_to32(p) (Z7_BSWAP16 (*(const UInt16 *)(const void *)(p)))
|
||||
#else
|
||||
#define GetBe16_to32(p) (Z7_BSWAP32 (*(const UInt16 *)(const void *)(p)) >> 16)
|
||||
#endif
|
||||
|
||||
#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))
|
||||
#define SetBe64(p, v) { (*(UInt64 *)(void *)(p)) = Z7_BSWAP64(v); }
|
||||
#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 SetBe64
|
||||
#define SetBe64(p, v) { Byte *_ppp_ = (Byte *)(p); UInt64 _vvv_ = (v); \
|
||||
_ppp_[0] = (Byte)(_vvv_ >> 56); \
|
||||
_ppp_[1] = (Byte)(_vvv_ >> 48); \
|
||||
_ppp_[2] = (Byte)(_vvv_ >> 40); \
|
||||
_ppp_[3] = (Byte)(_vvv_ >> 32); \
|
||||
_ppp_[4] = (Byte)(_vvv_ >> 24); \
|
||||
_ppp_[5] = (Byte)(_vvv_ >> 16); \
|
||||
_ppp_[6] = (Byte)(_vvv_ >> 8); \
|
||||
_ppp_[7] = (Byte)_vvv_; }
|
||||
#endif
|
||||
|
||||
#ifndef GetBe16
|
||||
#ifdef GetBe16_to32
|
||||
#define GetBe16(p) ( (UInt16) GetBe16_to32(p))
|
||||
#else
|
||||
#define GetBe16(p) ( (UInt16) ( \
|
||||
((UInt16)((const Byte *)(p))[0] << 8) | \
|
||||
((const Byte *)(p))[1] ))
|
||||
#endif
|
||||
#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)
|
||||
// #define Z7_GET_NATIVE16_FROM_2_BYTES(b0, b1) ((b1) | ((b0) << 8))
|
||||
#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)
|
||||
// #define Z7_GET_NATIVE16_FROM_2_BYTES(b0, b1) ((b0) | ((b1) << 8))
|
||||
#else
|
||||
#error Stop_Compiling_Unknown_Endian_CONV
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(MY_CPU_BE)
|
||||
|
||||
#define GetBe64a(p) (*(const UInt64 *)(const void *)(p))
|
||||
#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); }
|
||||
|
||||
// gcc and clang for powerpc can transform load byte access to load reverse word access.
|
||||
// sp we can use byte access instead of word access. Z7_BSWAP64 cab be slow
|
||||
#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_64BIT)
|
||||
#define GetUi64a(p) Z7_BSWAP64 (*(const UInt64 *)(const void *)(p))
|
||||
#else
|
||||
#define GetUi64a(p) GetUi64(p)
|
||||
#endif
|
||||
|
||||
#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED)
|
||||
#define GetUi32a(p) Z7_BSWAP32 (*(const UInt32 *)(const void *)(p))
|
||||
#else
|
||||
#define GetUi32a(p) GetUi32(p)
|
||||
#endif
|
||||
|
||||
#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 GetUi64a(p) (*(const UInt64 *)(const void *)(p))
|
||||
#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 GetBe64a(p) GetBe64(p)
|
||||
#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
|
||||
|
||||
|
||||
#ifndef GetBe16_to32
|
||||
#define GetBe16_to32(p) GetBe16(p)
|
||||
#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_AVX512F_AVX512VL(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_SHA512(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
|
||||
BoolInt CPU_IsSupported_SHA512(void);
|
||||
|
||||
#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
|
||||
Vendored
+469
@@ -0,0 +1,469 @@
|
||||
7z Format description (18.06)
|
||||
----------------------------
|
||||
|
||||
This file contains description of 7z archive format.
|
||||
7z archive can contain files compressed with any method.
|
||||
See "Methods.txt" for description for defined compressing methods.
|
||||
|
||||
|
||||
Format structure Overview
|
||||
-------------------------
|
||||
|
||||
Some fields can be optional.
|
||||
|
||||
Archive structure
|
||||
~~~~~~~~~~~~~~~~~
|
||||
SignatureHeader
|
||||
[PackedStreams]
|
||||
[PackedStreamsForHeaders]
|
||||
[
|
||||
Header
|
||||
or
|
||||
{
|
||||
Packed Header
|
||||
HeaderInfo
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
||||
Header structure
|
||||
~~~~~~~~~~~~~~~~
|
||||
{
|
||||
ArchiveProperties
|
||||
AdditionalStreams
|
||||
{
|
||||
PackInfo
|
||||
{
|
||||
PackPos
|
||||
NumPackStreams
|
||||
Sizes[NumPackStreams]
|
||||
CRCs[NumPackStreams]
|
||||
}
|
||||
CodersInfo
|
||||
{
|
||||
NumFolders
|
||||
Folders[NumFolders]
|
||||
{
|
||||
NumCoders
|
||||
CodersInfo[NumCoders]
|
||||
{
|
||||
ID
|
||||
NumInStreams;
|
||||
NumOutStreams;
|
||||
PropertiesSize
|
||||
Properties[PropertiesSize]
|
||||
}
|
||||
NumBindPairs
|
||||
BindPairsInfo[NumBindPairs]
|
||||
{
|
||||
InIndex;
|
||||
OutIndex;
|
||||
}
|
||||
PackedIndices
|
||||
}
|
||||
UnPackSize[Folders][Folders.NumOutstreams]
|
||||
CRCs[NumFolders]
|
||||
}
|
||||
SubStreamsInfo
|
||||
{
|
||||
NumUnPackStreamsInFolders[NumFolders];
|
||||
UnPackSizes[]
|
||||
CRCs[]
|
||||
}
|
||||
}
|
||||
MainStreamsInfo
|
||||
{
|
||||
(Same as in AdditionalStreams)
|
||||
}
|
||||
FilesInfo
|
||||
{
|
||||
NumFiles
|
||||
Properties[]
|
||||
{
|
||||
ID
|
||||
Size
|
||||
Data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HeaderInfo structure
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
{
|
||||
(Same as in AdditionalStreams)
|
||||
}
|
||||
|
||||
|
||||
|
||||
Notes about Notation and encoding
|
||||
---------------------------------
|
||||
|
||||
7z uses little endian encoding.
|
||||
|
||||
7z archive format has optional headers that are marked as
|
||||
[]
|
||||
Header
|
||||
[]
|
||||
|
||||
REAL_UINT64 means real UINT64.
|
||||
|
||||
UINT64 means real UINT64 encoded with the following scheme:
|
||||
|
||||
Size of encoding sequence depends from first byte:
|
||||
First_Byte Extra_Bytes Value
|
||||
(binary)
|
||||
0xxxxxxx : ( xxxxxxx )
|
||||
10xxxxxx BYTE y[1] : ( xxxxxx << (8 * 1)) + y
|
||||
110xxxxx BYTE y[2] : ( xxxxx << (8 * 2)) + y
|
||||
...
|
||||
1111110x BYTE y[6] : ( x << (8 * 6)) + y
|
||||
11111110 BYTE y[7] : y
|
||||
11111111 BYTE y[8] : y
|
||||
|
||||
|
||||
|
||||
Property IDs
|
||||
------------
|
||||
|
||||
0x00 = kEnd
|
||||
|
||||
0x01 = kHeader
|
||||
|
||||
0x02 = kArchiveProperties
|
||||
|
||||
0x03 = kAdditionalStreamsInfo
|
||||
0x04 = kMainStreamsInfo
|
||||
0x05 = kFilesInfo
|
||||
|
||||
0x06 = kPackInfo
|
||||
0x07 = kUnPackInfo
|
||||
0x08 = kSubStreamsInfo
|
||||
|
||||
0x09 = kSize
|
||||
0x0A = kCRC
|
||||
|
||||
0x0B = kFolder
|
||||
|
||||
0x0C = kCodersUnPackSize
|
||||
0x0D = kNumUnPackStream
|
||||
|
||||
0x0E = kEmptyStream
|
||||
0x0F = kEmptyFile
|
||||
0x10 = kAnti
|
||||
|
||||
0x11 = kName
|
||||
0x12 = kCTime
|
||||
0x13 = kATime
|
||||
0x14 = kMTime
|
||||
0x15 = kWinAttributes
|
||||
0x16 = kComment
|
||||
|
||||
0x17 = kEncodedHeader
|
||||
|
||||
0x18 = kStartPos
|
||||
0x19 = kDummy
|
||||
|
||||
|
||||
7z format headers
|
||||
-----------------
|
||||
|
||||
SignatureHeader
|
||||
~~~~~~~~~~~~~~~
|
||||
BYTE kSignature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
|
||||
|
||||
ArchiveVersion
|
||||
{
|
||||
BYTE Major; // now = 0
|
||||
BYTE Minor; // now = 4
|
||||
};
|
||||
|
||||
UINT32 StartHeaderCRC;
|
||||
|
||||
StartHeader
|
||||
{
|
||||
REAL_UINT64 NextHeaderOffset
|
||||
REAL_UINT64 NextHeaderSize
|
||||
UINT32 NextHeaderCRC
|
||||
}
|
||||
|
||||
|
||||
...........................
|
||||
|
||||
|
||||
ArchiveProperties
|
||||
~~~~~~~~~~~~~~~~~
|
||||
BYTE NID::kArchiveProperties (0x02)
|
||||
for (;;)
|
||||
{
|
||||
BYTE PropertyType;
|
||||
if (aType == 0)
|
||||
break;
|
||||
UINT64 PropertySize;
|
||||
BYTE PropertyData[PropertySize];
|
||||
}
|
||||
|
||||
|
||||
Digests (NumStreams)
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
BYTE AllAreDefined
|
||||
if (AllAreDefined == 0)
|
||||
{
|
||||
for(NumStreams)
|
||||
BIT Defined
|
||||
}
|
||||
UINT32 CRCs[NumDefined]
|
||||
|
||||
|
||||
PackInfo
|
||||
~~~~~~~~~~~~
|
||||
BYTE NID::kPackInfo (0x06)
|
||||
UINT64 PackPos
|
||||
UINT64 NumPackStreams
|
||||
|
||||
[]
|
||||
BYTE NID::kSize (0x09)
|
||||
UINT64 PackSizes[NumPackStreams]
|
||||
[]
|
||||
|
||||
[]
|
||||
BYTE NID::kCRC (0x0A)
|
||||
PackStreamDigests[NumPackStreams]
|
||||
[]
|
||||
|
||||
BYTE NID::kEnd
|
||||
|
||||
|
||||
Folder
|
||||
~~~~~~
|
||||
UINT64 NumCoders;
|
||||
for (NumCoders)
|
||||
{
|
||||
BYTE
|
||||
{
|
||||
0:3 CodecIdSize
|
||||
4: Is Complex Coder
|
||||
5: There Are Attributes
|
||||
6: Reserved
|
||||
7: There are more alternative methods. (Not used anymore, must be 0).
|
||||
}
|
||||
BYTE CodecId[CodecIdSize]
|
||||
if (Is Complex Coder)
|
||||
{
|
||||
UINT64 NumInStreams;
|
||||
UINT64 NumOutStreams;
|
||||
}
|
||||
if (There Are Attributes)
|
||||
{
|
||||
UINT64 PropertiesSize
|
||||
BYTE Properties[PropertiesSize]
|
||||
}
|
||||
}
|
||||
|
||||
NumBindPairs = NumOutStreamsTotal - 1;
|
||||
|
||||
for (NumBindPairs)
|
||||
{
|
||||
UINT64 InIndex;
|
||||
UINT64 OutIndex;
|
||||
}
|
||||
|
||||
NumPackedStreams = NumInStreamsTotal - NumBindPairs;
|
||||
if (NumPackedStreams > 1)
|
||||
for(NumPackedStreams)
|
||||
{
|
||||
UINT64 Index;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
Coders Info
|
||||
~~~~~~~~~~~
|
||||
|
||||
BYTE NID::kUnPackInfo (0x07)
|
||||
|
||||
|
||||
BYTE NID::kFolder (0x0B)
|
||||
UINT64 NumFolders
|
||||
BYTE External
|
||||
switch(External)
|
||||
{
|
||||
case 0:
|
||||
Folders[NumFolders]
|
||||
case 1:
|
||||
UINT64 DataStreamIndex
|
||||
}
|
||||
|
||||
|
||||
BYTE ID::kCodersUnPackSize (0x0C)
|
||||
for(Folders)
|
||||
for(Folder.NumOutStreams)
|
||||
UINT64 UnPackSize;
|
||||
|
||||
|
||||
[]
|
||||
BYTE NID::kCRC (0x0A)
|
||||
UnPackDigests[NumFolders]
|
||||
[]
|
||||
|
||||
|
||||
|
||||
BYTE NID::kEnd
|
||||
|
||||
|
||||
|
||||
SubStreams Info
|
||||
~~~~~~~~~~~~~~
|
||||
BYTE NID::kSubStreamsInfo; (0x08)
|
||||
|
||||
[]
|
||||
BYTE NID::kNumUnPackStream; (0x0D)
|
||||
UINT64 NumUnPackStreamsInFolders[NumFolders];
|
||||
[]
|
||||
|
||||
|
||||
[]
|
||||
BYTE NID::kSize (0x09)
|
||||
UINT64 UnPackSizes[]
|
||||
[]
|
||||
|
||||
|
||||
[]
|
||||
BYTE NID::kCRC (0x0A)
|
||||
Digests[Number of streams with unknown CRC]
|
||||
[]
|
||||
|
||||
|
||||
BYTE NID::kEnd
|
||||
|
||||
|
||||
Streams Info
|
||||
~~~~~~~~~~~~
|
||||
|
||||
[]
|
||||
PackInfo
|
||||
[]
|
||||
|
||||
|
||||
[]
|
||||
CodersInfo
|
||||
[]
|
||||
|
||||
|
||||
[]
|
||||
SubStreamsInfo
|
||||
[]
|
||||
|
||||
BYTE NID::kEnd
|
||||
|
||||
|
||||
FilesInfo
|
||||
~~~~~~~~~
|
||||
BYTE NID::kFilesInfo; (0x05)
|
||||
UINT64 NumFiles
|
||||
|
||||
for (;;)
|
||||
{
|
||||
BYTE PropertyType;
|
||||
if (aType == 0)
|
||||
break;
|
||||
|
||||
UINT64 Size;
|
||||
|
||||
switch(PropertyType)
|
||||
{
|
||||
kEmptyStream: (0x0E)
|
||||
for(NumFiles)
|
||||
BIT IsEmptyStream
|
||||
|
||||
kEmptyFile: (0x0F)
|
||||
for(EmptyStreams)
|
||||
BIT IsEmptyFile
|
||||
|
||||
kAnti: (0x10)
|
||||
for(EmptyStreams)
|
||||
BIT IsAntiFile
|
||||
|
||||
case kCTime: (0x12)
|
||||
case kATime: (0x13)
|
||||
case kMTime: (0x14)
|
||||
BYTE AllAreDefined
|
||||
if (AllAreDefined == 0)
|
||||
{
|
||||
for(NumFiles)
|
||||
BIT TimeDefined
|
||||
}
|
||||
BYTE External;
|
||||
if(External != 0)
|
||||
UINT64 DataIndex
|
||||
[]
|
||||
for(Defined Items)
|
||||
REAL_UINT64 Time
|
||||
[]
|
||||
|
||||
kNames: (0x11)
|
||||
BYTE External;
|
||||
if(External != 0)
|
||||
UINT64 DataIndex
|
||||
[]
|
||||
for(Files)
|
||||
{
|
||||
wchar_t Names[NameSize];
|
||||
wchar_t 0;
|
||||
}
|
||||
[]
|
||||
|
||||
kAttributes: (0x15)
|
||||
BYTE AllAreDefined
|
||||
if (AllAreDefined == 0)
|
||||
{
|
||||
for(NumFiles)
|
||||
BIT AttributesAreDefined
|
||||
}
|
||||
BYTE External;
|
||||
if(External != 0)
|
||||
UINT64 DataIndex
|
||||
[]
|
||||
for(Defined Attributes)
|
||||
UINT32 Attributes
|
||||
[]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Header
|
||||
~~~~~~
|
||||
BYTE NID::kHeader (0x01)
|
||||
|
||||
[]
|
||||
ArchiveProperties
|
||||
[]
|
||||
|
||||
[]
|
||||
BYTE NID::kAdditionalStreamsInfo; (0x03)
|
||||
StreamsInfo
|
||||
[]
|
||||
|
||||
[]
|
||||
BYTE NID::kMainStreamsInfo; (0x04)
|
||||
StreamsInfo
|
||||
[]
|
||||
|
||||
[]
|
||||
FilesInfo
|
||||
[]
|
||||
|
||||
BYTE NID::kEnd
|
||||
|
||||
|
||||
HeaderInfo
|
||||
~~~~~~~~~~
|
||||
[]
|
||||
BYTE NID::kEncodedHeader; (0x17)
|
||||
StreamsInfo for Encoded Header
|
||||
[]
|
||||
|
||||
|
||||
---
|
||||
End of document
|
||||
Vendored
+177
@@ -0,0 +1,177 @@
|
||||
7-Zip method IDs for 7z and xz archives
|
||||
---------------------------------------
|
||||
|
||||
Version: 24.02
|
||||
Date: 2024-03-22
|
||||
|
||||
Each compression or crypto method in 7z is associated with unique binary value (ID).
|
||||
The length of ID in bytes is arbitrary but it can not exceed 63 bits (8 bytes).
|
||||
|
||||
xz and 7z formats use same ID map.
|
||||
|
||||
If you want to add some new ID, you have two ways:
|
||||
1) Write request for allocating IDs to 7-Zip developers.
|
||||
2) Generate 8-bytes ID:
|
||||
|
||||
3F ZZ ZZ ZZ ZZ ZZ MM MM
|
||||
|
||||
3F - Prefix for random IDs (1 byte)
|
||||
ZZ ZZ ZZ ZZ ZZ - Developer ID (5 bytes). Use real random bytes.
|
||||
|
||||
MM MM - Method ID (2 bytes)
|
||||
|
||||
You can notify 7-Zip developers about your Developer ID / Method ID.
|
||||
|
||||
Note: Use new ID, if old codec can not decode data encoded with new version.
|
||||
|
||||
|
||||
List of defined IDs
|
||||
-------------------
|
||||
|
||||
00 - Copy
|
||||
|
||||
03 - Delta
|
||||
04 - BCJ (x86)
|
||||
05 - PPC (big-endian)
|
||||
06 - IA64
|
||||
07 - ARM (little-endian)
|
||||
08 - ARMT (little-endian)
|
||||
09 - SPARC
|
||||
0A - ARM64
|
||||
0B - RISCV
|
||||
|
||||
21 - LZMA2
|
||||
|
||||
02.. - Common
|
||||
03 [Swap]
|
||||
- 2 Swap2
|
||||
- 4 Swap4
|
||||
|
||||
03.. - 7z
|
||||
01 -
|
||||
01 - LZMA
|
||||
|
||||
03 - [Branch Codecs]
|
||||
01 - [x86 Codecs]
|
||||
03 - BCJ
|
||||
1B - BCJ2 (4 packed streams)
|
||||
02 -
|
||||
05 - PPC (big-endian)
|
||||
03 -
|
||||
01 - Alpha
|
||||
04 -
|
||||
01 - IA64
|
||||
05 -
|
||||
01 - ARM (little-endian)
|
||||
06 -
|
||||
05 - M68 (big-endian)
|
||||
07 -
|
||||
01 - ARMT (little-endian)
|
||||
08 -
|
||||
05 - SPARC
|
||||
|
||||
04 -
|
||||
01 - PPMD
|
||||
|
||||
7F -
|
||||
01 - experimental method.
|
||||
|
||||
|
||||
04.. - Misc codecs
|
||||
|
||||
00 - Reserved
|
||||
|
||||
01 - [Zip]
|
||||
00 - Copy (not used. Use {00} instead)
|
||||
01 - Shrink
|
||||
06 - Implode
|
||||
08 - Deflate
|
||||
09 - Deflate64
|
||||
0A - Imploding
|
||||
0C - BZip2 (not used. Use {040202} instead)
|
||||
0E - LZMA (LZMA-zip)
|
||||
|
||||
5D - ZSTD
|
||||
5F - xz
|
||||
60 - Jpeg
|
||||
61 - WavPack
|
||||
62 - PPMd (PPMd-zip)
|
||||
63 - wzAES
|
||||
|
||||
02 -
|
||||
02 - BZip2
|
||||
|
||||
03 - [Rar]
|
||||
01 - Rar1
|
||||
02 - Rar2
|
||||
03 - Rar3
|
||||
05 - Rar5
|
||||
|
||||
04 - [Arj]
|
||||
01 - Arj(1,2,3)
|
||||
02 - Arj4
|
||||
|
||||
05 - [Z]
|
||||
|
||||
06 - [Lzh]
|
||||
|
||||
07 - Reserved for 7z
|
||||
|
||||
08 - [Cab]
|
||||
|
||||
09 - [NSIS]
|
||||
01 - DeflateNSIS
|
||||
02 - BZip2NSIS
|
||||
|
||||
F7 - External codecs (that are not included to 7-Zip)
|
||||
|
||||
0x xx - reserved
|
||||
|
||||
10 xx - reserved (LZHAM)
|
||||
01 - LZHAM
|
||||
|
||||
11 xx - reserved (Tino Reichardt)
|
||||
01 - ZSTD
|
||||
02 - BROTLI
|
||||
04 - LZ4
|
||||
05 - LZ5
|
||||
06 - LIZARD
|
||||
|
||||
12 xx - reserved (Denis Anisimov)
|
||||
|
||||
01 - WavPack2
|
||||
FE - eSplitter
|
||||
FF - RawSplitter
|
||||
|
||||
|
||||
06.. - Crypto
|
||||
|
||||
F0 - Ciphers without hashing algo
|
||||
|
||||
01 - [AES]
|
||||
0x - AES-128
|
||||
4x - AES-192
|
||||
8x - AES-256
|
||||
Cx - AES
|
||||
|
||||
x0 - ECB
|
||||
x1 - CBC
|
||||
x2 - CFB
|
||||
x3 - OFB
|
||||
x4 - CTR
|
||||
|
||||
F1 - Combine Ciphers
|
||||
|
||||
01 - [Zip]
|
||||
01 - ZipCrypto (Main Zip crypto algo)
|
||||
|
||||
03 - [RAR]
|
||||
02 -
|
||||
03 - Rar29AES (AES-128 + modified SHA-1)
|
||||
|
||||
07 - [7z]
|
||||
01 - 7zAES (AES-256 + SHA-256)
|
||||
|
||||
|
||||
---
|
||||
End of document
|
||||
Vendored
+437
@@ -0,0 +1,437 @@
|
||||
LZMA SDK 26.03
|
||||
--------------
|
||||
|
||||
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.
|
||||
|
||||
How to compile with makefile in Windows
|
||||
---------------------------------------
|
||||
|
||||
Some macronames can be defined for compiling with makefile:
|
||||
|
||||
PLATFORM
|
||||
with possible values: x64, x86, arm64, arm, ia64
|
||||
|
||||
OLD_COMPILER
|
||||
for old VC compiler, like MSCV 6.0.
|
||||
|
||||
MY_DYNAMIC_LINK
|
||||
for dynamic linking to the run-time library (msvcrt.dll).
|
||||
The default makefile option is static linking to the run-time library.
|
||||
|
||||
To compile 7zr.exe file for x64 with Visual Studio 2022,
|
||||
use the following command sequence:
|
||||
|
||||
cd SRC\CPP\7zip\Bundles\Alone7z\
|
||||
%comspec% /k "C:\Program Files\VS2022\VC\Auxiliary\Build\vcvars64.bat"
|
||||
nmake
|
||||
|
||||
You can use other "vcvars*.bat" files from the "VS2022\VC\Auxiliary\Build" directory
|
||||
to compile for other platforms:
|
||||
vcvars64.bat
|
||||
vcvarsamd64_arm64.bat
|
||||
vcvarsamd64_x86.bat
|
||||
|
||||
|
||||
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 (x86 32-bit version)
|
||||
bin/7zr.exe - 7-Zip console program (reduced version) (x86 32-bit version)
|
||||
bin/x64/7zr.exe - 7-Zip console program (reduced version) (x64 version)
|
||||
bin/x64/7zdec.exe - simplified 7z archive decoder (x64 version)
|
||||
bin/arm64/7zr.exe - 7-Zip console program (reduced version) (arm64 version)
|
||||
bin/arm64/7zdec.exe - simplified 7z archive decoder (arm64 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 4 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, 31], default: N=24 (32 MB)
|
||||
The maximum value for dictionary size is N=31 (2 GB).
|
||||
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.
|
||||
bt5 d * 11.5 + 4MB Binary Tree with 5 bytes hashing.
|
||||
hc4 d * 7.5 + 4MB Hash Chain with 4 bytes hashing.
|
||||
hc5 d * 7.5 + 4MB Hash Chain with 5 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
|
||||
Vendored
+169
@@ -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);
|
||||
}
|
||||
Vendored
+19
@@ -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
|
||||
Vendored
+99
@@ -0,0 +1,99 @@
|
||||
/* DllSecur.c -- DLL loading security
|
||||
: Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "7zWindows.h"
|
||||
|
||||
#include "DllSecur.h"
|
||||
|
||||
#ifndef UNDER_CE
|
||||
|
||||
Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
|
||||
|
||||
typedef BOOL (WINAPI *Func_SetDefaultDllDirectories)(DWORD DirectoryFlags);
|
||||
|
||||
#define MY_LOAD_LIBRARY_SEARCH_USER_DIRS 0x400
|
||||
#define MY_LOAD_LIBRARY_SEARCH_SYSTEM32 0x800
|
||||
|
||||
#define DELIM "\0"
|
||||
|
||||
static const char * const g_Dlls =
|
||||
"userenv"
|
||||
DELIM "setupapi"
|
||||
DELIM "apphelp"
|
||||
DELIM "propsys"
|
||||
DELIM "dwmapi"
|
||||
DELIM "cryptbase"
|
||||
DELIM "oleacc"
|
||||
DELIM "clbcatq"
|
||||
DELIM "version"
|
||||
#ifndef _CONSOLE
|
||||
DELIM "uxtheme"
|
||||
#endif
|
||||
DELIM;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
#if defined (_MSC_VER) && _MSC_VER >= 1900
|
||||
// sysinfoapi.h: kit10: GetVersion was declared deprecated
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
|
||||
#define IF_NON_VISTA_SET_DLL_DIRS_AND_RETURN \
|
||||
if ((UInt16)GetVersion() != 6) { \
|
||||
const \
|
||||
Func_SetDefaultDllDirectories setDllDirs = \
|
||||
(Func_SetDefaultDllDirectories) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), \
|
||||
"SetDefaultDllDirectories"); \
|
||||
if (setDllDirs) if (setDllDirs(MY_LOAD_LIBRARY_SEARCH_SYSTEM32 | MY_LOAD_LIBRARY_SEARCH_USER_DIRS)) return; }
|
||||
|
||||
void My_SetDefaultDllDirectories(void)
|
||||
{
|
||||
#ifndef UNDER_CE
|
||||
IF_NON_VISTA_SET_DLL_DIRS_AND_RETURN
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void LoadSecurityDlls(void)
|
||||
{
|
||||
#ifndef UNDER_CE
|
||||
// at Vista (ver 6.0) : CoCreateInstance(CLSID_ShellLink, ...) doesn't work after SetDefaultDllDirectories() : Check it ???
|
||||
IF_NON_VISTA_SET_DLL_DIRS_AND_RETURN
|
||||
{
|
||||
WCHAR buf[MAX_PATH + 100];
|
||||
const char *dll;
|
||||
unsigned pos = GetSystemDirectoryW(buf, MAX_PATH + 2);
|
||||
if (pos == 0 || pos > MAX_PATH)
|
||||
return;
|
||||
if (buf[pos - 1] != '\\')
|
||||
buf[pos++] = '\\';
|
||||
for (dll = g_Dlls; *dll != 0;)
|
||||
{
|
||||
WCHAR *dest = &buf[pos];
|
||||
for (;;)
|
||||
{
|
||||
const char c = *dll++;
|
||||
if (c == 0)
|
||||
break;
|
||||
*dest++ = (Byte)c;
|
||||
}
|
||||
dest[0] = '.';
|
||||
dest[1] = 'd';
|
||||
dest[2] = 'l';
|
||||
dest[3] = 'l';
|
||||
dest[4] = 0;
|
||||
// lstrcatW(buf, L".dll");
|
||||
LoadLibraryExW(buf, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
Vendored
+20
@@ -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
|
||||
Vendored
+493
@@ -0,0 +1,493 @@
|
||||
/* Lzma2Dec.c -- LZMA2 Decoder
|
||||
2024-03-01 : 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;
|
||||
}
|
||||
|
||||
default:
|
||||
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
|
||||
Vendored
+121
@@ -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
|
||||
Vendored
+1367
File diff suppressed because it is too large.
Load diff
Vendored
+237
@@ -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
|
||||
Vendored
+169
@@ -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
|
||||
Vendored
+1131
File diff suppressed because it is too large.
Load diff
Vendored
+181
@@ -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
|
||||
Vendored
+312
@@ -0,0 +1,312 @@
|
||||
/* Ppmd7Dec.c -- Ppmd7z (PPMdH with 7z Range Coder) Decoder
|
||||
2023-09-07 : 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) ((Byte *)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
|
||||
{
|
||||
const unsigned sym0 = s2[0].Symbol;
|
||||
const 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 & (UInt32)(MASK(s->Symbol))) & (0 - (UInt32)num);
|
||||
s += num;
|
||||
p->MinContext = mc;
|
||||
|
||||
do
|
||||
{
|
||||
const unsigned sym0 = s[0].Symbol;
|
||||
const unsigned sym1 = s[1].Symbol;
|
||||
s += 2;
|
||||
hiCnt += (s[-2].Freq & (UInt32)(MASK(sym0)));
|
||||
hiCnt += (s[-1].Freq & (UInt32)(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 & (UInt32)(MASK(s->Symbol));
|
||||
// if ((Int32)count >= 0)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
count -= s->Freq & (UInt32)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break;
|
||||
// count -= s->Freq & (UInt32)(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
|
||||
Vendored
+127
@@ -0,0 +1,127 @@
|
||||
/* Precomp.h -- precompilation file
|
||||
: Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef ZIP7_INC_PRECOMP_H
|
||||
#define ZIP7_INC_PRECOMP_H
|
||||
|
||||
/*
|
||||
this file must be included before another *.h files and before <windows.h>.
|
||||
this file is included from the following files:
|
||||
C\*.c
|
||||
C\Util\*\Precomp.h <- C\Util\*\*.c
|
||||
CPP\Common\Common.h <- *\StdAfx.h <- *\*.cpp
|
||||
|
||||
this file can set the following macros:
|
||||
Z7_LARGE_PAGES 1
|
||||
Z7_LONG_PATH 1
|
||||
Z7_WIN32_WINNT_MIN 0x0500 (or higher) : we require at least win2000+ for 7-Zip
|
||||
_WIN32_WINNT 0x0500 (or higher)
|
||||
WINVER _WIN32_WINNT
|
||||
UNICODE 1
|
||||
_UNICODE 1
|
||||
*/
|
||||
|
||||
#include "Compiler.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// #pragma warning(disable : 4206) // nonstandard extension used : translation unit is empty
|
||||
#if _MSC_VER >= 1912
|
||||
// #pragma warning(disable : 5039) // pointer or reference to potentially throwing function passed to 'extern "C"' function under - EHc.Undefined behavior may occur if this function throws an exception.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
// for debug:
|
||||
#define UNICODE 1
|
||||
#define _UNICODE 1
|
||||
#define _WIN32_WINNT 0x0500 // win2000
|
||||
#ifndef WINVER
|
||||
#define WINVER _WIN32_WINNT
|
||||
#endif
|
||||
*/
|
||||
|
||||
#ifndef Z7_LARGE_PAGES
|
||||
#if !defined(Z7_NO_LARGE_PAGES) && !defined(UNDER_CE)
|
||||
#define Z7_LARGE_PAGES 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
/*
|
||||
this "Precomp.h" file must be included before <windows.h>,
|
||||
if we want to define _WIN32_WINNT before <windows.h>.
|
||||
*/
|
||||
|
||||
#ifndef Z7_LONG_PATH
|
||||
#ifndef Z7_NO_LONG_PATH
|
||||
#define Z7_LONG_PATH 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef Z7_DEVICE_FILE
|
||||
#ifndef Z7_NO_DEVICE_FILE
|
||||
// #define Z7_DEVICE_FILE 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// we don't change macros if included after <windows.h>
|
||||
#ifndef _WINDOWS_
|
||||
|
||||
#ifndef Z7_WIN32_WINNT_MIN
|
||||
#if defined(_M_ARM64) || defined(__aarch64__)
|
||||
// #define Z7_WIN32_WINNT_MIN 0x0a00 // win10
|
||||
#define Z7_WIN32_WINNT_MIN 0x0600 // vista
|
||||
#elif defined(_M_ARM) && defined(_M_ARMT) && defined(_M_ARM_NT)
|
||||
// #define Z7_WIN32_WINNT_MIN 0x0602 // win8
|
||||
#define Z7_WIN32_WINNT_MIN 0x0600 // vista
|
||||
#elif defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) || defined(_M_IA64)
|
||||
#define Z7_WIN32_WINNT_MIN 0x0503 // win2003
|
||||
// #elif defined(_M_IX86) || defined(__i386__)
|
||||
// #define Z7_WIN32_WINNT_MIN 0x0500 // win2000
|
||||
#else // x86 and another(old) systems
|
||||
#define Z7_WIN32_WINNT_MIN 0x0500 // win2000
|
||||
// #define Z7_WIN32_WINNT_MIN 0x0502 // win2003 // for debug
|
||||
#endif
|
||||
#endif // Z7_WIN32_WINNT_MIN
|
||||
|
||||
|
||||
#ifndef Z7_DO_NOT_DEFINE_WIN32_WINNT
|
||||
#ifdef _WIN32_WINNT
|
||||
// #error Stop_Compiling_Bad_WIN32_WINNT
|
||||
#else
|
||||
#ifndef Z7_NO_DEFINE_WIN32_WINNT
|
||||
Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
|
||||
#define _WIN32_WINNT Z7_WIN32_WINNT_MIN
|
||||
Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
|
||||
#endif
|
||||
#endif // _WIN32_WINNT
|
||||
|
||||
#ifndef WINVER
|
||||
#define WINVER _WIN32_WINNT
|
||||
#endif
|
||||
#endif // Z7_DO_NOT_DEFINE_WIN32_WINNT
|
||||
|
||||
|
||||
#ifndef _MBCS
|
||||
#ifndef Z7_NO_UNICODE
|
||||
// UNICODE and _UNICODE are used by <windows.h> and by 7-zip code.
|
||||
|
||||
#ifndef UNICODE
|
||||
#define UNICODE 1
|
||||
#endif
|
||||
|
||||
#ifndef _UNICODE
|
||||
Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
|
||||
#define _UNICODE 1
|
||||
Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
|
||||
#endif
|
||||
|
||||
#endif // Z7_NO_UNICODE
|
||||
#endif // _MBCS
|
||||
#endif // _WINDOWS_
|
||||
|
||||
// #include "7zWindows.h"
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#endif
|
||||
Vendored
+85
@@ -0,0 +1,85 @@
|
||||
# 7z decoder sources (LZMA SDK)
|
||||
|
||||
Vendored subset of the **LZMA SDK 26.03** (2026-09-03) by Igor Pavlov.
|
||||
Public domain — see `DOC/lzma-sdk.txt`:
|
||||
|
||||
> LZMA SDK is written and placed in the public domain by Igor Pavlov.
|
||||
|
||||
Upstream: <https://www.7-zip.org/sdk.html> — release archive
|
||||
`lzma2603.7z` from <https://github.com/ip7z/7zip/releases>.
|
||||
|
||||
These files back the 7z branch of the extraction engine (`src/sevenz_*.c`).
|
||||
The SDK ships both a C and a C++ implementation; only the **C** one is used
|
||||
here, because it builds with the plain `prospero-clang` C toolchain on PS5 and
|
||||
has no dependency on the C++ runtime.
|
||||
|
||||
## What is vendored
|
||||
|
||||
| Group | Files |
|
||||
|---|---|
|
||||
| container | `7z.h`, `7zArcIn.c`, `7zDec.c` |
|
||||
| streams / infra | `7zTypes.h`, `7zStream.c`, `7zFile.c`, `7zAlloc.c`, `7zBuf.c`, `7zBuf2.c`, `Alloc.c` |
|
||||
| checksums | `7zCrc.c`, `7zCrcOpt.c`, `SwapBytes.c` |
|
||||
| CPU / portability | `CpuArch.c`, `Compiler.h`, `Precomp.h`, `RotateDefs.h`, `7zWindows.h` |
|
||||
| codecs | `LzmaDec.c`, `Lzma2Dec.c`, `Ppmd7.c`, `Ppmd7Dec.c`, `Ppmd.h`, `Bcj2.c`, `Bra.c`, `Bra86.c`, `BraIA64.c`, `Delta.c` |
|
||||
| crypto | `Aes.c`, `AesOpt.c`, `Sha256.c`, `Sha256Opt.c` |
|
||||
| misc | `DllSecur.c` (only referenced by the Windows path of `7zFile.c`), `7zVersion.h` |
|
||||
|
||||
The encoder half of the SDK (`LzmaEnc.c`, `Lzma2Enc.c`, `Xz*.c`, `Sort.c`,
|
||||
`Threads.c`, `Mt*.c`, `Ppmd*Enc.c`, …) is deliberately **not** vendored: the
|
||||
engine only ever decodes.
|
||||
|
||||
Build flags that matter:
|
||||
|
||||
* `-DZ7_PPMD_SUPPORT` — without it `7zDec.c` drops the PPMd coder entirely.
|
||||
* `-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE`
|
||||
* `-w` — the sources are not expected to be warning clean.
|
||||
|
||||
## Known SDK limitations the engine has to work around
|
||||
|
||||
Both were confirmed empirically against real 7-Zip 26.03 output, see
|
||||
`tests/sevenz_e2e.c` and `tests/make_sevenz_fixtures.py`.
|
||||
|
||||
### 1. `CSzFolder` caps a folder at 4 coders / 3 bonds
|
||||
|
||||
`7z.h` defines `SZ_NUM_CODERS_IN_FOLDER_MAX 4` and
|
||||
`SZ_NUM_BONDS_IN_FOLDER_MAX 3`, and `SzGetNextFolderItem()` refuses anything
|
||||
larger. But the chain 7-Zip produces for `-m0=bcj2` is **BCJ2 + 4×LZMA2 = 5
|
||||
coders / 4 bonds**, so `SzAr_DecodeFolder()` returns `SZ_ERROR_UNSUPPORTED` on
|
||||
an archive that 7-Zip itself created without complaint.
|
||||
|
||||
Note this only affects *decoding*: `SzArEx_Open()` parses folder blobs with a
|
||||
separate, far more permissive scanner (`k_Scan_NumCoders_MAX 64`, in
|
||||
`7zArcIn.c`), so the file list and all unpack sizes are still correct — the
|
||||
failure shows up per-entry, at extract time.
|
||||
|
||||
Consequence: the engine parses folder blobs with its own dynamic parser and
|
||||
drives the codec chain itself instead of calling `SzAr_DecodeFolder()`.
|
||||
|
||||
### 2. There is no 7zAES coder in the C decoder
|
||||
|
||||
`IS_SUPPORTED_CODER()` in `7zDec.c` accepts only `Copy`, `LZMA`, `LZMA2`,
|
||||
`PPMd` and the branch/delta/BCJ2 filters. `Aes.c` is present but never wired
|
||||
up, so both `-p<password>` archives and `-mhe=on` (encrypted header) archives
|
||||
are rejected.
|
||||
|
||||
Consequence: the engine implements the 7zAES coder itself on top of the
|
||||
vendored `Aes.c` / `Sha256.c`. The reference implementation is in the SDK's
|
||||
C++ tree at `CPP/7zip/Crypto/7zAes.cpp` (not vendored, kept in the SDK tarball):
|
||||
|
||||
* properties: `b0 & 0x3F` = numCyclesPower, `b0 bit7` and `b1>>4` add to the
|
||||
salt size, `b0 bit6` and `b1 & 0x0F` add to the IV size
|
||||
* key: `SHA-256(salt || password_utf16le || counter_le64)` iterated
|
||||
`1 << numCyclesPower` times, unless `numCyclesPower == 0x3F` in which case
|
||||
the key is `salt || password` truncated/zero-padded to 32 bytes
|
||||
* then AES-256-CBC with that key and the (zero-padded) IV
|
||||
|
||||
## Regenerating this directory
|
||||
|
||||
```sh
|
||||
curl -L -o lzma2603.7z https://github.com/ip7z/7zip/releases/download/26.03/lzma2603.7z
|
||||
7zr x lzma2603.7z -osdk
|
||||
# copy the files listed above out of sdk/C/
|
||||
```
|
||||
|
||||
`tests/run-sevenz-tests.sh` builds this subset and runs the fixture matrix.
|
||||
Vendored
+50
@@ -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
|
||||
Vendored
+492
@@ -0,0 +1,492 @@
|
||||
/* Sha256.c -- SHA-256 Hash
|
||||
: Igor Pavlov : Public domain
|
||||
This code is based on public domain code from Wei Dai's Crypto++ library. */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "Sha256.h"
|
||||
#include "RotateDefs.h"
|
||||
#include "CpuArch.h"
|
||||
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
#if defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30800) \
|
||||
|| defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 50100) \
|
||||
|| defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) \
|
||||
|| defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1600) \
|
||||
|| defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
#define Z7_COMPILER_SHA256_SUPPORTED
|
||||
#endif
|
||||
#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE)
|
||||
|
||||
#if defined(__ARM_FEATURE_SHA2) \
|
||||
|| defined(__ARM_FEATURE_CRYPTO)
|
||||
#define Z7_COMPILER_SHA256_SUPPORTED
|
||||
#else
|
||||
#if defined(MY_CPU_ARM64) \
|
||||
|| defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \
|
||||
|| defined(Z7_MSC_VER_ORIGINAL)
|
||||
#if defined(__ARM_FP) && \
|
||||
( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \
|
||||
|| defined(__GNUC__) && (__GNUC__ >= 6) \
|
||||
) \
|
||||
|| defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910)
|
||||
#if defined(MY_CPU_ARM64) \
|
||||
|| !defined(Z7_CLANG_VERSION) \
|
||||
|| defined(__ARM_NEON) && \
|
||||
(Z7_CLANG_VERSION < 170000 || \
|
||||
Z7_CLANG_VERSION > 170001)
|
||||
#define Z7_COMPILER_SHA256_SUPPORTED
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks);
|
||||
|
||||
#ifdef Z7_COMPILER_SHA256_SUPPORTED
|
||||
void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks);
|
||||
|
||||
static SHA256_FUNC_UPDATE_BLOCKS g_SHA256_FUNC_UPDATE_BLOCKS = Sha256_UpdateBlocks;
|
||||
static SHA256_FUNC_UPDATE_BLOCKS g_SHA256_FUNC_UPDATE_BLOCKS_HW;
|
||||
|
||||
#define SHA256_UPDATE_BLOCKS(p) p->v.vars.func_UpdateBlocks
|
||||
#else
|
||||
#define SHA256_UPDATE_BLOCKS(p) Sha256_UpdateBlocks
|
||||
#endif
|
||||
|
||||
|
||||
BoolInt Sha256_SetFunction(CSha256 *p, unsigned algo)
|
||||
{
|
||||
SHA256_FUNC_UPDATE_BLOCKS func = Sha256_UpdateBlocks;
|
||||
|
||||
#ifdef Z7_COMPILER_SHA256_SUPPORTED
|
||||
if (algo != SHA256_ALGO_SW)
|
||||
{
|
||||
if (algo == SHA256_ALGO_DEFAULT)
|
||||
func = g_SHA256_FUNC_UPDATE_BLOCKS;
|
||||
else
|
||||
{
|
||||
if (algo != SHA256_ALGO_HW)
|
||||
return False;
|
||||
func = g_SHA256_FUNC_UPDATE_BLOCKS_HW;
|
||||
if (!func)
|
||||
return False;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (algo > 1)
|
||||
return False;
|
||||
#endif
|
||||
|
||||
p->v.vars.func_UpdateBlocks = func;
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/* define it for speed optimization */
|
||||
|
||||
#ifdef Z7_SFX
|
||||
#define STEP_PRE 1
|
||||
#define STEP_MAIN 1
|
||||
#else
|
||||
#define STEP_PRE 2
|
||||
#define STEP_MAIN 4
|
||||
// #define Z7_SHA256_UNROLL
|
||||
#endif
|
||||
|
||||
#undef Z7_SHA256_BIG_W
|
||||
#if STEP_MAIN != 16
|
||||
#define Z7_SHA256_BIG_W
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
void Sha256_InitState(CSha256 *p)
|
||||
{
|
||||
p->v.vars.count = 0;
|
||||
p->state[0] = 0x6a09e667;
|
||||
p->state[1] = 0xbb67ae85;
|
||||
p->state[2] = 0x3c6ef372;
|
||||
p->state[3] = 0xa54ff53a;
|
||||
p->state[4] = 0x510e527f;
|
||||
p->state[5] = 0x9b05688c;
|
||||
p->state[6] = 0x1f83d9ab;
|
||||
p->state[7] = 0x5be0cd19;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void Sha256_Init(CSha256 *p)
|
||||
{
|
||||
p->v.vars.func_UpdateBlocks =
|
||||
#ifdef Z7_COMPILER_SHA256_SUPPORTED
|
||||
g_SHA256_FUNC_UPDATE_BLOCKS;
|
||||
#else
|
||||
NULL;
|
||||
#endif
|
||||
Sha256_InitState(p);
|
||||
}
|
||||
|
||||
#define S0(x) (rotrFixed(x, 2) ^ rotrFixed(x,13) ^ rotrFixed(x,22))
|
||||
#define S1(x) (rotrFixed(x, 6) ^ rotrFixed(x,11) ^ rotrFixed(x,25))
|
||||
#define s0(x) (rotrFixed(x, 7) ^ rotrFixed(x,18) ^ (x >> 3))
|
||||
#define s1(x) (rotrFixed(x,17) ^ rotrFixed(x,19) ^ (x >>10))
|
||||
|
||||
#define Ch(x,y,z) (z^(x&(y^z)))
|
||||
#define Maj(x,y,z) ((x&y)|(z&(x|y)))
|
||||
|
||||
|
||||
#define W_PRE(i) (W[(i) + (size_t)(j)] = GetBe32(data + ((size_t)(j) + i) * 4))
|
||||
|
||||
#define blk2_main(j, i) s1(w(j, (i)-2)) + w(j, (i)-7) + s0(w(j, (i)-15))
|
||||
|
||||
#ifdef Z7_SHA256_BIG_W
|
||||
// we use +i instead of +(i) to change the order to solve CLANG compiler warning for signed/unsigned.
|
||||
#define w(j, i) W[(size_t)(j) + i]
|
||||
#define blk2(j, i) (w(j, i) = w(j, (i)-16) + blk2_main(j, i))
|
||||
#else
|
||||
#if STEP_MAIN == 16
|
||||
#define w(j, i) W[(i) & 15]
|
||||
#else
|
||||
#define w(j, i) W[((size_t)(j) + (i)) & 15]
|
||||
#endif
|
||||
#define blk2(j, i) (w(j, i) += blk2_main(j, i))
|
||||
#endif
|
||||
|
||||
#define W_MAIN(i) blk2(j, i)
|
||||
|
||||
|
||||
#define T1(wx, i) \
|
||||
tmp = h + S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \
|
||||
h = g; \
|
||||
g = f; \
|
||||
f = e; \
|
||||
e = d + tmp; \
|
||||
tmp += S0(a) + Maj(a, b, c); \
|
||||
d = c; \
|
||||
c = b; \
|
||||
b = a; \
|
||||
a = tmp; \
|
||||
|
||||
#define R1_PRE(i) T1( W_PRE, i)
|
||||
#define R1_MAIN(i) T1( W_MAIN, i)
|
||||
|
||||
#if (!defined(Z7_SHA256_UNROLL) || STEP_MAIN < 8) && (STEP_MAIN >= 4)
|
||||
#define R2_MAIN(i) \
|
||||
R1_MAIN(i) \
|
||||
R1_MAIN(i + 1) \
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if defined(Z7_SHA256_UNROLL) && STEP_MAIN >= 8
|
||||
|
||||
#define T4( a,b,c,d,e,f,g,h, wx, i) \
|
||||
h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \
|
||||
tmp = h; \
|
||||
h += d; \
|
||||
d = tmp + S0(a) + Maj(a, b, c); \
|
||||
|
||||
#define R4( wx, i) \
|
||||
T4 ( a,b,c,d,e,f,g,h, wx, (i )); \
|
||||
T4 ( d,a,b,c,h,e,f,g, wx, (i+1)); \
|
||||
T4 ( c,d,a,b,g,h,e,f, wx, (i+2)); \
|
||||
T4 ( b,c,d,a,f,g,h,e, wx, (i+3)); \
|
||||
|
||||
#define R4_PRE(i) R4( W_PRE, i)
|
||||
#define R4_MAIN(i) R4( W_MAIN, i)
|
||||
|
||||
|
||||
#define T8( a,b,c,d,e,f,g,h, wx, i) \
|
||||
h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \
|
||||
d += h; \
|
||||
h += S0(a) + Maj(a, b, c); \
|
||||
|
||||
#define R8( wx, i) \
|
||||
T8 ( a,b,c,d,e,f,g,h, wx, i ); \
|
||||
T8 ( h,a,b,c,d,e,f,g, wx, i+1); \
|
||||
T8 ( g,h,a,b,c,d,e,f, wx, i+2); \
|
||||
T8 ( f,g,h,a,b,c,d,e, wx, i+3); \
|
||||
T8 ( e,f,g,h,a,b,c,d, wx, i+4); \
|
||||
T8 ( d,e,f,g,h,a,b,c, wx, i+5); \
|
||||
T8 ( c,d,e,f,g,h,a,b, wx, i+6); \
|
||||
T8 ( b,c,d,e,f,g,h,a, wx, i+7); \
|
||||
|
||||
#define R8_PRE(i) R8( W_PRE, i)
|
||||
#define R8_MAIN(i) R8( W_MAIN, i)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
extern
|
||||
MY_ALIGN(64) const UInt32 SHA256_K_ARRAY[64];
|
||||
MY_ALIGN(64) const UInt32 SHA256_K_ARRAY[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
||||
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define K SHA256_K_ARRAY
|
||||
|
||||
Z7_NO_INLINE
|
||||
void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks)
|
||||
{
|
||||
UInt32 W
|
||||
#ifdef Z7_SHA256_BIG_W
|
||||
[64];
|
||||
#else
|
||||
[16];
|
||||
#endif
|
||||
unsigned j;
|
||||
UInt32 a,b,c,d,e,f,g,h;
|
||||
#if !defined(Z7_SHA256_UNROLL) || (STEP_MAIN <= 4) || (STEP_PRE <= 4)
|
||||
UInt32 tmp;
|
||||
#endif
|
||||
|
||||
if (numBlocks == 0) return;
|
||||
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
f = state[5];
|
||||
g = state[6];
|
||||
h = state[7];
|
||||
|
||||
do
|
||||
{
|
||||
|
||||
for (j = 0; j < 16; j += STEP_PRE)
|
||||
{
|
||||
#if STEP_PRE > 4
|
||||
|
||||
#if STEP_PRE < 8
|
||||
R4_PRE(0);
|
||||
#else
|
||||
R8_PRE(0);
|
||||
#if STEP_PRE == 16
|
||||
R8_PRE(8);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
R1_PRE(0)
|
||||
#if STEP_PRE >= 2
|
||||
R1_PRE(1)
|
||||
#if STEP_PRE >= 4
|
||||
R1_PRE(2)
|
||||
R1_PRE(3)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
for (j = 16; j < 64; j += STEP_MAIN)
|
||||
{
|
||||
#if defined(Z7_SHA256_UNROLL) && STEP_MAIN >= 8
|
||||
|
||||
#if STEP_MAIN < 8
|
||||
R4_MAIN(0)
|
||||
#else
|
||||
R8_MAIN(0)
|
||||
#if STEP_MAIN == 16
|
||||
R8_MAIN(8)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
R1_MAIN(0)
|
||||
#if STEP_MAIN >= 2
|
||||
R1_MAIN(1)
|
||||
#if STEP_MAIN >= 4
|
||||
R2_MAIN(2)
|
||||
#if STEP_MAIN >= 8
|
||||
R2_MAIN(4)
|
||||
R2_MAIN(6)
|
||||
#if STEP_MAIN >= 16
|
||||
R2_MAIN(8)
|
||||
R2_MAIN(10)
|
||||
R2_MAIN(12)
|
||||
R2_MAIN(14)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
a += state[0]; state[0] = a;
|
||||
b += state[1]; state[1] = b;
|
||||
c += state[2]; state[2] = c;
|
||||
d += state[3]; state[3] = d;
|
||||
e += state[4]; state[4] = e;
|
||||
f += state[5]; state[5] = f;
|
||||
g += state[6]; state[6] = g;
|
||||
h += state[7]; state[7] = h;
|
||||
|
||||
data += SHA256_BLOCK_SIZE;
|
||||
}
|
||||
while (--numBlocks);
|
||||
}
|
||||
|
||||
|
||||
#define Sha256_UpdateBlock(p) SHA256_UPDATE_BLOCKS(p)(p->state, p->buffer, 1)
|
||||
|
||||
void Sha256_Update(CSha256 *p, const Byte *data, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
{
|
||||
const unsigned pos = (unsigned)p->v.vars.count & (SHA256_BLOCK_SIZE - 1);
|
||||
const unsigned num = SHA256_BLOCK_SIZE - pos;
|
||||
p->v.vars.count += size;
|
||||
if (num > size)
|
||||
{
|
||||
memcpy(p->buffer + pos, data, size);
|
||||
return;
|
||||
}
|
||||
if (pos != 0)
|
||||
{
|
||||
size -= num;
|
||||
memcpy(p->buffer + pos, data, num);
|
||||
data += num;
|
||||
Sha256_UpdateBlock(p);
|
||||
}
|
||||
}
|
||||
{
|
||||
const size_t numBlocks = size >> 6;
|
||||
// if (numBlocks)
|
||||
SHA256_UPDATE_BLOCKS(p)(p->state, data, numBlocks);
|
||||
size &= SHA256_BLOCK_SIZE - 1;
|
||||
if (size == 0)
|
||||
return;
|
||||
data += (numBlocks << 6);
|
||||
memcpy(p->buffer, data, size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Sha256_Final(CSha256 *p, Byte *digest)
|
||||
{
|
||||
unsigned pos = (unsigned)p->v.vars.count & (SHA256_BLOCK_SIZE - 1);
|
||||
p->buffer[pos++] = 0x80;
|
||||
if (pos > (SHA256_BLOCK_SIZE - 4 * 2))
|
||||
{
|
||||
while (pos != SHA256_BLOCK_SIZE) { p->buffer[pos++] = 0; }
|
||||
// memset(&p->buf.buffer[pos], 0, SHA256_BLOCK_SIZE - pos);
|
||||
Sha256_UpdateBlock(p);
|
||||
pos = 0;
|
||||
}
|
||||
memset(&p->buffer[pos], 0, (SHA256_BLOCK_SIZE - 4 * 2) - pos);
|
||||
{
|
||||
const UInt64 numBits = p->v.vars.count << 3;
|
||||
SetBe32(p->buffer + SHA256_BLOCK_SIZE - 4 * 2, (UInt32)(numBits >> 32))
|
||||
SetBe32(p->buffer + SHA256_BLOCK_SIZE - 4 * 1, (UInt32)(numBits))
|
||||
}
|
||||
Sha256_UpdateBlock(p);
|
||||
#if 1 && defined(MY_CPU_BE)
|
||||
memcpy(digest, p->state, SHA256_DIGEST_SIZE);
|
||||
#else
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < 8; i += 2)
|
||||
{
|
||||
const UInt32 v0 = p->state[i];
|
||||
const UInt32 v1 = p->state[(size_t)i + 1];
|
||||
SetBe32(digest , v0)
|
||||
SetBe32(digest + 4, v1)
|
||||
digest += 4 * 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
Sha256_InitState(p);
|
||||
}
|
||||
|
||||
|
||||
void Sha256Prepare(void)
|
||||
{
|
||||
#ifdef Z7_COMPILER_SHA256_SUPPORTED
|
||||
SHA256_FUNC_UPDATE_BLOCKS f, f_hw;
|
||||
f = Sha256_UpdateBlocks;
|
||||
f_hw = NULL;
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
if (CPU_IsSupported_SHA()
|
||||
&& CPU_IsSupported_SSSE3()
|
||||
)
|
||||
#else
|
||||
if (CPU_IsSupported_SHA2())
|
||||
#endif
|
||||
{
|
||||
// printf("\n========== HW SHA256 ======== \n");
|
||||
f = f_hw = Sha256_UpdateBlocks_HW;
|
||||
}
|
||||
g_SHA256_FUNC_UPDATE_BLOCKS = f;
|
||||
g_SHA256_FUNC_UPDATE_BLOCKS_HW = f_hw;
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef U64C
|
||||
#undef K
|
||||
#undef S0
|
||||
#undef S1
|
||||
#undef s0
|
||||
#undef s1
|
||||
#undef Ch
|
||||
#undef Maj
|
||||
#undef W_MAIN
|
||||
#undef W_PRE
|
||||
#undef w
|
||||
#undef blk2_main
|
||||
#undef blk2
|
||||
#undef T1
|
||||
#undef T4
|
||||
#undef T8
|
||||
#undef R1_PRE
|
||||
#undef R1_MAIN
|
||||
#undef R2_MAIN
|
||||
#undef R4
|
||||
#undef R4_PRE
|
||||
#undef R4_MAIN
|
||||
#undef R8
|
||||
#undef R8_PRE
|
||||
#undef R8_MAIN
|
||||
#undef STEP_PRE
|
||||
#undef STEP_MAIN
|
||||
#undef Z7_SHA256_BIG_W
|
||||
#undef Z7_SHA256_UNROLL
|
||||
#undef Z7_COMPILER_SHA256_SUPPORTED
|
||||
Vendored
+86
@@ -0,0 +1,86 @@
|
||||
/* Sha256.h -- SHA-256 Hash
|
||||
: 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
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
SHA256_FUNC_UPDATE_BLOCKS func_UpdateBlocks;
|
||||
UInt64 count;
|
||||
} vars;
|
||||
UInt64 _pad_64bit[4];
|
||||
void *_pad_align_ptr[2];
|
||||
} v;
|
||||
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
|
||||
Vendored
+451
@@ -0,0 +1,451 @@
|
||||
/* Sha256Opt.c -- SHA-256 optimized code for SHA-256 hardware instructions
|
||||
: Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
#include "Compiler.h"
|
||||
#include "CpuArch.h"
|
||||
|
||||
// #define Z7_USE_HW_SHA_STUB // for debug
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1600) // fix that check
|
||||
#define USE_HW_SHA
|
||||
#elif defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30800) \
|
||||
|| defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 50100) \
|
||||
|| defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900)
|
||||
#define USE_HW_SHA
|
||||
#if !defined(__INTEL_COMPILER)
|
||||
// icc defines __GNUC__, but icc doesn't support __attribute__(__target__)
|
||||
#if !defined(__SHA__) || !defined(__SSSE3__)
|
||||
#define ATTRIB_SHA __attribute__((__target__("sha,ssse3")))
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#if (_MSC_VER >= 1900)
|
||||
#define USE_HW_SHA
|
||||
#else
|
||||
#define Z7_USE_HW_SHA_STUB
|
||||
#endif
|
||||
#endif
|
||||
// #endif // MY_CPU_X86_OR_AMD64
|
||||
#ifndef USE_HW_SHA
|
||||
// #define Z7_USE_HW_SHA_STUB // for debug
|
||||
#endif
|
||||
|
||||
#ifdef USE_HW_SHA
|
||||
|
||||
// #pragma message("Sha256 HW")
|
||||
|
||||
|
||||
|
||||
|
||||
// sse/sse2/ssse3:
|
||||
#include <tmmintrin.h>
|
||||
// sha*:
|
||||
#include <immintrin.h>
|
||||
|
||||
#if defined (__clang__) && defined(_MSC_VER)
|
||||
#if !defined(__SHA__)
|
||||
#include <shaintrin.h>
|
||||
#endif
|
||||
#else
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
SHA256 uses:
|
||||
SSE2:
|
||||
_mm_loadu_si128
|
||||
_mm_storeu_si128
|
||||
_mm_set_epi32
|
||||
_mm_add_epi32
|
||||
_mm_shuffle_epi32 / pshufd
|
||||
|
||||
|
||||
|
||||
SSSE3:
|
||||
_mm_shuffle_epi8 / pshufb
|
||||
_mm_alignr_epi8
|
||||
SHA:
|
||||
_mm_sha256*
|
||||
*/
|
||||
|
||||
// K array must be aligned for 16-bytes at least.
|
||||
// The compiler can look align attribute and selects
|
||||
// movdqu - for code without align attribute
|
||||
// movdqa - for code with align attribute
|
||||
extern
|
||||
MY_ALIGN(64)
|
||||
const UInt32 SHA256_K_ARRAY[64];
|
||||
#define K SHA256_K_ARRAY
|
||||
|
||||
|
||||
#define ADD_EPI32(dest, src) dest = _mm_add_epi32(dest, src);
|
||||
#define SHA256_MSG1(dest, src) dest = _mm_sha256msg1_epu32(dest, src);
|
||||
#define SHA256_MSG2(dest, src) dest = _mm_sha256msg2_epu32(dest, src);
|
||||
|
||||
#define LOAD_SHUFFLE(m, k) \
|
||||
m = _mm_loadu_si128((const __m128i *)(const void *)(data + (k) * 16)); \
|
||||
m = _mm_shuffle_epi8(m, mask); \
|
||||
|
||||
#define NNN(m0, m1, m2, m3)
|
||||
|
||||
#define SM1(m1, m2, m3, m0) \
|
||||
SHA256_MSG1(m0, m1); \
|
||||
|
||||
#define SM2(m2, m3, m0, m1) \
|
||||
ADD_EPI32(m0, _mm_alignr_epi8(m3, m2, 4)) \
|
||||
SHA256_MSG2(m0, m3); \
|
||||
|
||||
#define RND2(t0, t1) \
|
||||
t0 = _mm_sha256rnds2_epu32(t0, t1, msg);
|
||||
|
||||
|
||||
|
||||
#define R4(k, m0, m1, m2, m3, OP0, OP1) \
|
||||
msg = _mm_add_epi32(m0, *(const __m128i *) (const void *) &K[(k) * 4]); \
|
||||
RND2(state0, state1); \
|
||||
msg = _mm_shuffle_epi32(msg, 0x0E); \
|
||||
OP0(m0, m1, m2, m3) \
|
||||
RND2(state1, state0); \
|
||||
OP1(m0, m1, m2, m3) \
|
||||
|
||||
#define R16(k, OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7) \
|
||||
R4 ( (k)*4+0, m0,m1,m2,m3, OP0, OP1 ) \
|
||||
R4 ( (k)*4+1, m1,m2,m3,m0, OP2, OP3 ) \
|
||||
R4 ( (k)*4+2, m2,m3,m0,m1, OP4, OP5 ) \
|
||||
R4 ( (k)*4+3, m3,m0,m1,m2, OP6, OP7 ) \
|
||||
|
||||
#define PREPARE_STATE \
|
||||
tmp = _mm_shuffle_epi32(state0, 0x1B); /* abcd */ \
|
||||
state0 = _mm_shuffle_epi32(state1, 0x1B); /* efgh */ \
|
||||
state1 = state0; \
|
||||
state0 = _mm_unpacklo_epi64(state0, tmp); /* cdgh */ \
|
||||
state1 = _mm_unpackhi_epi64(state1, tmp); /* abef */ \
|
||||
|
||||
|
||||
void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks);
|
||||
#ifdef ATTRIB_SHA
|
||||
ATTRIB_SHA
|
||||
#endif
|
||||
void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks)
|
||||
{
|
||||
const __m128i mask = _mm_set_epi32(0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203);
|
||||
|
||||
|
||||
__m128i tmp, state0, state1;
|
||||
|
||||
if (numBlocks == 0)
|
||||
return;
|
||||
|
||||
state0 = _mm_loadu_si128((const __m128i *) (const void *) &state[0]);
|
||||
state1 = _mm_loadu_si128((const __m128i *) (const void *) &state[4]);
|
||||
|
||||
PREPARE_STATE
|
||||
|
||||
do
|
||||
{
|
||||
__m128i state0_save, state1_save;
|
||||
__m128i m0, m1, m2, m3;
|
||||
__m128i msg;
|
||||
// #define msg tmp
|
||||
|
||||
state0_save = state0;
|
||||
state1_save = state1;
|
||||
|
||||
LOAD_SHUFFLE (m0, 0)
|
||||
LOAD_SHUFFLE (m1, 1)
|
||||
LOAD_SHUFFLE (m2, 2)
|
||||
LOAD_SHUFFLE (m3, 3)
|
||||
|
||||
|
||||
|
||||
R16 ( 0, NNN, NNN, SM1, NNN, SM1, SM2, SM1, SM2 )
|
||||
R16 ( 1, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 )
|
||||
R16 ( 2, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 )
|
||||
R16 ( 3, SM1, SM2, NNN, SM2, NNN, NNN, NNN, NNN )
|
||||
|
||||
ADD_EPI32(state0, state0_save)
|
||||
ADD_EPI32(state1, state1_save)
|
||||
|
||||
data += 64;
|
||||
}
|
||||
while (--numBlocks);
|
||||
|
||||
PREPARE_STATE
|
||||
|
||||
_mm_storeu_si128((__m128i *) (void *) &state[0], state0);
|
||||
_mm_storeu_si128((__m128i *) (void *) &state[4], state1);
|
||||
}
|
||||
|
||||
#endif // USE_HW_SHA
|
||||
|
||||
#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE)
|
||||
|
||||
#if defined(__ARM_FEATURE_SHA2) \
|
||||
|| defined(__ARM_FEATURE_CRYPTO)
|
||||
#define USE_HW_SHA
|
||||
#else
|
||||
#if defined(MY_CPU_ARM64) \
|
||||
|| defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \
|
||||
|| defined(Z7_MSC_VER_ORIGINAL)
|
||||
#if defined(__ARM_FP) && \
|
||||
( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \
|
||||
|| defined(__GNUC__) && (__GNUC__ >= 6) \
|
||||
) \
|
||||
|| defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910)
|
||||
#if defined(MY_CPU_ARM64) \
|
||||
|| !defined(Z7_CLANG_VERSION) \
|
||||
|| defined(__ARM_NEON) && \
|
||||
(Z7_CLANG_VERSION < 170000 || \
|
||||
Z7_CLANG_VERSION > 170001)
|
||||
#define USE_HW_SHA
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_HW_SHA
|
||||
|
||||
// #pragma message("=== Sha256 HW === ")
|
||||
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#if !defined(__ARM_FEATURE_SHA2) && \
|
||||
!defined(__ARM_FEATURE_CRYPTO)
|
||||
#ifdef MY_CPU_ARM64
|
||||
#if defined(__clang__)
|
||||
#define ATTRIB_SHA __attribute__((__target__("crypto")))
|
||||
#else
|
||||
#define ATTRIB_SHA __attribute__((__target__("+crypto")))
|
||||
#endif
|
||||
#else
|
||||
#if defined(__clang__) && (__clang_major__ >= 1)
|
||||
#define ATTRIB_SHA __attribute__((__target__("armv8-a,sha2")))
|
||||
#else
|
||||
#define ATTRIB_SHA __attribute__((__target__("fpu=crypto-neon-fp-armv8")))
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
// _MSC_VER
|
||||
// for arm32
|
||||
#define _ARM_USE_NEW_NEON_INTRINSICS
|
||||
#endif
|
||||
|
||||
#if defined(Z7_MSC_VER_ORIGINAL) && defined(MY_CPU_ARM64)
|
||||
#include <arm64_neon.h>
|
||||
#else
|
||||
|
||||
#if defined(__clang__) && __clang_major__ < 16
|
||||
#if !defined(__ARM_FEATURE_SHA2) && \
|
||||
!defined(__ARM_FEATURE_CRYPTO)
|
||||
// #pragma message("=== we set __ARM_FEATURE_CRYPTO 1 === ")
|
||||
Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
|
||||
#define Z7_ARM_FEATURE_CRYPTO_WAS_SET 1
|
||||
// #if defined(__clang__) && __clang_major__ < 13
|
||||
#define __ARM_FEATURE_CRYPTO 1
|
||||
// #else
|
||||
#define __ARM_FEATURE_SHA2 1
|
||||
// #endif
|
||||
Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
|
||||
#endif
|
||||
#endif // clang
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
#if defined(__ARM_ARCH) && __ARM_ARCH < 8
|
||||
Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
|
||||
// #pragma message("#define __ARM_ARCH 8")
|
||||
#undef __ARM_ARCH
|
||||
#define __ARM_ARCH 8
|
||||
Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
|
||||
#endif
|
||||
|
||||
#endif // clang
|
||||
|
||||
#include <arm_neon.h>
|
||||
|
||||
#if defined(Z7_ARM_FEATURE_CRYPTO_WAS_SET) && \
|
||||
defined(__ARM_FEATURE_CRYPTO) && \
|
||||
defined(__ARM_FEATURE_SHA2)
|
||||
Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
|
||||
#undef __ARM_FEATURE_CRYPTO
|
||||
#undef __ARM_FEATURE_SHA2
|
||||
#undef Z7_ARM_FEATURE_CRYPTO_WAS_SET
|
||||
Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
|
||||
// #pragma message("=== we undefine __ARM_FEATURE_CRYPTO === ")
|
||||
#endif
|
||||
|
||||
#endif // Z7_MSC_VER_ORIGINAL
|
||||
|
||||
typedef uint32x4_t v128;
|
||||
// typedef __n128 v128; // MSVC
|
||||
|
||||
#ifdef MY_CPU_BE
|
||||
#define MY_rev32_for_LE(x) x
|
||||
#else
|
||||
#define MY_rev32_for_LE(x) vrev32q_u8(x)
|
||||
#endif
|
||||
|
||||
#if 1 // 0 for debug
|
||||
// for arm32: it works slower by some reason than direct code
|
||||
/*
|
||||
for arm32 it generates:
|
||||
MSVC-2022, GCC-9:
|
||||
vld1.32 {d18,d19}, [r10]
|
||||
vst1.32 {d4,d5}, [r3]
|
||||
vld1.8 {d20-d21}, [r4]
|
||||
there is no align hint (like [r10:128]). So instruction allows unaligned access
|
||||
*/
|
||||
#define LOAD_128_32(_p) vld1q_u32(_p)
|
||||
#define LOAD_128_8(_p) vld1q_u8 (_p)
|
||||
#define STORE_128_32(_p, _v) vst1q_u32(_p, _v)
|
||||
#else
|
||||
/*
|
||||
for arm32:
|
||||
MSVC-2022:
|
||||
vldm r10,{d18,d19}
|
||||
vstm r3,{d4,d5}
|
||||
does it require strict alignment?
|
||||
GCC-9:
|
||||
vld1.64 {d30-d31}, [r0:64]
|
||||
vldr d28, [r0, #16]
|
||||
vldr d29, [r0, #24]
|
||||
vst1.64 {d30-d31}, [r0:64]
|
||||
vstr d28, [r0, #16]
|
||||
vstr d29, [r0, #24]
|
||||
there is hint [r0:64], so does it requires 64-bit alignment.
|
||||
*/
|
||||
#define LOAD_128_32(_p) (*(const v128 *)(const void *)(_p))
|
||||
#define LOAD_128_8(_p) vreinterpretq_u8_u32(*(const v128 *)(const void *)(_p))
|
||||
#define STORE_128_32(_p, _v) *(v128 *)(void *)(_p) = (_v)
|
||||
#endif
|
||||
|
||||
#define LOAD_SHUFFLE(m, k) \
|
||||
m = vreinterpretq_u32_u8( \
|
||||
MY_rev32_for_LE( \
|
||||
LOAD_128_8(data + (k) * 16))); \
|
||||
|
||||
// K array must be aligned for 16-bytes at least.
|
||||
extern
|
||||
MY_ALIGN(64)
|
||||
const UInt32 SHA256_K_ARRAY[64];
|
||||
#define K SHA256_K_ARRAY
|
||||
|
||||
#define SHA256_SU0(dest, src) dest = vsha256su0q_u32(dest, src);
|
||||
#define SHA256_SU1(dest, src2, src3) dest = vsha256su1q_u32(dest, src2, src3);
|
||||
|
||||
#define SM1(m0, m1, m2, m3) SHA256_SU0(m3, m0)
|
||||
#define SM2(m0, m1, m2, m3) SHA256_SU1(m2, m0, m1)
|
||||
#define NNN(m0, m1, m2, m3)
|
||||
|
||||
#define R4(k, m0, m1, m2, m3, OP0, OP1) \
|
||||
msg = vaddq_u32(m0, *(const v128 *) (const void *) &K[(k) * 4]); \
|
||||
tmp = state0; \
|
||||
state0 = vsha256hq_u32( state0, state1, msg ); \
|
||||
state1 = vsha256h2q_u32( state1, tmp, msg ); \
|
||||
OP0(m0, m1, m2, m3); \
|
||||
OP1(m0, m1, m2, m3); \
|
||||
|
||||
|
||||
#define R16(k, OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7) \
|
||||
R4 ( (k)*4+0, m0, m1, m2, m3, OP0, OP1 ) \
|
||||
R4 ( (k)*4+1, m1, m2, m3, m0, OP2, OP3 ) \
|
||||
R4 ( (k)*4+2, m2, m3, m0, m1, OP4, OP5 ) \
|
||||
R4 ( (k)*4+3, m3, m0, m1, m2, OP6, OP7 ) \
|
||||
|
||||
|
||||
void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks);
|
||||
#ifdef ATTRIB_SHA
|
||||
ATTRIB_SHA
|
||||
#endif
|
||||
void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks)
|
||||
{
|
||||
v128 state0, state1;
|
||||
|
||||
if (numBlocks == 0)
|
||||
return;
|
||||
|
||||
state0 = LOAD_128_32(&state[0]);
|
||||
state1 = LOAD_128_32(&state[4]);
|
||||
|
||||
do
|
||||
{
|
||||
v128 state0_save, state1_save;
|
||||
v128 m0, m1, m2, m3;
|
||||
v128 msg, tmp;
|
||||
|
||||
state0_save = state0;
|
||||
state1_save = state1;
|
||||
|
||||
LOAD_SHUFFLE (m0, 0)
|
||||
LOAD_SHUFFLE (m1, 1)
|
||||
LOAD_SHUFFLE (m2, 2)
|
||||
LOAD_SHUFFLE (m3, 3)
|
||||
|
||||
R16 ( 0, NNN, NNN, SM1, NNN, SM1, SM2, SM1, SM2 )
|
||||
R16 ( 1, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 )
|
||||
R16 ( 2, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 )
|
||||
R16 ( 3, SM1, SM2, NNN, SM2, NNN, NNN, NNN, NNN )
|
||||
|
||||
state0 = vaddq_u32(state0, state0_save);
|
||||
state1 = vaddq_u32(state1, state1_save);
|
||||
|
||||
data += 64;
|
||||
}
|
||||
while (--numBlocks);
|
||||
|
||||
STORE_128_32(&state[0], state0);
|
||||
STORE_128_32(&state[4], state1);
|
||||
}
|
||||
|
||||
#endif // USE_HW_SHA
|
||||
|
||||
#endif // MY_CPU_ARM_OR_ARM64
|
||||
|
||||
|
||||
#if !defined(USE_HW_SHA) && defined(Z7_USE_HW_SHA_STUB)
|
||||
// #error Stop_Compiling_UNSUPPORTED_SHA
|
||||
// #include <stdlib.h>
|
||||
// We can compile this file with another C compiler,
|
||||
// or we can compile asm version.
|
||||
// So we can generate real code instead of this stub function.
|
||||
// #include "Sha256.h"
|
||||
// #if defined(_MSC_VER)
|
||||
#pragma message("Sha256 HW-SW stub was used")
|
||||
// #endif
|
||||
void Z7_FASTCALL Sha256_UpdateBlocks (UInt32 state[8], const Byte *data, size_t numBlocks);
|
||||
void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks);
|
||||
void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks)
|
||||
{
|
||||
Sha256_UpdateBlocks(state, data, numBlocks);
|
||||
/*
|
||||
UNUSED_VAR(state);
|
||||
UNUSED_VAR(data);
|
||||
UNUSED_VAR(numBlocks);
|
||||
exit(1);
|
||||
return;
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#undef K
|
||||
#undef RND2
|
||||
#undef MY_rev32_for_LE
|
||||
|
||||
#undef NNN
|
||||
#undef LOAD_128
|
||||
#undef STORE_128
|
||||
#undef LOAD_SHUFFLE
|
||||
#undef SM1
|
||||
#undef SM2
|
||||
|
||||
|
||||
#undef R4
|
||||
#undef R16
|
||||
#undef PREPARE_STATE
|
||||
#undef USE_HW_SHA
|
||||
#undef ATTRIB_SHA
|
||||
#undef USE_VER_MIN
|
||||
#undef Z7_USE_HW_SHA_STUB
|
||||
Vendored
+835
@@ -0,0 +1,835 @@
|
||||
/* SwapBytes.c -- Byte Swap conversion filter
|
||||
2024-03-01 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "Compiler.h"
|
||||
#include "CpuArch.h"
|
||||
#include "RotateDefs.h"
|
||||
#include "SwapBytes.h"
|
||||
|
||||
typedef UInt16 CSwapUInt16;
|
||||
typedef UInt32 CSwapUInt32;
|
||||
|
||||
// #define k_SwapBytes_Mode_BASE 0
|
||||
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
|
||||
#define k_SwapBytes_Mode_SSE2 1
|
||||
#define k_SwapBytes_Mode_SSSE3 2
|
||||
#define k_SwapBytes_Mode_AVX2 3
|
||||
|
||||
// #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1900)
|
||||
#if defined(__clang__) && (__clang_major__ >= 4) \
|
||||
|| defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40701)
|
||||
#define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_AVX2
|
||||
#define SWAP_ATTRIB_SSE2 __attribute__((__target__("sse2")))
|
||||
#define SWAP_ATTRIB_SSSE3 __attribute__((__target__("ssse3")))
|
||||
#define SWAP_ATTRIB_AVX2 __attribute__((__target__("avx2")))
|
||||
#elif defined(_MSC_VER)
|
||||
#if (_MSC_VER == 1900)
|
||||
#pragma warning(disable : 4752) // found Intel(R) Advanced Vector Extensions; consider using /arch:AVX
|
||||
#endif
|
||||
#if (_MSC_VER >= 1900)
|
||||
#define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_AVX2
|
||||
#elif (_MSC_VER >= 1500) // (VS2008)
|
||||
#define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_SSSE3
|
||||
#elif (_MSC_VER >= 1310) // (VS2003)
|
||||
#define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_SSE2
|
||||
#endif
|
||||
#endif // _MSC_VER
|
||||
|
||||
/*
|
||||
// for debug
|
||||
#ifdef k_SwapBytes_Mode_MAX
|
||||
#undef k_SwapBytes_Mode_MAX
|
||||
#endif
|
||||
*/
|
||||
|
||||
#ifndef k_SwapBytes_Mode_MAX
|
||||
#define k_SwapBytes_Mode_MAX 0
|
||||
#endif
|
||||
|
||||
#if (k_SwapBytes_Mode_MAX != 0) && defined(MY_CPU_AMD64)
|
||||
#define k_SwapBytes_Mode_MIN k_SwapBytes_Mode_SSE2
|
||||
#else
|
||||
#define k_SwapBytes_Mode_MIN 0
|
||||
#endif
|
||||
|
||||
#if (k_SwapBytes_Mode_MAX >= k_SwapBytes_Mode_AVX2)
|
||||
#define USE_SWAP_AVX2
|
||||
#endif
|
||||
#if (k_SwapBytes_Mode_MAX >= k_SwapBytes_Mode_SSSE3)
|
||||
#define USE_SWAP_SSSE3
|
||||
#endif
|
||||
#if (k_SwapBytes_Mode_MAX >= k_SwapBytes_Mode_SSE2)
|
||||
#define USE_SWAP_128
|
||||
#endif
|
||||
|
||||
#if k_SwapBytes_Mode_MAX <= k_SwapBytes_Mode_MIN || !defined(USE_SWAP_128)
|
||||
#define FORCE_SWAP_MODE
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_SWAP_128
|
||||
/*
|
||||
<mmintrin.h> MMX
|
||||
<xmmintrin.h> SSE
|
||||
<emmintrin.h> SSE2
|
||||
<pmmintrin.h> SSE3
|
||||
<tmmintrin.h> SSSE3
|
||||
<smmintrin.h> SSE4.1
|
||||
<nmmintrin.h> SSE4.2
|
||||
<ammintrin.h> SSE4A
|
||||
<wmmintrin.h> AES
|
||||
<immintrin.h> AVX, AVX2, FMA
|
||||
*/
|
||||
|
||||
#include <emmintrin.h> // sse2
|
||||
// typedef __m128i v128;
|
||||
|
||||
#define SWAP2_128(i) { \
|
||||
const __m128i v = *(const __m128i *)(const void *)(items + (i) * 8); \
|
||||
*( __m128i *)( void *)(items + (i) * 8) = \
|
||||
_mm_or_si128( \
|
||||
_mm_slli_epi16(v, 8), \
|
||||
_mm_srli_epi16(v, 8)); }
|
||||
// _mm_or_si128() has more ports to execute than _mm_add_epi16().
|
||||
|
||||
static
|
||||
#ifdef SWAP_ATTRIB_SSE2
|
||||
SWAP_ATTRIB_SSE2
|
||||
#endif
|
||||
void
|
||||
Z7_FASTCALL
|
||||
SwapBytes2_128(CSwapUInt16 *items, const CSwapUInt16 *lim)
|
||||
{
|
||||
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||
do
|
||||
{
|
||||
SWAP2_128(0) SWAP2_128(1) items += 2 * 8;
|
||||
SWAP2_128(0) SWAP2_128(1) items += 2 * 8;
|
||||
}
|
||||
while (items != lim);
|
||||
}
|
||||
|
||||
/*
|
||||
// sse2
|
||||
#define SWAP4_128_pack(i) { \
|
||||
__m128i v = *(const __m128i *)(const void *)(items + (i) * 4); \
|
||||
__m128i v0 = _mm_unpacklo_epi8(v, mask); \
|
||||
__m128i v1 = _mm_unpackhi_epi8(v, mask); \
|
||||
v0 = _mm_shufflelo_epi16(v0, 0x1b); \
|
||||
v1 = _mm_shufflelo_epi16(v1, 0x1b); \
|
||||
v0 = _mm_shufflehi_epi16(v0, 0x1b); \
|
||||
v1 = _mm_shufflehi_epi16(v1, 0x1b); \
|
||||
*(__m128i *)(void *)(items + (i) * 4) = _mm_packus_epi16(v0, v1); }
|
||||
|
||||
static
|
||||
#ifdef SWAP_ATTRIB_SSE2
|
||||
SWAP_ATTRIB_SSE2
|
||||
#endif
|
||||
void
|
||||
Z7_FASTCALL
|
||||
SwapBytes4_128_pack(CSwapUInt32 *items, const CSwapUInt32 *lim)
|
||||
{
|
||||
const __m128i mask = _mm_setzero_si128();
|
||||
// const __m128i mask = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||
do
|
||||
{
|
||||
SWAP4_128_pack(0); items += 1 * 4;
|
||||
// SWAP4_128_pack(0); SWAP4_128_pack(1); items += 2 * 4;
|
||||
}
|
||||
while (items != lim);
|
||||
}
|
||||
|
||||
// sse2
|
||||
#define SWAP4_128_shift(i) { \
|
||||
__m128i v = *(const __m128i *)(const void *)(items + (i) * 4); \
|
||||
__m128i v2; \
|
||||
v2 = _mm_or_si128( \
|
||||
_mm_slli_si128(_mm_and_si128(v, mask), 1), \
|
||||
_mm_and_si128(_mm_srli_si128(v, 1), mask)); \
|
||||
v = _mm_or_si128( \
|
||||
_mm_slli_epi32(v, 24), \
|
||||
_mm_srli_epi32(v, 24)); \
|
||||
*(__m128i *)(void *)(items + (i) * 4) = _mm_or_si128(v2, v); }
|
||||
|
||||
static
|
||||
#ifdef SWAP_ATTRIB_SSE2
|
||||
SWAP_ATTRIB_SSE2
|
||||
#endif
|
||||
void
|
||||
Z7_FASTCALL
|
||||
SwapBytes4_128_shift(CSwapUInt32 *items, const CSwapUInt32 *lim)
|
||||
{
|
||||
#define M1 0xff00
|
||||
const __m128i mask = _mm_set_epi32(M1, M1, M1, M1);
|
||||
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||
do
|
||||
{
|
||||
// SWAP4_128_shift(0) SWAP4_128_shift(1) items += 2 * 4;
|
||||
// SWAP4_128_shift(0) SWAP4_128_shift(1) items += 2 * 4;
|
||||
SWAP4_128_shift(0); items += 1 * 4;
|
||||
}
|
||||
while (items != lim);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
#if defined(USE_SWAP_SSSE3) || defined(USE_SWAP_AVX2)
|
||||
|
||||
#define SWAP_SHUF_REV_SEQ_2_VALS(v) (v)+1, (v)
|
||||
#define SWAP_SHUF_REV_SEQ_4_VALS(v) (v)+3, (v)+2, (v)+1, (v)
|
||||
|
||||
#define SWAP2_SHUF_MASK_16_BYTES \
|
||||
SWAP_SHUF_REV_SEQ_2_VALS (0 * 2), \
|
||||
SWAP_SHUF_REV_SEQ_2_VALS (1 * 2), \
|
||||
SWAP_SHUF_REV_SEQ_2_VALS (2 * 2), \
|
||||
SWAP_SHUF_REV_SEQ_2_VALS (3 * 2), \
|
||||
SWAP_SHUF_REV_SEQ_2_VALS (4 * 2), \
|
||||
SWAP_SHUF_REV_SEQ_2_VALS (5 * 2), \
|
||||
SWAP_SHUF_REV_SEQ_2_VALS (6 * 2), \
|
||||
SWAP_SHUF_REV_SEQ_2_VALS (7 * 2)
|
||||
|
||||
#define SWAP4_SHUF_MASK_16_BYTES \
|
||||
SWAP_SHUF_REV_SEQ_4_VALS (0 * 4), \
|
||||
SWAP_SHUF_REV_SEQ_4_VALS (1 * 4), \
|
||||
SWAP_SHUF_REV_SEQ_4_VALS (2 * 4), \
|
||||
SWAP_SHUF_REV_SEQ_4_VALS (3 * 4)
|
||||
|
||||
#if defined(USE_SWAP_AVX2)
|
||||
/* if we use 256_BIT_INIT_MASK, each static array mask will be larger for 16 bytes */
|
||||
// #define SWAP_USE_256_BIT_INIT_MASK
|
||||
#endif
|
||||
|
||||
#if defined(SWAP_USE_256_BIT_INIT_MASK) && defined(USE_SWAP_AVX2)
|
||||
#define SWAP_MASK_INIT_SIZE 32
|
||||
#else
|
||||
#define SWAP_MASK_INIT_SIZE 16
|
||||
#endif
|
||||
|
||||
MY_ALIGN(SWAP_MASK_INIT_SIZE)
|
||||
static const Byte k_ShufMask_Swap2[] =
|
||||
{
|
||||
SWAP2_SHUF_MASK_16_BYTES
|
||||
#if SWAP_MASK_INIT_SIZE > 16
|
||||
, SWAP2_SHUF_MASK_16_BYTES
|
||||
#endif
|
||||
};
|
||||
|
||||
MY_ALIGN(SWAP_MASK_INIT_SIZE)
|
||||
static const Byte k_ShufMask_Swap4[] =
|
||||
{
|
||||
SWAP4_SHUF_MASK_16_BYTES
|
||||
#if SWAP_MASK_INIT_SIZE > 16
|
||||
, SWAP4_SHUF_MASK_16_BYTES
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#ifdef USE_SWAP_SSSE3
|
||||
|
||||
#include <tmmintrin.h> // ssse3
|
||||
|
||||
#define SHUF_128(i) *(items + (i)) = \
|
||||
_mm_shuffle_epi8(*(items + (i)), mask); // SSSE3
|
||||
|
||||
// Z7_NO_INLINE
|
||||
static
|
||||
#ifdef SWAP_ATTRIB_SSSE3
|
||||
SWAP_ATTRIB_SSSE3
|
||||
#endif
|
||||
Z7_ATTRIB_NO_VECTORIZE
|
||||
void
|
||||
Z7_FASTCALL
|
||||
ShufBytes_128(void *items8, const void *lim8, const void *mask128_ptr)
|
||||
{
|
||||
__m128i *items = (__m128i *)items8;
|
||||
const __m128i *lim = (const __m128i *)lim8;
|
||||
// const __m128i mask = _mm_set_epi8(SHUF_SWAP2_MASK_16_VALS);
|
||||
// const __m128i mask = _mm_set_epi8(SHUF_SWAP4_MASK_16_VALS);
|
||||
// const __m128i mask = _mm_load_si128((const __m128i *)(const void *)&(k_ShufMask_Swap4[0]));
|
||||
// const __m128i mask = _mm_load_si128((const __m128i *)(const void *)&(k_ShufMask_Swap4[0]));
|
||||
// const __m128i mask = *(const __m128i *)(const void *)&(k_ShufMask_Swap4[0]);
|
||||
const __m128i mask = *(const __m128i *)mask128_ptr;
|
||||
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||
do
|
||||
{
|
||||
SHUF_128(0) SHUF_128(1) items += 2;
|
||||
SHUF_128(0) SHUF_128(1) items += 2;
|
||||
}
|
||||
while (items != lim);
|
||||
}
|
||||
|
||||
#endif // USE_SWAP_SSSE3
|
||||
|
||||
|
||||
|
||||
#ifdef USE_SWAP_AVX2
|
||||
|
||||
#include <immintrin.h> // avx, avx2
|
||||
#if defined(__clang__)
|
||||
#include <avxintrin.h>
|
||||
#include <avx2intrin.h>
|
||||
#endif
|
||||
|
||||
#define SHUF_256(i) *(items + (i)) = \
|
||||
_mm256_shuffle_epi8(*(items + (i)), mask); // AVX2
|
||||
|
||||
// Z7_NO_INLINE
|
||||
static
|
||||
#ifdef SWAP_ATTRIB_AVX2
|
||||
SWAP_ATTRIB_AVX2
|
||||
#endif
|
||||
Z7_ATTRIB_NO_VECTORIZE
|
||||
void
|
||||
Z7_FASTCALL
|
||||
ShufBytes_256(void *items8, const void *lim8, const void *mask128_ptr)
|
||||
{
|
||||
__m256i *items = (__m256i *)items8;
|
||||
const __m256i *lim = (const __m256i *)lim8;
|
||||
/*
|
||||
UNUSED_VAR(mask128_ptr)
|
||||
__m256i mask =
|
||||
for Swap4: _mm256_setr_epi8(SWAP4_SHUF_MASK_16_BYTES, SWAP4_SHUF_MASK_16_BYTES);
|
||||
for Swap2: _mm256_setr_epi8(SWAP2_SHUF_MASK_16_BYTES, SWAP2_SHUF_MASK_16_BYTES);
|
||||
*/
|
||||
const __m256i mask =
|
||||
#if SWAP_MASK_INIT_SIZE > 16
|
||||
*(const __m256i *)(const void *)mask128_ptr;
|
||||
#else
|
||||
/* msvc: broadcastsi128() version reserves the stack for no reason
|
||||
msvc 19.29-: _mm256_insertf128_si256() / _mm256_set_m128i)) versions use non-avx movdqu xmm0,XMMWORD PTR [r8]
|
||||
msvc 19.30+ (VS2022): replaces _mm256_set_m128i(m,m) to vbroadcastf128(m) as we want
|
||||
*/
|
||||
// _mm256_broadcastsi128_si256(*mask128_ptr);
|
||||
#if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION < 80000)
|
||||
#define MY_mm256_set_m128i(hi, lo) _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1)
|
||||
#else
|
||||
#define MY_mm256_set_m128i _mm256_set_m128i
|
||||
#endif
|
||||
MY_mm256_set_m128i(
|
||||
*(const __m128i *)mask128_ptr,
|
||||
*(const __m128i *)mask128_ptr);
|
||||
#endif
|
||||
|
||||
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||
do
|
||||
{
|
||||
SHUF_256(0) SHUF_256(1) items += 2;
|
||||
SHUF_256(0) SHUF_256(1) items += 2;
|
||||
}
|
||||
while (items != lim);
|
||||
}
|
||||
|
||||
#endif // USE_SWAP_AVX2
|
||||
#endif // USE_SWAP_SSSE3 || USE_SWAP_AVX2
|
||||
#endif // USE_SWAP_128
|
||||
|
||||
|
||||
|
||||
// compile message "NEON intrinsics not available with the soft-float ABI"
|
||||
#elif defined(MY_CPU_ARM_OR_ARM64) \
|
||||
&& defined(MY_CPU_LE) \
|
||||
&& !defined(Z7_DISABLE_ARM_NEON)
|
||||
|
||||
#if defined(__clang__) && (__clang_major__ >= 8) \
|
||||
|| defined(__GNUC__) && (__GNUC__ >= 6)
|
||||
#if defined(__ARM_FP)
|
||||
#if (defined(__ARM_ARCH) && (__ARM_ARCH >= 4)) \
|
||||
|| defined(MY_CPU_ARM64)
|
||||
#if defined(MY_CPU_ARM64) \
|
||||
|| !defined(Z7_CLANG_VERSION) \
|
||||
|| defined(__ARM_NEON)
|
||||
#define USE_SWAP_128
|
||||
#ifdef MY_CPU_ARM64
|
||||
// #define SWAP_ATTRIB_NEON __attribute__((__target__("")))
|
||||
#else
|
||||
#if defined(Z7_CLANG_VERSION)
|
||||
// #define SWAP_ATTRIB_NEON __attribute__((__target__("neon")))
|
||||
#else
|
||||
// #pragma message("SWAP_ATTRIB_NEON __attribute__((__target__(fpu=neon))")
|
||||
#define SWAP_ATTRIB_NEON __attribute__((__target__("fpu=neon")))
|
||||
#endif
|
||||
#endif // MY_CPU_ARM64
|
||||
#endif // __ARM_NEON
|
||||
#endif // __ARM_ARCH
|
||||
#endif // __ARM_FP
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
#if (_MSC_VER >= 1910)
|
||||
#define USE_SWAP_128
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_SWAP_128
|
||||
#if defined(Z7_MSC_VER_ORIGINAL) && defined(MY_CPU_ARM64)
|
||||
#include <arm64_neon.h>
|
||||
#else
|
||||
|
||||
/*
|
||||
#if !defined(__ARM_NEON)
|
||||
#if defined(Z7_GCC_VERSION) && (__GNUC__ < 5) \
|
||||
|| defined(Z7_GCC_VERSION) && (__GNUC__ == 5) && (Z7_GCC_VERSION < 90201) \
|
||||
|| defined(Z7_GCC_VERSION) && (__GNUC__ == 5) && (Z7_GCC_VERSION < 100100)
|
||||
Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
|
||||
#pragma message("#define __ARM_NEON 1")
|
||||
// #define __ARM_NEON 1
|
||||
Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
|
||||
#endif
|
||||
#endif
|
||||
*/
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef USE_SWAP_128
|
||||
#define FORCE_SWAP_MODE
|
||||
#else
|
||||
|
||||
#ifdef MY_CPU_ARM64
|
||||
// for debug : comment it
|
||||
#define FORCE_SWAP_MODE
|
||||
#else
|
||||
#define k_SwapBytes_Mode_NEON 1
|
||||
#endif
|
||||
// typedef uint8x16_t v128;
|
||||
#define SWAP2_128(i) *(uint8x16_t *) (void *)(items + (i) * 8) = \
|
||||
vrev16q_u8(*(const uint8x16_t *)(const void *)(items + (i) * 8));
|
||||
#define SWAP4_128(i) *(uint8x16_t *) (void *)(items + (i) * 4) = \
|
||||
vrev32q_u8(*(const uint8x16_t *)(const void *)(items + (i) * 4));
|
||||
|
||||
// Z7_NO_INLINE
|
||||
static
|
||||
#ifdef SWAP_ATTRIB_NEON
|
||||
SWAP_ATTRIB_NEON
|
||||
#endif
|
||||
Z7_ATTRIB_NO_VECTORIZE
|
||||
void
|
||||
Z7_FASTCALL
|
||||
SwapBytes2_128(CSwapUInt16 *items, const CSwapUInt16 *lim)
|
||||
{
|
||||
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||
do
|
||||
{
|
||||
SWAP2_128(0) SWAP2_128(1) items += 2 * 8;
|
||||
SWAP2_128(0) SWAP2_128(1) items += 2 * 8;
|
||||
}
|
||||
while (items != lim);
|
||||
}
|
||||
|
||||
// Z7_NO_INLINE
|
||||
static
|
||||
#ifdef SWAP_ATTRIB_NEON
|
||||
SWAP_ATTRIB_NEON
|
||||
#endif
|
||||
Z7_ATTRIB_NO_VECTORIZE
|
||||
void
|
||||
Z7_FASTCALL
|
||||
SwapBytes4_128(CSwapUInt32 *items, const CSwapUInt32 *lim)
|
||||
{
|
||||
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||
do
|
||||
{
|
||||
SWAP4_128(0) SWAP4_128(1) items += 2 * 4;
|
||||
SWAP4_128(0) SWAP4_128(1) items += 2 * 4;
|
||||
}
|
||||
while (items != lim);
|
||||
}
|
||||
|
||||
#endif // USE_SWAP_128
|
||||
|
||||
#else // MY_CPU_ARM_OR_ARM64
|
||||
#define FORCE_SWAP_MODE
|
||||
#endif // MY_CPU_ARM_OR_ARM64
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if defined(Z7_MSC_VER_ORIGINAL) && defined(MY_CPU_X86)
|
||||
/* _byteswap_ushort() in MSVC x86 32-bit works via slow { mov dh, al; mov dl, ah }
|
||||
So we use own versions of byteswap function */
|
||||
#if (_MSC_VER < 1400 ) // old MSVC-X86 without _rotr16() support
|
||||
#define SWAP2_16(i) { UInt32 v = items[i]; v += (v << 16); v >>= 8; items[i] = (CSwapUInt16)v; }
|
||||
#else // is new MSVC-X86 with fast _rotr16()
|
||||
#include <intrin.h>
|
||||
#define SWAP2_16(i) { items[i] = _rotr16(items[i], 8); }
|
||||
#endif
|
||||
#else // is not MSVC-X86
|
||||
#define SWAP2_16(i) { CSwapUInt16 v = items[i]; items[i] = Z7_BSWAP16(v); }
|
||||
#endif // MSVC-X86
|
||||
|
||||
#if defined(Z7_CPU_FAST_BSWAP_SUPPORTED)
|
||||
#define SWAP4_32(i) { CSwapUInt32 v = items[i]; items[i] = Z7_BSWAP32(v); }
|
||||
#else
|
||||
#define SWAP4_32(i) \
|
||||
{ UInt32 v = items[i]; \
|
||||
v = ((v & 0xff00ff) << 8) + ((v >> 8) & 0xff00ff); \
|
||||
v = rotlFixed(v, 16); \
|
||||
items[i] = v; }
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#if defined(FORCE_SWAP_MODE) && defined(USE_SWAP_128)
|
||||
#define DEFAULT_Swap2 SwapBytes2_128
|
||||
#if !defined(MY_CPU_X86_OR_AMD64)
|
||||
#define DEFAULT_Swap4 SwapBytes4_128
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(DEFAULT_Swap2) || !defined(DEFAULT_Swap4)
|
||||
|
||||
#define SWAP_BASE_FUNCS_PREFIXES \
|
||||
Z7_FORCE_INLINE \
|
||||
static \
|
||||
Z7_ATTRIB_NO_VECTOR \
|
||||
void Z7_FASTCALL
|
||||
|
||||
|
||||
#if defined(MY_CPU_ARM_OR_ARM64)
|
||||
#if defined(__clang__)
|
||||
#pragma GCC diagnostic ignored "-Wlanguage-extension-token"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MY_CPU_64BIT
|
||||
|
||||
#if defined(MY_CPU_ARM64) \
|
||||
&& defined(__ARM_ARCH) && (__ARM_ARCH >= 8) \
|
||||
&& ( (defined(__GNUC__) && (__GNUC__ >= 4)) \
|
||||
|| (defined(__clang__) && (__clang_major__ >= 4)))
|
||||
|
||||
#define SWAP2_64_VAR(v) asm ("rev16 %x0,%x0" : "+r" (v));
|
||||
#define SWAP4_64_VAR(v) asm ("rev32 %x0,%x0" : "+r" (v));
|
||||
|
||||
#else // is not ARM64-GNU
|
||||
|
||||
#if !defined(MY_CPU_X86_OR_AMD64) || (k_SwapBytes_Mode_MIN == 0) || !defined(USE_SWAP_128)
|
||||
#define SWAP2_64_VAR(v) \
|
||||
v = ( 0x00ff00ff00ff00ff & (v >> 8)) \
|
||||
+ ((0x00ff00ff00ff00ff & v) << 8);
|
||||
/* plus gives faster code in MSVC */
|
||||
#endif
|
||||
|
||||
#ifdef Z7_CPU_FAST_BSWAP_SUPPORTED
|
||||
#define SWAP4_64_VAR(v) \
|
||||
v = Z7_BSWAP64(v); \
|
||||
v = Z7_ROTL64(v, 32);
|
||||
#else
|
||||
#define SWAP4_64_VAR(v) \
|
||||
v = ( 0x000000ff000000ff & (v >> 24)) \
|
||||
+ ((0x000000ff000000ff & v) << 24 ) \
|
||||
+ ( 0x0000ff000000ff00 & (v >> 8)) \
|
||||
+ ((0x0000ff000000ff00 & v) << 8 ) \
|
||||
;
|
||||
#endif
|
||||
|
||||
#endif // ARM64-GNU
|
||||
|
||||
|
||||
#ifdef SWAP2_64_VAR
|
||||
|
||||
#define SWAP2_64(i) { \
|
||||
UInt64 v = *(const UInt64 *)(const void *)(items + (i) * 4); \
|
||||
SWAP2_64_VAR(v) \
|
||||
*(UInt64 *)(void *)(items + (i) * 4) = v; }
|
||||
|
||||
SWAP_BASE_FUNCS_PREFIXES
|
||||
SwapBytes2_64(CSwapUInt16 *items, const CSwapUInt16 *lim)
|
||||
{
|
||||
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||
do
|
||||
{
|
||||
SWAP2_64(0) SWAP2_64(1) items += 2 * 4;
|
||||
SWAP2_64(0) SWAP2_64(1) items += 2 * 4;
|
||||
}
|
||||
while (items != lim);
|
||||
}
|
||||
|
||||
#define DEFAULT_Swap2 SwapBytes2_64
|
||||
#if !defined(FORCE_SWAP_MODE)
|
||||
#define SWAP2_DEFAULT_MODE 0
|
||||
#endif
|
||||
#else // !defined(SWAP2_64_VAR)
|
||||
#define DEFAULT_Swap2 SwapBytes2_128
|
||||
#if !defined(FORCE_SWAP_MODE)
|
||||
#define SWAP2_DEFAULT_MODE 1
|
||||
#endif
|
||||
#endif // SWAP2_64_VAR
|
||||
|
||||
|
||||
#define SWAP4_64(i) { \
|
||||
UInt64 v = *(const UInt64 *)(const void *)(items + (i) * 2); \
|
||||
SWAP4_64_VAR(v) \
|
||||
*(UInt64 *)(void *)(items + (i) * 2) = v; }
|
||||
|
||||
SWAP_BASE_FUNCS_PREFIXES
|
||||
SwapBytes4_64(CSwapUInt32 *items, const CSwapUInt32 *lim)
|
||||
{
|
||||
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||
do
|
||||
{
|
||||
SWAP4_64(0) SWAP4_64(1) items += 2 * 2;
|
||||
SWAP4_64(0) SWAP4_64(1) items += 2 * 2;
|
||||
}
|
||||
while (items != lim);
|
||||
}
|
||||
|
||||
#define DEFAULT_Swap4 SwapBytes4_64
|
||||
|
||||
#else // is not 64BIT
|
||||
|
||||
|
||||
#if defined(MY_CPU_ARM_OR_ARM64) \
|
||||
&& defined(__ARM_ARCH) && (__ARM_ARCH >= 6) \
|
||||
&& ( (defined(__GNUC__) && (__GNUC__ >= 4)) \
|
||||
|| (defined(__clang__) && (__clang_major__ >= 4)))
|
||||
|
||||
#ifdef MY_CPU_64BIT
|
||||
#define SWAP2_32_VAR(v) asm ("rev16 %w0,%w0" : "+r" (v));
|
||||
#else
|
||||
#define SWAP2_32_VAR(v) asm ("rev16 %0,%0" : "+r" (v)); // for clang/gcc
|
||||
// asm ("rev16 %r0,%r0" : "+r" (a)); // for gcc
|
||||
#endif
|
||||
|
||||
#elif defined(_MSC_VER) && (_MSC_VER < 1300) && defined(MY_CPU_X86) \
|
||||
|| !defined(Z7_CPU_FAST_BSWAP_SUPPORTED) \
|
||||
|| !defined(Z7_CPU_FAST_ROTATE_SUPPORTED)
|
||||
// old msvc doesn't support _byteswap_ulong()
|
||||
#define SWAP2_32_VAR(v) \
|
||||
v = ((v & 0xff00ff) << 8) + ((v >> 8) & 0xff00ff);
|
||||
|
||||
#else // is not ARM and is not old-MSVC-X86 and fast BSWAP/ROTATE are supported
|
||||
#define SWAP2_32_VAR(v) \
|
||||
v = Z7_BSWAP32(v); \
|
||||
v = rotlFixed(v, 16);
|
||||
|
||||
#endif // GNU-ARM*
|
||||
|
||||
#define SWAP2_32(i) { \
|
||||
UInt32 v = *(const UInt32 *)(const void *)(items + (i) * 2); \
|
||||
SWAP2_32_VAR(v); \
|
||||
*(UInt32 *)(void *)(items + (i) * 2) = v; }
|
||||
|
||||
|
||||
SWAP_BASE_FUNCS_PREFIXES
|
||||
SwapBytes2_32(CSwapUInt16 *items, const CSwapUInt16 *lim)
|
||||
{
|
||||
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||
do
|
||||
{
|
||||
SWAP2_32(0) SWAP2_32(1) items += 2 * 2;
|
||||
SWAP2_32(0) SWAP2_32(1) items += 2 * 2;
|
||||
}
|
||||
while (items != lim);
|
||||
}
|
||||
|
||||
|
||||
SWAP_BASE_FUNCS_PREFIXES
|
||||
SwapBytes4_32(CSwapUInt32 *items, const CSwapUInt32 *lim)
|
||||
{
|
||||
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||
do
|
||||
{
|
||||
SWAP4_32(0) SWAP4_32(1) items += 2;
|
||||
SWAP4_32(0) SWAP4_32(1) items += 2;
|
||||
}
|
||||
while (items != lim);
|
||||
}
|
||||
|
||||
#define DEFAULT_Swap2 SwapBytes2_32
|
||||
#define DEFAULT_Swap4 SwapBytes4_32
|
||||
#if !defined(FORCE_SWAP_MODE)
|
||||
#define SWAP2_DEFAULT_MODE 0
|
||||
#endif
|
||||
|
||||
#endif // MY_CPU_64BIT
|
||||
#endif // if !defined(DEFAULT_Swap2) || !defined(DEFAULT_Swap4)
|
||||
|
||||
|
||||
|
||||
#if !defined(FORCE_SWAP_MODE)
|
||||
static unsigned g_SwapBytes_Mode;
|
||||
#endif
|
||||
|
||||
/* size of largest unrolled loop iteration: 128 bytes = 4 * 32 bytes (AVX). */
|
||||
#define SWAP_ITERATION_BLOCK_SIZE_MAX (1 << 7)
|
||||
|
||||
// 32 bytes for (AVX) or 2 * 16-bytes for NEON.
|
||||
#define SWAP_VECTOR_ALIGN_SIZE (1 << 5)
|
||||
|
||||
Z7_NO_INLINE
|
||||
void z7_SwapBytes2(CSwapUInt16 *items, size_t numItems)
|
||||
{
|
||||
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||
for (; numItems != 0 && ((unsigned)(ptrdiff_t)items & (SWAP_VECTOR_ALIGN_SIZE - 1)) != 0; numItems--)
|
||||
{
|
||||
SWAP2_16(0)
|
||||
items++;
|
||||
}
|
||||
{
|
||||
const size_t k_Align_Mask = SWAP_ITERATION_BLOCK_SIZE_MAX / sizeof(CSwapUInt16) - 1;
|
||||
size_t numItems2 = numItems;
|
||||
CSwapUInt16 *lim;
|
||||
numItems &= k_Align_Mask;
|
||||
numItems2 &= ~(size_t)k_Align_Mask;
|
||||
lim = items + numItems2;
|
||||
if (numItems2 != 0)
|
||||
{
|
||||
#if !defined(FORCE_SWAP_MODE)
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
#ifdef USE_SWAP_AVX2
|
||||
if (g_SwapBytes_Mode > k_SwapBytes_Mode_SSSE3)
|
||||
ShufBytes_256((__m256i *)(void *)items,
|
||||
(const __m256i *)(const void *)lim,
|
||||
(const __m128i *)(const void *)&(k_ShufMask_Swap2[0]));
|
||||
else
|
||||
#endif
|
||||
#ifdef USE_SWAP_SSSE3
|
||||
if (g_SwapBytes_Mode >= k_SwapBytes_Mode_SSSE3)
|
||||
ShufBytes_128((__m128i *)(void *)items,
|
||||
(const __m128i *)(const void *)lim,
|
||||
(const __m128i *)(const void *)&(k_ShufMask_Swap2[0]));
|
||||
else
|
||||
#endif
|
||||
#endif // MY_CPU_X86_OR_AMD64
|
||||
#if SWAP2_DEFAULT_MODE == 0
|
||||
if (g_SwapBytes_Mode != 0)
|
||||
SwapBytes2_128(items, lim);
|
||||
else
|
||||
#endif
|
||||
#endif // FORCE_SWAP_MODE
|
||||
DEFAULT_Swap2(items, lim);
|
||||
}
|
||||
items = lim;
|
||||
}
|
||||
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||
for (; numItems != 0; numItems--)
|
||||
{
|
||||
SWAP2_16(0)
|
||||
items++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Z7_NO_INLINE
|
||||
void z7_SwapBytes4(CSwapUInt32 *items, size_t numItems)
|
||||
{
|
||||
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||
for (; numItems != 0 && ((unsigned)(ptrdiff_t)items & (SWAP_VECTOR_ALIGN_SIZE - 1)) != 0; numItems--)
|
||||
{
|
||||
SWAP4_32(0)
|
||||
items++;
|
||||
}
|
||||
{
|
||||
const size_t k_Align_Mask = SWAP_ITERATION_BLOCK_SIZE_MAX / sizeof(CSwapUInt32) - 1;
|
||||
size_t numItems2 = numItems;
|
||||
CSwapUInt32 *lim;
|
||||
numItems &= k_Align_Mask;
|
||||
numItems2 &= ~(size_t)k_Align_Mask;
|
||||
lim = items + numItems2;
|
||||
if (numItems2 != 0)
|
||||
{
|
||||
#if !defined(FORCE_SWAP_MODE)
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
#ifdef USE_SWAP_AVX2
|
||||
if (g_SwapBytes_Mode > k_SwapBytes_Mode_SSSE3)
|
||||
ShufBytes_256((__m256i *)(void *)items,
|
||||
(const __m256i *)(const void *)lim,
|
||||
(const __m128i *)(const void *)&(k_ShufMask_Swap4[0]));
|
||||
else
|
||||
#endif
|
||||
#ifdef USE_SWAP_SSSE3
|
||||
if (g_SwapBytes_Mode >= k_SwapBytes_Mode_SSSE3)
|
||||
ShufBytes_128((__m128i *)(void *)items,
|
||||
(const __m128i *)(const void *)lim,
|
||||
(const __m128i *)(const void *)&(k_ShufMask_Swap4[0]));
|
||||
else
|
||||
#endif
|
||||
#else // MY_CPU_X86_OR_AMD64
|
||||
|
||||
if (g_SwapBytes_Mode != 0)
|
||||
SwapBytes4_128(items, lim);
|
||||
else
|
||||
#endif // MY_CPU_X86_OR_AMD64
|
||||
#endif // FORCE_SWAP_MODE
|
||||
DEFAULT_Swap4(items, lim);
|
||||
}
|
||||
items = lim;
|
||||
}
|
||||
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
|
||||
for (; numItems != 0; numItems--)
|
||||
{
|
||||
SWAP4_32(0)
|
||||
items++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #define SHOW_HW_STATUS
|
||||
|
||||
#ifdef SHOW_HW_STATUS
|
||||
#include <stdio.h>
|
||||
#define PRF(x) x
|
||||
#else
|
||||
#define PRF(x)
|
||||
#endif
|
||||
|
||||
void z7_SwapBytesPrepare(void)
|
||||
{
|
||||
#ifndef FORCE_SWAP_MODE
|
||||
unsigned mode = 0; // k_SwapBytes_Mode_BASE;
|
||||
|
||||
#ifdef MY_CPU_ARM_OR_ARM64
|
||||
{
|
||||
if (CPU_IsSupported_NEON())
|
||||
{
|
||||
// #pragma message ("=== SwapBytes NEON")
|
||||
PRF(printf("\n=== SwapBytes NEON\n");)
|
||||
mode = k_SwapBytes_Mode_NEON;
|
||||
}
|
||||
}
|
||||
#else // MY_CPU_ARM_OR_ARM64
|
||||
{
|
||||
#ifdef USE_SWAP_AVX2
|
||||
if (CPU_IsSupported_AVX2())
|
||||
{
|
||||
// #pragma message ("=== SwapBytes AVX2")
|
||||
PRF(printf("\n=== SwapBytes AVX2\n");)
|
||||
mode = k_SwapBytes_Mode_AVX2;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef USE_SWAP_SSSE3
|
||||
if (CPU_IsSupported_SSSE3())
|
||||
{
|
||||
// #pragma message ("=== SwapBytes SSSE3")
|
||||
PRF(printf("\n=== SwapBytes SSSE3\n");)
|
||||
mode = k_SwapBytes_Mode_SSSE3;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#if !defined(MY_CPU_AMD64)
|
||||
if (CPU_IsSupported_SSE2())
|
||||
#endif
|
||||
{
|
||||
// #pragma message ("=== SwapBytes SSE2")
|
||||
PRF(printf("\n=== SwapBytes SSE2\n");)
|
||||
mode = k_SwapBytes_Mode_SSE2;
|
||||
}
|
||||
}
|
||||
#endif // MY_CPU_ARM_OR_ARM64
|
||||
g_SwapBytes_Mode = mode;
|
||||
// g_SwapBytes_Mode = 0; // for debug
|
||||
#endif // FORCE_SWAP_MODE
|
||||
PRF(printf("\n=== SwapBytesPrepare\n");)
|
||||
}
|
||||
|
||||
#undef PRF
|
||||
Vendored
+17
@@ -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
|
||||
Reference in new issue
Block a user