mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-01 07:33:12 +08:00
Build node:zlib on the zlib Node bundles (#2355)
This commit is contained in:
@@ -326,9 +326,9 @@ test.skipIf(
|
||||
|
||||
let vendorEntries = await readdir(vendorRoot);
|
||||
expect(vendorEntries.filter((name) => name.startsWith("mbedtls-")).length).toBe(2);
|
||||
// Host clang uses system zlib, so only the Zig build materializes a zlib
|
||||
// object family in the shared vendor root.
|
||||
expect(vendorEntries.filter((name) => name.startsWith("zlib-")).length).toBe(1);
|
||||
// Host clang and Zig each materialize their own vendored zlib object
|
||||
// family in the shared vendor root.
|
||||
expect(vendorEntries.filter((name) => name.startsWith("zlib-")).length).toBe(2);
|
||||
// Invalidate the host archive. A targetless Zig rebuild must continue to
|
||||
// use the separately keyed Zig archive instead of repairing or consuming
|
||||
// the host-clang entry.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import { basename, dirname, join, resolve } from "node:path";
|
||||
import { type CcDriver } from "./driver.js";
|
||||
import { resolvedToolIdentity, resolvedTool } from "./tool-identity.js";
|
||||
import { execFileAsync } from "./process.js";
|
||||
@@ -168,7 +168,7 @@ export function effectiveCompilerInvocationFingerprint(
|
||||
export async function implicitDependencyProbeIncludes(rtDir: string): Promise<string[]> {
|
||||
const vendor = join(rtDir, "..", "vendor");
|
||||
const quickjsSources = new Set<string>(LRE_SOURCES);
|
||||
const zlibSources = new Set<string>(ZLIB_SOURCES);
|
||||
const zlibSources = new Set<string>(ZLIB_SOURCES.map((source) => basename(source)));
|
||||
const fileGroups = await Promise.all([
|
||||
nativeSourceFiles(rtDir, false),
|
||||
nativeSourceFiles(join(vendor, "ryu"), false),
|
||||
@@ -181,7 +181,7 @@ export async function implicitDependencyProbeIncludes(rtDir: string): Promise<st
|
||||
nativeSourceFiles(join(vendor, "mbedtls", "library"), true),
|
||||
nativeSourceFiles(
|
||||
join(vendor, "zlib"),
|
||||
false,
|
||||
true,
|
||||
(name) => name.endsWith(".h") || zlibSources.has(name),
|
||||
),
|
||||
]);
|
||||
@@ -199,8 +199,10 @@ export async function implicitDependencyProbeIncludes(rtDir: string): Promise<st
|
||||
* __has_include finds them on arm64 too, where including them is an
|
||||
* #error. Covers the SSE/AVX intrinsic families (<emmintrin.h>,
|
||||
* <immintrin.h>, ...), <x86intrin.h>, <x86gprintrin.h> and <cpuid.h>. */
|
||||
/** clang's x86 intrinsic headers: every <...intrin.h> but the Windows
|
||||
* <intrin.h> (<xsaveintrin.h>, <immintrin.h>, ...), and <cpuid.h>. */
|
||||
function x86OnlyHeader(include: string): boolean {
|
||||
return include === "<cpuid.h>" || /^<(x86|x86gpr|[a-z]*mm)intrin\.h>$/.test(include);
|
||||
return include === "<cpuid.h>" || /^<[a-z0-9_]+intrin\.h>$/.test(include);
|
||||
}
|
||||
|
||||
/** One guarded line of the implicit-toolchain probe source: the header is
|
||||
|
||||
@@ -76,14 +76,9 @@ export interface CcOptions {
|
||||
fetch?: boolean;
|
||||
/** The program uses zlib (index.ts detects zlib.* libCalls on the IR):
|
||||
* compiles scr_zlib.c — the regex gating precedent, so zlib-free
|
||||
* binaries keep their exact link line. The default host-clang build links
|
||||
* the SYSTEM libz (macOS ships it), byte-identical to the historical line;
|
||||
* every Zig build compiles the vendored zlib with the selected driver instead
|
||||
* (ensureZlibObjects — zig has no libz in its sysroots). Compressed bytes may
|
||||
* differ between the
|
||||
* system and vendored libraries, which is why the corpus only ever
|
||||
* compares round-trips and fixed-blob inflation, never raw deflate
|
||||
* output. */
|
||||
* binaries keep their exact link line. Every driver compiles the vendored
|
||||
* zlib, the copy Node bundles (ensureZlibObjects), so compressed bytes match
|
||||
* Node's. */
|
||||
zlib?: boolean;
|
||||
/** The program uses node:zlib's Brotli forms (with zlib): compiles
|
||||
* scr_brotli.c and links the vendored brotli archive. */
|
||||
|
||||
@@ -217,18 +217,13 @@ const RUNTIME_UNITS: readonly RuntimeUnit[] = [
|
||||
// Blob and File (every blob.* call selects dynAsync, whose unit boxes
|
||||
// their reads as dyn promises).
|
||||
unit((u) => u.opts.dynAsync, "scr_blob.c"),
|
||||
// The zlib UNIT (scr_zlib.c) gates on zlib.* IR use; the LINK (system
|
||||
// libz on the default host-clang build, vendored objects on Zig builds)
|
||||
// also serves the native fetch's gzip decoder — spread exactly once.
|
||||
// The zlib UNIT (scr_zlib.c) gates on zlib.* IR use; the vendored zlib
|
||||
// objects also serve the native fetch's gzip decoder — spread exactly once.
|
||||
unitArgs((u) =>
|
||||
u.opts.zlib
|
||||
? isZigDriver(u.driver)
|
||||
? ["-I", vendorZlibDir(), u.rt(join(u.rtDir, "scr_zlib.c")), ...u.zlibObjects]
|
||||
: [u.rt(join(u.rtDir, "scr_zlib.c"))]
|
||||
? ["-I", vendorZlibDir(), u.rt(join(u.rtDir, "scr_zlib.c")), ...u.zlibObjects]
|
||||
: u.nativeFetch
|
||||
? isZigDriver(u.driver)
|
||||
? ["-I", vendorZlibDir(), ...u.zlibObjects]
|
||||
: []
|
||||
? ["-I", vendorZlibDir(), ...u.zlibObjects]
|
||||
: [],
|
||||
),
|
||||
// Brotli (scr_brotli.c) plugs into the zlib engine and links the
|
||||
@@ -674,11 +669,11 @@ export async function compileCInternal(
|
||||
let lreObjects = regex
|
||||
? lreObjectPaths(sanitize, driver, vendorBuildIdentity, vendorCacheRoot)
|
||||
: [];
|
||||
// Vendored zlib is the Zig story — default host-clang builds keep the exact
|
||||
// historical `-lz` system link (see CcOptions.zlib). The native fetch's
|
||||
// gzip decoder rides the same objects/link.
|
||||
// Every driver links the vendored zlib (the copy Node bundles), so
|
||||
// compressed bytes match Node's. The native fetch's gzip decoder rides the
|
||||
// same objects.
|
||||
let zlibObjects =
|
||||
((opts.zlib ?? false) || nativeFetch) && isZigDriver(driver)
|
||||
(opts.zlib ?? false) || nativeFetch
|
||||
? zlibObjectPaths(sanitize, driver, vendorBuildIdentity, vendorCacheRoot)
|
||||
: [];
|
||||
const materializeVendorPrerequisites = async (
|
||||
@@ -827,11 +822,6 @@ export async function compileCInternal(
|
||||
...(opts.linkInputs ?? []),
|
||||
...(opts.systemLibraries ?? []).map((name) => `-l${name}`),
|
||||
...(opts.frameworks ?? []).flatMap((name) => ["-framework", name]),
|
||||
// GNU ld resolves libraries from left to right and commonly enables
|
||||
// --as-needed: host-clang libz must follow scr_zlib.c/scr_fetch.c and every
|
||||
// generated/native input that references inflate symbols. Cross
|
||||
// and targetless Zig builds use vendored zlib objects in the input section above.
|
||||
...(((opts.zlib ?? false) || nativeFetch) && !isZigDriver(driver) ? ["-lz"] : []),
|
||||
...unwinderLinkArgs(driver),
|
||||
// glibc keeps libm separate from libc. This must trail the generated
|
||||
// program and every native FFI input because GNU ld resolves archives
|
||||
@@ -1085,7 +1075,6 @@ export async function compileCInternal(
|
||||
...(targetPlatform(driver) === "win32" ? ["-ladvapi32", "-liphlpapi", "-lws2_32"] : []),
|
||||
...(mbedtls && targetPlatform(driver) === "win32" ? ["-lbcrypt"] : []),
|
||||
...(tlsCa && targetPlatform(driver) === "win32" ? ["-lcrypt32"] : []),
|
||||
...(((opts.zlib ?? false) || nativeFetch) && !isZigDriver(driver) ? ["-lz"] : []),
|
||||
...unwinderLinkArgs(driver),
|
||||
...driver.linkArgs,
|
||||
...executableLinkFlags,
|
||||
@@ -1098,7 +1087,6 @@ export async function compileCInternal(
|
||||
...(targetPlatform(driver) === "win32" ? ["-ladvapi32", "-liphlpapi", "-lws2_32"] : []),
|
||||
...(mbedtls && targetPlatform(driver) === "win32" ? ["-lbcrypt"] : []),
|
||||
...(tlsCa && targetPlatform(driver) === "win32" ? ["-lcrypt32"] : []),
|
||||
...(((opts.zlib ?? false) || nativeFetch) && !isZigDriver(driver) ? ["-lz"] : []),
|
||||
...unwinderLinkArgs(driver),
|
||||
...driver.linkArgs,
|
||||
...executableLinkFlags,
|
||||
|
||||
@@ -78,9 +78,8 @@ import { CacheInputsChangedError } from "./session.js";
|
||||
* External-symbol contract: undefined references only to the target's C/math
|
||||
* runtime and system APIs. Windows embedders additionally link advapi32,
|
||||
* iphlpapi, and ws2_32; the platform driver supplies its ordinary CRT and
|
||||
* kernel imports. Zlib rides the VENDORED per-flavor objects here even on
|
||||
* hosts because the executable lane's system `-lz` cannot ride inside an
|
||||
* archive. */
|
||||
* kernel imports. Zlib rides the vendored per-flavor objects, as in the
|
||||
* executable lane. */
|
||||
|
||||
export async function compileLibArchive(opts: LibArchiveOptions): Promise<void> {
|
||||
clearCcCaches();
|
||||
|
||||
@@ -18,6 +18,12 @@ const execFileAsync = promisify(execFile);
|
||||
* runtime pack's executable_section_elimination flags). */
|
||||
const LRE_SECTION_FLAGS = ["-ffunction-sections", "-fdata-sections"];
|
||||
|
||||
/** A vendored source's object file name: sources in subdirectories
|
||||
* (zlib's contrib/optimizations/inflate.c) flatten to one directory. */
|
||||
function vendorObjectName(source: string): string {
|
||||
return source.replaceAll("/", "-").replace(/\.c$/, ".o");
|
||||
}
|
||||
|
||||
import {
|
||||
QJS_COMMIT,
|
||||
MBEDTLS_VERSION,
|
||||
@@ -25,6 +31,7 @@ import {
|
||||
BROTLI_VERSION,
|
||||
LRE_SOURCES,
|
||||
ZLIB_SOURCES,
|
||||
zlibInputs,
|
||||
} from "./vendor-inputs.js";
|
||||
export {
|
||||
QJS_COMMIT,
|
||||
@@ -243,11 +250,18 @@ export function createVendorArchives(context: VendorArchiveContext) {
|
||||
return join(runtimeSrcDir(), "..", "vendor", "zlib");
|
||||
}
|
||||
|
||||
/** The vendored zlib TUs behind Zig zlib support: every root *.c
|
||||
* except the gzFile file-I/O units (gz*.c — nothing in scr_zlib.c
|
||||
* references the gzFile API, and those TUs alone want unistd/io headers).
|
||||
* The default host-clang build links the system libz; Zig builds use this
|
||||
* list so targetless and explicit-target Zig inputs stay on one toolchain. */
|
||||
/** The vendored zlib TUs every C-lane build links (zlibInputs picks them
|
||||
* per target; the gzFile file-I/O units are never compiled, nothing in
|
||||
* scr_zlib.c references the gzFile API). */
|
||||
|
||||
/** The triple zlibInputs reads for a driver: its explicit target, else
|
||||
* the host. */
|
||||
function zlibTriple(driver: Pick<CcDriver, "target">): string {
|
||||
if (driver.target !== null) return driver.target;
|
||||
const cpu =
|
||||
process.arch === "x64" ? "x86_64" : process.arch === "arm64" ? "aarch64" : process.arch;
|
||||
return `${cpu}-${process.platform === "win32" ? "windows" : process.platform}`;
|
||||
}
|
||||
|
||||
function zlibObjectPaths(
|
||||
sanitize: boolean,
|
||||
@@ -260,15 +274,15 @@ export function createVendorArchives(context: VendorArchiveContext) {
|
||||
(driver.argv.length === 1 && driver.argv[0] === "clang" ? "" : "-zigcc") +
|
||||
`-${vendorCacheTargetFlavor(driver)}-${buildIdentity}`;
|
||||
const cacheDir = join(cacheRoot, `zlib-${ZLIB_VERSION}-${flavor}`);
|
||||
return ZLIB_SOURCES.map((f) => join(cacheDir, f.replace(/\.c$/, ".o")));
|
||||
return zlibInputs(zlibTriple(driver)).sources.map((f) => join(cacheDir, vendorObjectName(f)));
|
||||
}
|
||||
|
||||
/** The zlib objects for one flavor, compiled lazily on the first zlib-using
|
||||
* Zig build (~1s) and cached like the lre objects —
|
||||
* C-lane build (~1s) and cached like the lre objects —
|
||||
* <build-cache>/vendor/zlib-<version>-<flavor>-<target>-<toolchain>/*.o — with the same atomic-rename
|
||||
* publish (parallel first builds race safely; losers discard their work).
|
||||
* Plain is -Os, asan matches the final link so the sanitized lane
|
||||
* instruments the codec too. The flavor keys the driver and target exactly
|
||||
* Plain is -O3, as Node builds zlib; asan matches the final link so the
|
||||
* sanitized lane instruments the codec too. The flavor keys the driver and target exactly
|
||||
* like the lre flavor: the keying
|
||||
* must never hand a zig-built object set to a clang link off a shared
|
||||
* directory. */
|
||||
@@ -282,6 +296,7 @@ export function createVendorArchives(context: VendorArchiveContext) {
|
||||
(sanitize ? "asan" : "plain") +
|
||||
(driver.argv.length === 1 && driver.argv[0] === "clang" ? "" : "-zigcc") +
|
||||
`-${vendorCacheTargetFlavor(driver)}-${buildIdentity}`;
|
||||
const inputs = zlibInputs(zlibTriple(driver));
|
||||
return ensureVendorObjects({
|
||||
sanitize,
|
||||
driver,
|
||||
@@ -289,8 +304,9 @@ export function createVendorArchives(context: VendorArchiveContext) {
|
||||
flavor,
|
||||
name: "zlib",
|
||||
vendor: vendorZlibDir(),
|
||||
sources: ZLIB_SOURCES,
|
||||
sources: inputs.sources,
|
||||
objects: zlibObjectPaths(sanitize, driver, buildIdentity, cacheRoot),
|
||||
flags: [...(sanitize ? [] : ["-O3"]), ...inputs.defines.map((define) => `-D${define}`)],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -327,7 +343,7 @@ export function createVendorArchives(context: VendorArchiveContext) {
|
||||
"-c",
|
||||
join(vendor, f),
|
||||
"-o",
|
||||
join(buildDir, f.replace(/\.c$/, ".o")),
|
||||
join(buildDir, vendorObjectName(f)),
|
||||
],
|
||||
{ cwd: buildDir },
|
||||
);
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import { existsSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
import { expect, test } from "vitest";
|
||||
import { ZLIB_SOURCES, zlibInputs } from "./vendor-inputs.js";
|
||||
|
||||
const repoRoot = fileURLToPath(new URL("../../../..", import.meta.url));
|
||||
const zlibDir = join(repoRoot, "packages/runtime/vendor/zlib");
|
||||
|
||||
const TRIPLES = [
|
||||
// The runtime packs' targets.
|
||||
"x86_64-unknown-linux-gnu",
|
||||
"x86_64-unknown-linux-musl",
|
||||
"aarch64-unknown-linux-gnu",
|
||||
"aarch64-unknown-linux-musl",
|
||||
"aarch64-unknown-linux-android26",
|
||||
"arm64-apple-macosx14.0.0",
|
||||
"x86_64-apple-macosx14.0.0",
|
||||
"arm64-apple-ios15.0",
|
||||
"arm64-apple-ios15.0-simulator",
|
||||
"x86_64-pc-windows-msvc",
|
||||
"wasm32-unknown-wasi",
|
||||
// Zig cross targets and host spellings.
|
||||
"x86_64-linux-gnu",
|
||||
"aarch64-linux-musl",
|
||||
"aarch64-macos",
|
||||
"x86_64-windows-gnu",
|
||||
"aarch64-windows-gnu",
|
||||
"wasm32-wasi",
|
||||
"x86_64-linux",
|
||||
"aarch64-darwin",
|
||||
];
|
||||
|
||||
test("the compiler's zlib inputs match the runtime packs' for every target", async () => {
|
||||
const packInputs = (await import(
|
||||
pathToFileURL(join(repoRoot, "packages/runtime-pack-common/scripts/zlib-inputs.mjs")).href
|
||||
)) as { zlibInputs(triple: string): { sources: string[]; defines: string[] } };
|
||||
for (const triple of TRIPLES) {
|
||||
expect(zlibInputs(triple), triple).toEqual(packInputs.zlibInputs(triple));
|
||||
}
|
||||
});
|
||||
|
||||
test("every zlib input exists, and ZLIB_SOURCES lists every source a target compiles", () => {
|
||||
const listed = new Set<string>(ZLIB_SOURCES);
|
||||
for (const triple of TRIPLES) {
|
||||
for (const source of zlibInputs(triple).sources) {
|
||||
expect(listed.has(source), `${triple}: ${source}`).toBe(true);
|
||||
expect(existsSync(join(zlibDir, source)), source).toBe(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("zlib inputs follow Node's deps/zlib/zlib.gyp", () => {
|
||||
const x64 = zlibInputs("x86_64-unknown-linux-gnu");
|
||||
expect(x64.sources).toContain("adler32_simd.c");
|
||||
expect(x64.sources).toContain("contrib/optimizations/inflate.c");
|
||||
expect(x64.sources).not.toContain("inflate.c");
|
||||
expect(x64.defines).toEqual([
|
||||
"HAVE_HIDDEN",
|
||||
"ADLER32_SIMD_SSSE3",
|
||||
"X86_NOT_WINDOWS",
|
||||
"INFLATE_CHUNK_SIMD_SSE2",
|
||||
"INFLATE_CHUNK_READ_64LE",
|
||||
"DEFLATE_SLIDE_HASH_SSE2",
|
||||
]);
|
||||
expect(zlibInputs("x86_64-pc-windows-msvc").defines).toContain("X86_WINDOWS");
|
||||
const mac = zlibInputs("arm64-apple-macosx14.0.0");
|
||||
expect(mac.sources).toContain("crc32_simd.c");
|
||||
expect(mac.defines).toContain("ARMV8_OS_MACOS");
|
||||
expect(mac.defines).toContain("CRC32_ARMV8_CRC32");
|
||||
const ios = zlibInputs("arm64-apple-ios15.0");
|
||||
expect(ios.sources).not.toContain("crc32_simd.c");
|
||||
expect(ios.defines).not.toContain("CRC32_ARMV8_CRC32");
|
||||
expect(ios.defines).toContain("INFLATE_CHUNK_SIMD_NEON");
|
||||
expect(zlibInputs("aarch64-unknown-linux-android26").defines).toContain("ARMV8_OS_LINUX");
|
||||
const wasm = zlibInputs("wasm32-unknown-wasi");
|
||||
expect(wasm.sources).toContain("inflate.c");
|
||||
expect(wasm.sources).not.toContain("contrib/optimizations/inflate.c");
|
||||
expect(wasm.defines).toEqual(["HAVE_HIDDEN", "CPU_NO_SIMD"]);
|
||||
});
|
||||
@@ -1,22 +1,98 @@
|
||||
/** The pinned QuickJS, mbedTLS, zlib, and brotli inputs used by native recipes. */
|
||||
export const QJS_COMMIT = "3c8f3d68953955950074c41c6e4d999562ae82a7";
|
||||
export const MBEDTLS_VERSION = "3.6.7";
|
||||
export const ZLIB_VERSION = "1.3.1";
|
||||
/** The zlib Node v24.22.0 bundles (`process.versions.zlib` there), the
|
||||
* Chromium fork in Node's deps/zlib (packages/runtime/vendor/zlib). */
|
||||
export const ZLIB_VERSION = "1.3.2.1-motley-285e94b";
|
||||
/** The brotli release Node v24.22.0 bundles (packages/runtime/vendor/brotli). */
|
||||
export const BROTLI_VERSION = "1.2.0";
|
||||
/** Exact translation-unit membership shared by cache builds and external
|
||||
* source-pack recipes. */
|
||||
export const LRE_SOURCES = ["libregexp.c", "libunicode.c"] as const;
|
||||
export const ZLIB_SOURCES = [
|
||||
const ZLIB_COMMON_SOURCES = [
|
||||
"adler32.c",
|
||||
"compress.c",
|
||||
"cpu_features.c",
|
||||
"crc32.c",
|
||||
"deflate.c",
|
||||
"infback.c",
|
||||
"inffast.c",
|
||||
"inflate.c",
|
||||
"inftrees.c",
|
||||
"trees.c",
|
||||
"uncompr.c",
|
||||
"zutil.c",
|
||||
] as const;
|
||||
|
||||
/** Every zlib translation unit some target compiles (zlibInputs). */
|
||||
export const ZLIB_SOURCES = [
|
||||
...ZLIB_COMMON_SOURCES,
|
||||
"adler32_simd.c",
|
||||
"crc32_simd.c",
|
||||
"inflate.c",
|
||||
"contrib/optimizations/inffast_chunk.c",
|
||||
"contrib/optimizations/inflate.c",
|
||||
] as const;
|
||||
|
||||
/** The zlib translation units and defines for a target, chosen the way
|
||||
* Node's deps/zlib/zlib.gyp chooses them. The SIMD units carry their own
|
||||
* target attributes and check the CPU at run time, so every unit builds with
|
||||
* the same flags, and compressed output does not depend on the choice.
|
||||
* packages/runtime-pack-common/scripts/zlib-inputs.mjs keeps the same table
|
||||
* for the runtime packs. `triple` is an LLVM or Zig target triple. */
|
||||
export function zlibInputs(triple: string): { sources: string[]; defines: string[] } {
|
||||
const [cpu = "", ...rest] = triple.split("-");
|
||||
const system = rest.join("-");
|
||||
const architecture =
|
||||
cpu === "x86_64" || cpu === "amd64"
|
||||
? "x64"
|
||||
: cpu === "aarch64" || cpu === "arm64"
|
||||
? "arm64"
|
||||
: cpu;
|
||||
const ios = system.includes("ios");
|
||||
const windows =
|
||||
system.includes("windows") || system.includes("win32") || system.includes("mingw");
|
||||
// Android reads the CPU features through getauxval, as Linux does: Node's
|
||||
// ARMV8_OS_ANDROID path needs the NDK's cpu-features library.
|
||||
const linux = system.includes("linux") || system.includes("android");
|
||||
const mac = !ios && (system.includes("darwin") || system.includes("macos"));
|
||||
const sources: string[] = [...ZLIB_COMMON_SOURCES];
|
||||
const defines = windows ? [] : ["HAVE_HIDDEN"];
|
||||
if (architecture === "x64" && !ios) {
|
||||
sources.push(
|
||||
"adler32_simd.c",
|
||||
"contrib/optimizations/inffast_chunk.c",
|
||||
"contrib/optimizations/inflate.c",
|
||||
);
|
||||
defines.push(
|
||||
"ADLER32_SIMD_SSSE3",
|
||||
windows ? "X86_WINDOWS" : "X86_NOT_WINDOWS",
|
||||
"INFLATE_CHUNK_SIMD_SSE2",
|
||||
"INFLATE_CHUNK_READ_64LE",
|
||||
"DEFLATE_SLIDE_HASH_SSE2",
|
||||
);
|
||||
} else if (architecture === "arm64") {
|
||||
sources.push("contrib/optimizations/inffast_chunk.c", "contrib/optimizations/inflate.c");
|
||||
defines.push(
|
||||
"INFLATE_CHUNK_SIMD_NEON",
|
||||
"INFLATE_CHUNK_READ_64LE",
|
||||
"__ARM_NEON__",
|
||||
"DEFLATE_SLIDE_HASH_NEON",
|
||||
);
|
||||
if (windows) {
|
||||
defines.push("ARMV8_OS_WINDOWS");
|
||||
} else if (linux || mac) {
|
||||
// Node builds the Adler-32 and CRC-32 units for every arm64 target but
|
||||
// iOS and Windows.
|
||||
sources.push("adler32_simd.c", "crc32_simd.c");
|
||||
defines.push(
|
||||
"ADLER32_SIMD_NEON",
|
||||
"CRC32_ARMV8_CRC32",
|
||||
linux ? "ARMV8_OS_LINUX" : "ARMV8_OS_MACOS",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
sources.push("inflate.c");
|
||||
defines.push("CPU_NO_SIMD");
|
||||
}
|
||||
return { sources, defines };
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
selectedRuntimeUnits,
|
||||
type RuntimePackMode,
|
||||
} from "../backend/runtime-pack-core.js";
|
||||
import { LRE_SOURCES, ZLIB_SOURCES } from "../backend/vendor-inputs.js";
|
||||
import { LRE_SOURCES, zlibInputs } from "../backend/vendor-inputs.js";
|
||||
import { contentDigest, type NativeCache } from "./cache.js";
|
||||
import type { NativeToolchain } from "./toolchain.js";
|
||||
|
||||
@@ -171,9 +171,10 @@ export function buildSanitizedRuntime(
|
||||
directory = quickjs;
|
||||
args = ["-std=c11", "-I", quickjs];
|
||||
} else if (name === "zlib") {
|
||||
sources = ZLIB_SOURCES;
|
||||
const inputs = zlibInputs(toolchain.target.llvmTriple);
|
||||
sources = inputs.sources;
|
||||
directory = zlib;
|
||||
args = ["-std=c11", "-I", zlib];
|
||||
args = ["-std=c11", ...inputs.defines.map((define) => "-D" + define), "-I", zlib];
|
||||
} else if (name === "mbedtls") {
|
||||
directory = join(mbedtls, "library");
|
||||
sources = readdirSync(directory)
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/tests/corpus/8405-zlib-compressed-bytes.ts"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/tests/corpus/8406-zlib-inflate-chunks.cjs"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
import { createDeterministicArchive } from "./archive.mjs";
|
||||
import { installRuntimePack, withBuildLock } from "./build-state.mjs";
|
||||
import { shareIdenticalArtifacts } from "../../runtime-pack-common/scripts/share-artifacts.mjs";
|
||||
import { zlibInputs } from "../../runtime-pack-common/scripts/zlib-inputs.mjs";
|
||||
|
||||
const run = promisify(execFile);
|
||||
const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
||||
@@ -76,19 +77,7 @@ async function build() {
|
||||
const brotli = join(vendorRoot, "brotli", "c");
|
||||
const QJS_SOURCES = ["dtoa.c", "libregexp.c", "libunicode.c", "quickjs.c"];
|
||||
const LRE_SOURCES = ["libregexp.c", "libunicode.c"];
|
||||
const ZLIB_SOURCES = [
|
||||
"adler32.c",
|
||||
"compress.c",
|
||||
"crc32.c",
|
||||
"deflate.c",
|
||||
"infback.c",
|
||||
"inffast.c",
|
||||
"inflate.c",
|
||||
"inftrees.c",
|
||||
"trees.c",
|
||||
"uncompr.c",
|
||||
"zutil.c",
|
||||
];
|
||||
const ZLIB_BUILD = zlibInputs(RUNTIME_PACK_MATRIX.target.llvm_triple);
|
||||
|
||||
// Speed-flavor executable units are emitted through the host LLVM helper
|
||||
// so their object and import bitcode come from one promoted module. The
|
||||
@@ -309,11 +298,12 @@ async function build() {
|
||||
"-I",
|
||||
quickjs,
|
||||
]),
|
||||
await archive("zlib", ZLIB_SOURCES, zlib, [
|
||||
await archive("zlib", ZLIB_BUILD.sources, zlib, [
|
||||
"-target",
|
||||
RUNTIME_PACK_MATRIX.target.llvm_triple,
|
||||
"-std=c11",
|
||||
"-Os",
|
||||
"-O3",
|
||||
...ZLIB_BUILD.defines.map((define) => `-D${define}`),
|
||||
...codeAlignment,
|
||||
"-I",
|
||||
zlib,
|
||||
@@ -356,6 +346,7 @@ async function build() {
|
||||
],
|
||||
[join(vendorRoot, "unicode", "LICENSE"), "artifacts/licenses/unicode.txt", "Unicode-3.0"],
|
||||
[join(zlib, "LICENSE"), "artifacts/licenses/zlib.txt", "Zlib"],
|
||||
[join(zlib, "LICENSE.chromium"), "artifacts/licenses/zlib-chromium.txt", "BSD-3-Clause"],
|
||||
[join(vendorRoot, "brotli", "LICENSE"), "artifacts/licenses/brotli.txt", "MIT"],
|
||||
[join(mbedtls, "LICENSE"), "artifacts/licenses/mbedtls.txt", "Apache-2.0"],
|
||||
];
|
||||
|
||||
@@ -17,6 +17,7 @@ import { buildImportBitcode, buildRuntimeUnit, resolveRuntimeUnitHelper } from "
|
||||
import { installRuntimePack, withBuildLock } from "./build-state.mjs";
|
||||
import { shareIdenticalArtifacts } from "./share-artifacts.mjs";
|
||||
import { parallelMap } from "./parallel-map.mjs";
|
||||
import { zlibInputs } from "./zlib-inputs.mjs";
|
||||
|
||||
const run = promisify(execFile);
|
||||
const packageRoot = process.env.SCRIPTC_RUNTIME_PACK_ROOT;
|
||||
@@ -89,19 +90,7 @@ async function build() {
|
||||
const brotli = join(vendorRoot, "brotli", "c");
|
||||
const qjsSources = ["dtoa.c", "libregexp.c", "libunicode.c", "quickjs.c"];
|
||||
const lreSources = ["libregexp.c", "libunicode.c"];
|
||||
const zlibSources = [
|
||||
"adler32.c",
|
||||
"compress.c",
|
||||
"crc32.c",
|
||||
"deflate.c",
|
||||
"infback.c",
|
||||
"inffast.c",
|
||||
"inflate.c",
|
||||
"inftrees.c",
|
||||
"trees.c",
|
||||
"uncompr.c",
|
||||
"zutil.c",
|
||||
];
|
||||
const zlibBuild = zlibInputs(config.target.llvm_triple);
|
||||
const sha256 = async (path) =>
|
||||
createHash("sha256")
|
||||
.update(await readFile(path))
|
||||
@@ -400,10 +389,11 @@ async function build() {
|
||||
: []),
|
||||
...(requestedArchives.has("zlib")
|
||||
? [
|
||||
await archive("zlib", zlibSources, zlib, [
|
||||
await archive("zlib", zlibBuild.sources, zlib, [
|
||||
...vendorTarget,
|
||||
"-std=c11",
|
||||
"-Os",
|
||||
"-O3",
|
||||
...zlibBuild.defines.map((define) => `-D${define}`),
|
||||
"-I",
|
||||
zlib,
|
||||
]),
|
||||
@@ -454,6 +444,7 @@ async function build() {
|
||||
"BSD-3-Clause",
|
||||
],
|
||||
[join(zlib, "LICENSE"), "artifacts/licenses/zlib.txt", "Zlib"],
|
||||
[join(zlib, "LICENSE.chromium"), "artifacts/licenses/zlib-chromium.txt", "BSD-3-Clause"],
|
||||
[join(vendorRoot, "brotli", "LICENSE"), "artifacts/licenses/brotli.txt", "MIT"],
|
||||
[join(mbedtls, "LICENSE"), "artifacts/licenses/mbedtls.txt", "Apache-2.0"],
|
||||
];
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
// The translation units and defines of the vendored zlib (packages/runtime/vendor/zlib,
|
||||
// the copy Node v24.22.0 bundles in deps/zlib), chosen per target the way Node's
|
||||
// deps/zlib/zlib.gyp chooses them. The SIMD units carry their own target attributes
|
||||
// and check the CPU at run time, so every unit builds with the same flags. Compressed
|
||||
// output does not depend on these choices. packages/compiler/src/backend/vendor-inputs.ts
|
||||
// keeps the same table for cross builds; a unit test checks that the two agree.
|
||||
|
||||
const COMMON_SOURCES = [
|
||||
"adler32.c",
|
||||
"compress.c",
|
||||
"cpu_features.c",
|
||||
"crc32.c",
|
||||
"deflate.c",
|
||||
"infback.c",
|
||||
"inffast.c",
|
||||
"inftrees.c",
|
||||
"trees.c",
|
||||
"uncompr.c",
|
||||
"zutil.c",
|
||||
];
|
||||
|
||||
/**
|
||||
* @param {string} triple an LLVM or Zig target triple, such as
|
||||
* "x86_64-unknown-linux-gnu", "arm64-apple-ios15.0" or "aarch64-linux-musl".
|
||||
* @returns {{ sources: string[], defines: string[] }}
|
||||
*/
|
||||
export function zlibInputs(triple) {
|
||||
const [cpu = "", ...rest] = triple.split("-");
|
||||
const system = rest.join("-");
|
||||
const architecture =
|
||||
cpu === "x86_64" || cpu === "amd64"
|
||||
? "x64"
|
||||
: cpu === "aarch64" || cpu === "arm64"
|
||||
? "arm64"
|
||||
: cpu;
|
||||
const ios = system.includes("ios");
|
||||
const windows =
|
||||
system.includes("windows") || system.includes("win32") || system.includes("mingw");
|
||||
// Android reads the CPU features through getauxval, as Linux does: Node's
|
||||
// ARMV8_OS_ANDROID path needs the NDK's cpu-features library.
|
||||
const linux = system.includes("linux") || system.includes("android");
|
||||
const mac = !ios && (system.includes("darwin") || system.includes("macos"));
|
||||
const sources = [...COMMON_SOURCES];
|
||||
const defines = windows ? [] : ["HAVE_HIDDEN"];
|
||||
if (architecture === "x64" && !ios) {
|
||||
sources.push(
|
||||
"adler32_simd.c",
|
||||
"contrib/optimizations/inffast_chunk.c",
|
||||
"contrib/optimizations/inflate.c",
|
||||
);
|
||||
defines.push(
|
||||
"ADLER32_SIMD_SSSE3",
|
||||
windows ? "X86_WINDOWS" : "X86_NOT_WINDOWS",
|
||||
"INFLATE_CHUNK_SIMD_SSE2",
|
||||
"INFLATE_CHUNK_READ_64LE",
|
||||
"DEFLATE_SLIDE_HASH_SSE2",
|
||||
);
|
||||
} else if (architecture === "arm64") {
|
||||
sources.push("contrib/optimizations/inffast_chunk.c", "contrib/optimizations/inflate.c");
|
||||
defines.push(
|
||||
"INFLATE_CHUNK_SIMD_NEON",
|
||||
"INFLATE_CHUNK_READ_64LE",
|
||||
"__ARM_NEON__",
|
||||
"DEFLATE_SLIDE_HASH_NEON",
|
||||
);
|
||||
if (windows) {
|
||||
defines.push("ARMV8_OS_WINDOWS");
|
||||
} else if (linux || mac) {
|
||||
// Node builds the Adler-32 and CRC-32 units for every arm64 target but
|
||||
// iOS and Windows.
|
||||
sources.push("adler32_simd.c", "crc32_simd.c");
|
||||
defines.push(
|
||||
"ADLER32_SIMD_NEON",
|
||||
"CRC32_ARMV8_CRC32",
|
||||
linux ? "ARMV8_OS_LINUX" : "ARMV8_OS_MACOS",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
sources.push("inflate.c");
|
||||
defines.push("CPU_NO_SIMD");
|
||||
}
|
||||
return { sources, defines };
|
||||
}
|
||||
@@ -1,13 +1,10 @@
|
||||
/* node:zlib, the lowered slice: the one-shot zlib/raw-DEFLATE/gzip codecs
|
||||
* over u8 bytes with Node's DEFAULT options. Compiled ONLY when the program
|
||||
* uses zlib (native-toolchain.ts gates it exactly like scr_regex.c/libregexp),
|
||||
* so zlib-free binaries keep their historical link line. Host builds link
|
||||
* the system -lz; cross targets link the vendored zlib built per target
|
||||
* (ensureZlibObjects in native-toolchain.ts).
|
||||
*
|
||||
* Compressed OUTPUT bytes are zlib-version-dependent — the differential
|
||||
* corpus tests round-trips and fixed-blob inflation, never raw deflate
|
||||
* output. deflate of valid input cannot fail (OOM aborts); inflate of
|
||||
* so zlib-free binaries keep their historical link line. Every build links
|
||||
* the vendored zlib (packages/runtime/vendor/zlib), the copy Node bundles,
|
||||
* so compressed bytes match Node's for the same parameters. deflate of valid
|
||||
* input cannot fail (OOM aborts); inflate of
|
||||
* corrupt input THROWS Node's catchable Error (zlib's own msg text:
|
||||
* "incorrect header check", ...). */
|
||||
#include "scr_runtime.h"
|
||||
|
||||
Vendored
+6
-4
@@ -38,13 +38,15 @@ The native runtime pack build produces `libscriptc-quickjs.a` for the compiler b
|
||||
|
||||
## zlib/
|
||||
|
||||
- Project: https://github.com/madler/zlib
|
||||
- Version: 1.3.1 (release tarball zlib-1.3.1.tar.gz, sha256 9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23)
|
||||
- Project: https://chromium.googlesource.com/chromium/src/third_party/zlib (Chromium's zlib, a fork of https://github.com/madler/zlib)
|
||||
- Version: 1.3.2.1-motley-285e94b, the copy Node v24.22.0 bundles in `deps/zlib` (`process.versions.zlib`)
|
||||
- License: zlib (see zlib/LICENSE)
|
||||
|
||||
The CROSS-target arm of node:zlib (see packages/runtime/src/scr_zlib.c): host builds keep the historical system `-lz` link (macOS ships libz), but zig's cross sysroots have no libz, so SCRIPTC_TARGET builds compile this vendored copy per target instead. Only the flat `*.c`/`*.h` at the distribution root are vendored (LICENSE beside them) — contrib, tests, build machinery, and docs are not. No vendored file is modified; the gz* file-I/O TUs are vendored for faithfulness but never compiled (nothing references the gzFile API — see ZLIB_SOURCES in packages/compiler/src/backend/vendor-archives.ts). To update, re-fetch the release tarball, copy the same flat set, and bump `ZLIB_VERSION` in vendor-archives.ts.
|
||||
The codec behind node:zlib's gzip, deflate and inflate functions and streams (see packages/runtime/src/scr_zlib.c) and the native fetch's gzip decoder. The flat `*.c`/`*.h` files at the root of Node's `deps/zlib`, `contrib/optimizations/`, `LICENSE` and `README.chromium` are vendored; `contrib/minizip`, the other contrib directories, tests, patches, Chromium's build files and docs are not. No vendored file is modified, and the files match Node's copy. The gz* file-I/O units are vendored but never compiled (nothing references the gzFile API).
|
||||
|
||||
The objects build lazily on the first zlib-using cross compile into the per-user build cache's `vendor/zlib-<version>-<flavor>-<target>-<toolchain>/` directory — one flavor per driver/target and compiler environment/identity (the lre-objects pattern). Zlib-free binaries never compile any of this; compressed OUTPUT bytes are zlib-version-dependent, which is why the corpus only compares round-trips and fixed-blob inflation.
|
||||
Each target compiles the units and defines Node's `deps/zlib/zlib.gyp` selects for it: the SSSE3 Adler-32 and SSE2 inflate and slide-hash code on x86-64, the NEON code and the ARMv8 CRC-32 code on arm64 Linux, Android and macOS, the NEON inflate and slide-hash code on iOS and Windows arm64, and the portable code (`CPU_NO_SIMD`) elsewhere. The table is `zlibInputs` in packages/runtime-pack-common/scripts/zlib-inputs.mjs (runtime packs) and in packages/compiler/src/backend/vendor-inputs.ts (Zig cross builds and the sanitized runtime), and a unit test keeps the two identical. Android reads CPU features through `getauxval` as Linux does, where Node's Android build uses the NDK's cpu-features library. The SIMD units check the CPU at run time and give the same output as the portable code, so compressed bytes match Node's for the same parameters on every target. To update, copy the same files from the `deps/zlib` of the Node version scriptc follows and bump `ZLIB_VERSION` in vendor-inputs.ts.
|
||||
|
||||
Runtime packs archive zlib at `-O3`, as Node builds it. Zig cross builds compile the objects lazily on the first zlib-using cross compile into the per-user build cache's `vendor/zlib-<version>-<flavor>-<target>-<toolchain>/` directory, one flavor per driver/target and compiler environment/identity (the lre-objects pattern). Zlib-free binaries compile and link none of it.
|
||||
|
||||
## brotli/
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
Copyright notice:
|
||||
|
||||
(C) 1995-2022 Jean-loup Gailly and Mark Adler
|
||||
(C) 1995-2026 Jean-loup Gailly and Mark Adler
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// Copyright 2015 The Chromium Authors
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
Name: zlib
|
||||
Short Name: zlib
|
||||
URL: https://github.com/madler/zlib
|
||||
Version: 1.3.2
|
||||
Revision: 09a1572aa624e5ddb6c075dc013880de70b1b9b9
|
||||
Update Mechanism: Manual (https://crbug.com/422348588)
|
||||
CPEPrefix: cpe:/a:zlib:zlib:1.3.2
|
||||
Security Critical: yes
|
||||
Shipped: yes
|
||||
License: Zlib
|
||||
License File: LICENSE
|
||||
License Android Compatible: yes
|
||||
|
||||
Description:
|
||||
"A massively spiffy yet delicately unobtrusive compression library."
|
||||
|
||||
zlib is a free, general-purpose, legally unencumbered lossless data-compression
|
||||
library. zlib implements the "deflate" compression algorithm described by RFC
|
||||
1951, which combines the LZ77 (Lempel-Ziv) algorithm with Huffman coding. zlib
|
||||
also implements the zlib (RFC 1950) and gzip (RFC 1952) wrapper formats.
|
||||
|
||||
Local Modifications:
|
||||
- Only source code from the http://zlib.net distribution used to build the zlib
|
||||
and minizip libraries are present. Many other files have been omitted. Only *.c
|
||||
and *.h files from the upstream root directory, contrib/minizip and
|
||||
examples/zpipe.c were imported.
|
||||
- The files named '*simd*' are original x86/Arm/RISC-V specific optimizations.
|
||||
- The contents of the google directory are original Chromium-specific
|
||||
additions.
|
||||
- The contents of the 'contrib' of directory are either Chromium-specific
|
||||
additions or heavily patched zlib files (e.g. inffast_chunk*).
|
||||
- Added chromeconf.h
|
||||
- Plus the changes in 'patches' folder.
|
||||
- Code in contrib/ other than contrib/minizip was added to match zlib's
|
||||
contributor layout.
|
||||
- In sync with 1.3.2 official release
|
||||
- ZIP reader modified to allow for progress callbacks during extraction.
|
||||
- ZIP reader modified to add detection of AES encrypted content.
|
||||
+33
@@ -57,10 +57,27 @@
|
||||
# define MOD63(a) a %= BASE
|
||||
#endif
|
||||
|
||||
#include "cpu_features.h"
|
||||
#if defined(ADLER32_SIMD_SSSE3) || defined(ADLER32_SIMD_NEON) || defined(ADLER32_SIMD_RVV)
|
||||
#include "adler32_simd.h"
|
||||
#endif
|
||||
|
||||
/* ========================================================================= */
|
||||
uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len) {
|
||||
unsigned long sum2;
|
||||
unsigned n;
|
||||
/* TODO(cavalcantii): verify if this lengths are optimal for current CPUs. */
|
||||
#if defined(ADLER32_SIMD_SSSE3) || defined(ADLER32_SIMD_NEON) \
|
||||
|| defined(ADLER32_SIMD_RVV)
|
||||
#if defined(ADLER32_SIMD_SSSE3)
|
||||
if (buf != Z_NULL && len >= 64 && x86_cpu_enable_ssse3)
|
||||
#elif defined(ADLER32_SIMD_NEON)
|
||||
if (buf != Z_NULL && len >= 64)
|
||||
#elif defined(ADLER32_SIMD_RVV)
|
||||
if (buf != Z_NULL && len >= 32 && riscv_cpu_enable_rvv)
|
||||
#endif
|
||||
return adler32_simd_(adler, buf, len);
|
||||
#endif
|
||||
|
||||
/* split Adler-32 into component sums */
|
||||
sum2 = (adler >> 16) & 0xffff;
|
||||
@@ -77,9 +94,25 @@ uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len) {
|
||||
return adler | (sum2 << 16);
|
||||
}
|
||||
|
||||
#if defined(ADLER32_SIMD_SSSE3) || defined(ADLER32_SIMD_NEON) \
|
||||
|| defined(RISCV_RVV)
|
||||
/*
|
||||
* Use SIMD to compute the adler32. Since this function can be
|
||||
* freely used, check CPU features here. zlib convention is to
|
||||
* call adler32(0, NULL, 0), before making calls to adler32().
|
||||
* So this is a good early (and infrequent) place to cache CPU
|
||||
* features for those later, more interesting adler32() calls.
|
||||
*/
|
||||
if (buf == Z_NULL) {
|
||||
if (!len) /* Assume user is calling adler32(0, NULL, 0); */
|
||||
cpu_check_features();
|
||||
return 1L;
|
||||
}
|
||||
#else
|
||||
/* initial Adler-32 value (deferred check for len == 1 speed) */
|
||||
if (buf == Z_NULL)
|
||||
return 1L;
|
||||
#endif
|
||||
|
||||
/* in case short lengths are provided, keep it somewhat fast */
|
||||
if (len < 16) {
|
||||
|
||||
+459
@@ -0,0 +1,459 @@
|
||||
/* adler32_simd.c
|
||||
*
|
||||
* Copyright 2017 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*
|
||||
* Per http://en.wikipedia.org/wiki/Adler-32 the adler32 A value (aka s1) is
|
||||
* the sum of N input data bytes D1 ... DN,
|
||||
*
|
||||
* A = A0 + D1 + D2 + ... + DN
|
||||
*
|
||||
* where A0 is the initial value.
|
||||
*
|
||||
* SSE2 _mm_sad_epu8() can be used for byte sums (see http://bit.ly/2wpUOeD,
|
||||
* for example) and accumulating the byte sums can use SSE shuffle-adds (see
|
||||
* the "Integer" section of http://bit.ly/2erPT8t for details). Arm NEON has
|
||||
* similar instructions.
|
||||
*
|
||||
* The adler32 B value (aka s2) sums the A values from each step:
|
||||
*
|
||||
* B0 + (A0 + D1) + (A0 + D1 + D2) + ... + (A0 + D1 + D2 + ... + DN) or
|
||||
*
|
||||
* B0 + N.A0 + N.D1 + (N-1).D2 + (N-2).D3 + ... + (N-(N-1)).DN
|
||||
*
|
||||
* B0 being the initial value. For 32 bytes (ideal for garden-variety SIMD):
|
||||
*
|
||||
* B = B0 + 32.A0 + [D1 D2 D3 ... D32] x [32 31 30 ... 1].
|
||||
*
|
||||
* Adjacent blocks of 32 input bytes can be iterated with the expressions to
|
||||
* compute the adler32 s1 s2 of M >> 32 input bytes [1].
|
||||
*
|
||||
* As M grows, the s1 s2 sums grow. If left unchecked, they would eventually
|
||||
* overflow the precision of their integer representation (bad). However, s1
|
||||
* and s2 also need to be computed modulo the adler BASE value (reduced). If
|
||||
* at most NMAX bytes are processed before a reduce, s1 s2 _cannot_ overflow
|
||||
* a uint32_t type (the NMAX constraint) [2].
|
||||
*
|
||||
* [1] the iterative equations for s2 contain constant factors; these can be
|
||||
* hoisted from the n-blocks do loop of the SIMD code.
|
||||
*
|
||||
* [2] zlib adler32_z() uses this fact to implement NMAX-block-based updates
|
||||
* of the adler s1 s2 of uint32_t type (see adler32.c).
|
||||
*/
|
||||
|
||||
#include "adler32_simd.h"
|
||||
|
||||
/* Definitions from adler32.c: largest prime smaller than 65536 */
|
||||
#define BASE 65521U
|
||||
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
|
||||
#define NMAX 5552
|
||||
|
||||
#if defined(ADLER32_SIMD_SSSE3)
|
||||
|
||||
#include <tmmintrin.h>
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
__attribute__((__target__("ssse3")))
|
||||
#endif
|
||||
uint32_t ZLIB_INTERNAL adler32_simd_( /* SSSE3 */
|
||||
uint32_t adler,
|
||||
const unsigned char *buf,
|
||||
z_size_t len)
|
||||
{
|
||||
/*
|
||||
* Split Adler-32 into component sums.
|
||||
*/
|
||||
uint32_t s1 = adler & 0xffff;
|
||||
uint32_t s2 = adler >> 16;
|
||||
|
||||
/*
|
||||
* Process the data in blocks.
|
||||
*/
|
||||
const unsigned BLOCK_SIZE = 1 << 5;
|
||||
|
||||
z_size_t blocks = len / BLOCK_SIZE;
|
||||
len -= blocks * BLOCK_SIZE;
|
||||
|
||||
while (blocks)
|
||||
{
|
||||
unsigned n = NMAX / BLOCK_SIZE; /* The NMAX constraint. */
|
||||
if (n > blocks)
|
||||
n = (unsigned) blocks;
|
||||
blocks -= n;
|
||||
|
||||
const __m128i tap1 =
|
||||
_mm_setr_epi8(32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17);
|
||||
const __m128i tap2 =
|
||||
_mm_setr_epi8(16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1);
|
||||
const __m128i zero =
|
||||
_mm_setr_epi8( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
const __m128i ones =
|
||||
_mm_set_epi16( 1, 1, 1, 1, 1, 1, 1, 1);
|
||||
|
||||
/*
|
||||
* Process n blocks of data. At most NMAX data bytes can be
|
||||
* processed before s2 must be reduced modulo BASE.
|
||||
*/
|
||||
__m128i v_ps = _mm_set_epi32(0, 0, 0, s1 * n);
|
||||
__m128i v_s2 = _mm_set_epi32(0, 0, 0, s2);
|
||||
__m128i v_s1 = _mm_set_epi32(0, 0, 0, 0);
|
||||
|
||||
do {
|
||||
/*
|
||||
* Load 32 input bytes.
|
||||
*/
|
||||
const __m128i bytes1 = _mm_loadu_si128((__m128i*)(buf));
|
||||
const __m128i bytes2 = _mm_loadu_si128((__m128i*)(buf + 16));
|
||||
|
||||
/*
|
||||
* Add previous block byte sum to v_ps.
|
||||
*/
|
||||
v_ps = _mm_add_epi32(v_ps, v_s1);
|
||||
|
||||
/*
|
||||
* Horizontally add the bytes for s1, multiply-adds the
|
||||
* bytes by [ 32, 31, 30, ... ] for s2.
|
||||
*/
|
||||
v_s1 = _mm_add_epi32(v_s1, _mm_sad_epu8(bytes1, zero));
|
||||
const __m128i mad1 = _mm_maddubs_epi16(bytes1, tap1);
|
||||
v_s2 = _mm_add_epi32(v_s2, _mm_madd_epi16(mad1, ones));
|
||||
|
||||
v_s1 = _mm_add_epi32(v_s1, _mm_sad_epu8(bytes2, zero));
|
||||
const __m128i mad2 = _mm_maddubs_epi16(bytes2, tap2);
|
||||
v_s2 = _mm_add_epi32(v_s2, _mm_madd_epi16(mad2, ones));
|
||||
|
||||
buf += BLOCK_SIZE;
|
||||
|
||||
} while (--n);
|
||||
|
||||
v_s2 = _mm_add_epi32(v_s2, _mm_slli_epi32(v_ps, 5));
|
||||
|
||||
/*
|
||||
* Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
|
||||
*/
|
||||
|
||||
#define S23O1 _MM_SHUFFLE(2,3,0,1) /* A B C D -> B A D C */
|
||||
#define S1O32 _MM_SHUFFLE(1,0,3,2) /* A B C D -> C D A B */
|
||||
|
||||
v_s1 = _mm_add_epi32(v_s1, _mm_shuffle_epi32(v_s1, S23O1));
|
||||
v_s1 = _mm_add_epi32(v_s1, _mm_shuffle_epi32(v_s1, S1O32));
|
||||
|
||||
s1 += _mm_cvtsi128_si32(v_s1);
|
||||
|
||||
v_s2 = _mm_add_epi32(v_s2, _mm_shuffle_epi32(v_s2, S23O1));
|
||||
v_s2 = _mm_add_epi32(v_s2, _mm_shuffle_epi32(v_s2, S1O32));
|
||||
|
||||
s2 = _mm_cvtsi128_si32(v_s2);
|
||||
|
||||
#undef S23O1
|
||||
#undef S1O32
|
||||
|
||||
/*
|
||||
* Reduce.
|
||||
*/
|
||||
s1 %= BASE;
|
||||
s2 %= BASE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle leftover data.
|
||||
*/
|
||||
if (len) {
|
||||
if (len >= 16) {
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
|
||||
len -= 16;
|
||||
}
|
||||
|
||||
while (len--) {
|
||||
s2 += (s1 += *buf++);
|
||||
}
|
||||
|
||||
if (s1 >= BASE)
|
||||
s1 -= BASE;
|
||||
s2 %= BASE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the recombined sums.
|
||||
*/
|
||||
return s1 | (s2 << 16);
|
||||
}
|
||||
|
||||
#elif defined(ADLER32_SIMD_NEON)
|
||||
|
||||
#include <arm_neon.h>
|
||||
|
||||
uint32_t ZLIB_INTERNAL adler32_simd_( /* NEON */
|
||||
uint32_t adler,
|
||||
const unsigned char *buf,
|
||||
z_size_t len)
|
||||
{
|
||||
/*
|
||||
* Split Adler-32 into component sums.
|
||||
*/
|
||||
uint32_t s1 = adler & 0xffff;
|
||||
uint32_t s2 = adler >> 16;
|
||||
|
||||
/*
|
||||
* Serially compute s1 & s2, until the data is 16-byte aligned.
|
||||
*/
|
||||
if ((uintptr_t)buf & 15) {
|
||||
while ((uintptr_t)buf & 15) {
|
||||
s2 += (s1 += *buf++);
|
||||
--len;
|
||||
}
|
||||
|
||||
if (s1 >= BASE)
|
||||
s1 -= BASE;
|
||||
s2 %= BASE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the data in blocks.
|
||||
*/
|
||||
const unsigned BLOCK_SIZE = 1 << 5;
|
||||
|
||||
z_size_t blocks = len / BLOCK_SIZE;
|
||||
len -= blocks * BLOCK_SIZE;
|
||||
|
||||
while (blocks)
|
||||
{
|
||||
unsigned n = NMAX / BLOCK_SIZE; /* The NMAX constraint. */
|
||||
if (n > blocks)
|
||||
n = (unsigned) blocks;
|
||||
blocks -= n;
|
||||
|
||||
/*
|
||||
* Process n blocks of data. At most NMAX data bytes can be
|
||||
* processed before s2 must be reduced modulo BASE.
|
||||
*/
|
||||
uint32x4_t v_s2 = (uint32x4_t) { 0, 0, 0, s1 * n };
|
||||
uint32x4_t v_s1 = (uint32x4_t) { 0, 0, 0, 0 };
|
||||
|
||||
uint16x8_t v_column_sum_1 = vdupq_n_u16(0);
|
||||
uint16x8_t v_column_sum_2 = vdupq_n_u16(0);
|
||||
uint16x8_t v_column_sum_3 = vdupq_n_u16(0);
|
||||
uint16x8_t v_column_sum_4 = vdupq_n_u16(0);
|
||||
|
||||
do {
|
||||
/*
|
||||
* Load 32 input bytes.
|
||||
*/
|
||||
const uint8x16_t bytes1 = vld1q_u8((uint8_t*)(buf));
|
||||
const uint8x16_t bytes2 = vld1q_u8((uint8_t*)(buf + 16));
|
||||
|
||||
/*
|
||||
* Add previous block byte sum to v_s2.
|
||||
*/
|
||||
v_s2 = vaddq_u32(v_s2, v_s1);
|
||||
|
||||
/*
|
||||
* Horizontally add the bytes for s1.
|
||||
*/
|
||||
v_s1 = vpadalq_u16(v_s1, vpadalq_u8(vpaddlq_u8(bytes1), bytes2));
|
||||
|
||||
/*
|
||||
* Vertically add the bytes for s2.
|
||||
*/
|
||||
v_column_sum_1 = vaddw_u8(v_column_sum_1, vget_low_u8 (bytes1));
|
||||
v_column_sum_2 = vaddw_u8(v_column_sum_2, vget_high_u8(bytes1));
|
||||
v_column_sum_3 = vaddw_u8(v_column_sum_3, vget_low_u8 (bytes2));
|
||||
v_column_sum_4 = vaddw_u8(v_column_sum_4, vget_high_u8(bytes2));
|
||||
|
||||
buf += BLOCK_SIZE;
|
||||
|
||||
} while (--n);
|
||||
|
||||
v_s2 = vshlq_n_u32(v_s2, 5);
|
||||
|
||||
/*
|
||||
* Multiply-add bytes by [ 32, 31, 30, ... ] for s2.
|
||||
*/
|
||||
v_s2 = vmlal_u16(v_s2, vget_low_u16 (v_column_sum_1),
|
||||
(uint16x4_t) { 32, 31, 30, 29 });
|
||||
v_s2 = vmlal_u16(v_s2, vget_high_u16(v_column_sum_1),
|
||||
(uint16x4_t) { 28, 27, 26, 25 });
|
||||
v_s2 = vmlal_u16(v_s2, vget_low_u16 (v_column_sum_2),
|
||||
(uint16x4_t) { 24, 23, 22, 21 });
|
||||
v_s2 = vmlal_u16(v_s2, vget_high_u16(v_column_sum_2),
|
||||
(uint16x4_t) { 20, 19, 18, 17 });
|
||||
v_s2 = vmlal_u16(v_s2, vget_low_u16 (v_column_sum_3),
|
||||
(uint16x4_t) { 16, 15, 14, 13 });
|
||||
v_s2 = vmlal_u16(v_s2, vget_high_u16(v_column_sum_3),
|
||||
(uint16x4_t) { 12, 11, 10, 9 });
|
||||
v_s2 = vmlal_u16(v_s2, vget_low_u16 (v_column_sum_4),
|
||||
(uint16x4_t) { 8, 7, 6, 5 });
|
||||
v_s2 = vmlal_u16(v_s2, vget_high_u16(v_column_sum_4),
|
||||
(uint16x4_t) { 4, 3, 2, 1 });
|
||||
|
||||
/*
|
||||
* Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
|
||||
*/
|
||||
uint32x2_t sum1 = vpadd_u32(vget_low_u32(v_s1), vget_high_u32(v_s1));
|
||||
uint32x2_t sum2 = vpadd_u32(vget_low_u32(v_s2), vget_high_u32(v_s2));
|
||||
uint32x2_t s1s2 = vpadd_u32(sum1, sum2);
|
||||
|
||||
s1 += vget_lane_u32(s1s2, 0);
|
||||
s2 += vget_lane_u32(s1s2, 1);
|
||||
|
||||
/*
|
||||
* Reduce.
|
||||
*/
|
||||
s1 %= BASE;
|
||||
s2 %= BASE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle leftover data.
|
||||
*/
|
||||
if (len) {
|
||||
if (len >= 16) {
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
s2 += (s1 += *buf++);
|
||||
|
||||
len -= 16;
|
||||
}
|
||||
|
||||
while (len--) {
|
||||
s2 += (s1 += *buf++);
|
||||
}
|
||||
|
||||
if (s1 >= BASE)
|
||||
s1 -= BASE;
|
||||
s2 %= BASE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the recombined sums.
|
||||
*/
|
||||
return s1 | (s2 << 16);
|
||||
}
|
||||
|
||||
#elif defined(ADLER32_SIMD_RVV)
|
||||
#include <riscv_vector.h>
|
||||
|
||||
/*
|
||||
* Patch by Simon Hosie, from:
|
||||
* https://github.com/cloudflare/zlib/pull/55
|
||||
*/
|
||||
|
||||
uint32_t ZLIB_INTERNAL adler32_simd_( /* RVV */
|
||||
uint32_t adler,
|
||||
const unsigned char *buf,
|
||||
unsigned long len)
|
||||
{
|
||||
size_t vl = __riscv_vsetvlmax_e8m2();
|
||||
const vuint16m4_t zero16 = __riscv_vmv_v_x_u16m4(0, vl);
|
||||
vuint16m4_t a_sum = zero16;
|
||||
vuint32m8_t b_sum = __riscv_vmv_v_x_u32m8(0, vl);
|
||||
|
||||
/* Deal with the part which is not a multiple of vl first; because it's
|
||||
* easier to zero-stuff the beginning of the checksum than it is to tweak the
|
||||
* multipliers and sums for odd lengths afterwards.
|
||||
*/
|
||||
size_t head = len & (vl - 1);
|
||||
if (head > 0) {
|
||||
vuint8m2_t zero8 = __riscv_vmv_v_x_u8m2(0, vl);
|
||||
vuint8m2_t in = __riscv_vle8_v_u8m2(buf, vl);
|
||||
in = __riscv_vslideup(zero8, in, vl - head, vl);
|
||||
vuint16m4_t in16 = __riscv_vwcvtu_x(in, vl);
|
||||
a_sum = in16;
|
||||
buf += head;
|
||||
}
|
||||
|
||||
/* We have a 32-bit accumulator, and in each iteration we add 22-times a
|
||||
* 16-bit value, plus another 16-bit value. We periodically subtract up to
|
||||
* 65535 times BASE to avoid overflow. b_overflow estimates how often we
|
||||
* need to do this subtraction.
|
||||
*/
|
||||
const int b_overflow = BASE / 23;
|
||||
int fixup = b_overflow;
|
||||
ssize_t iters = (len - head) / vl;
|
||||
while (iters > 0) {
|
||||
const vuint16m4_t a_overflow = __riscv_vrsub(a_sum, BASE, vl);
|
||||
int batch = iters < 22 ? iters : 22;
|
||||
iters -= batch;
|
||||
b_sum = __riscv_vwmaccu(b_sum, batch, a_sum, vl);
|
||||
vuint16m4_t a_batch = zero16, b_batch = zero16;
|
||||
|
||||
/* Do a short batch, where neither a_sum nor b_sum can overflow a 16-bit
|
||||
* register. Then add them back into the main accumulators.
|
||||
*/
|
||||
while (batch-- > 0) {
|
||||
vuint8m2_t in8 = __riscv_vle8_v_u8m2(buf, vl);
|
||||
buf += vl;
|
||||
b_batch = __riscv_vadd(b_batch, a_batch, vl);
|
||||
a_batch = __riscv_vwaddu_wv(a_batch, in8, vl);
|
||||
}
|
||||
vbool4_t ov = __riscv_vmsgeu(a_batch, a_overflow, vl);
|
||||
a_sum = __riscv_vadd(a_sum, a_batch, vl);
|
||||
a_sum = __riscv_vadd_mu(ov, a_sum, a_sum, 65536 - BASE, vl);
|
||||
b_sum = __riscv_vwaddu_wv(b_sum, b_batch, vl);
|
||||
if (--fixup <= 0) {
|
||||
b_sum = __riscv_vnmsac(b_sum, BASE, __riscv_vsrl(b_sum, 16, vl), vl);
|
||||
fixup = b_overflow;
|
||||
}
|
||||
}
|
||||
/* Adjust per-lane sums to have appropriate offsets from the end of the
|
||||
* buffer.
|
||||
*/
|
||||
const vuint16m4_t off = __riscv_vrsub(__riscv_vid_v_u16m4(vl), vl, vl);
|
||||
vuint16m4_t bsum16 = __riscv_vncvt_x(__riscv_vremu(b_sum, BASE, vl), vl);
|
||||
b_sum = __riscv_vadd(__riscv_vwmulu(a_sum, off, vl),
|
||||
__riscv_vwmulu(bsum16, vl, vl), vl);
|
||||
bsum16 = __riscv_vncvt_x(__riscv_vremu(b_sum, BASE, vl), vl);
|
||||
|
||||
/* And finally, do a horizontal sum across the registers for the final
|
||||
* result.
|
||||
*/
|
||||
uint32_t a = adler & 0xffff;
|
||||
uint32_t b = ((adler >> 16) + a * (len % BASE)) % BASE;
|
||||
vuint32m1_t sca = __riscv_vmv_v_x_u32m1(a, 1);
|
||||
vuint32m1_t scb = __riscv_vmv_v_x_u32m1(b, 1);
|
||||
sca = __riscv_vwredsumu(a_sum, sca, vl);
|
||||
scb = __riscv_vwredsumu(bsum16, scb, vl);
|
||||
a = __riscv_vmv_x(sca);
|
||||
b = __riscv_vmv_x(scb);
|
||||
a %= BASE;
|
||||
b %= BASE;
|
||||
return (b << 16) | a;
|
||||
}
|
||||
|
||||
#endif /* ADLER32_SIMD_SSSE3 */
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/* adler32_simd.h
|
||||
*
|
||||
* Copyright 2017 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "zconf.h"
|
||||
#include "zutil.h"
|
||||
|
||||
uint32_t ZLIB_INTERNAL adler32_simd_(
|
||||
uint32_t adler,
|
||||
const unsigned char *buf,
|
||||
z_size_t len);
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
/* Copyright 2017 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file. */
|
||||
|
||||
#ifndef THIRD_PARTY_ZLIB_CHROMECONF_H_
|
||||
#define THIRD_PARTY_ZLIB_CHROMECONF_H_
|
||||
|
||||
#if defined(COMPONENT_BUILD)
|
||||
#if defined(WIN32)
|
||||
#if defined(ZLIB_IMPLEMENTATION)
|
||||
#define ZEXTERN __declspec(dllexport)
|
||||
#else
|
||||
#define ZEXTERN __declspec(dllimport)
|
||||
#endif
|
||||
#elif defined(ZLIB_IMPLEMENTATION)
|
||||
#define ZEXTERN __attribute__((visibility("default")))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Rename all zlib names with a Cr_z_ prefix. This is based on the Z_PREFIX
|
||||
* option from zconf.h, but with a custom prefix. Where zconf.h would rename
|
||||
* both a macro and its underscore-suffixed internal implementation (such as
|
||||
* deflateInit2 and deflateInit2_), only the implementation is renamed here.
|
||||
* The Byte type is also omitted.
|
||||
*
|
||||
* To generate this list, run
|
||||
* sed -rn -e 's/^# *define +([^ ]+) +(z_[^ ]+)$/#define \1 Cr_\2/p' zconf.h
|
||||
* (use -E instead of -r on macOS).
|
||||
*
|
||||
* gzread is also addressed by modifications in gzread.c and zlib.h. */
|
||||
|
||||
#define Z_CR_PREFIX_SET
|
||||
|
||||
#define _dist_code Cr_z__dist_code
|
||||
#define _length_code Cr_z__length_code
|
||||
#define _tr_align Cr_z__tr_align
|
||||
#define _tr_flush_bits Cr_z__tr_flush_bits
|
||||
#define _tr_flush_block Cr_z__tr_flush_block
|
||||
#define _tr_init Cr_z__tr_init
|
||||
#define _tr_stored_block Cr_z__tr_stored_block
|
||||
#define _tr_tally Cr_z__tr_tally
|
||||
#define adler32 Cr_z_adler32
|
||||
#define adler32_combine Cr_z_adler32_combine
|
||||
#define adler32_combine64 Cr_z_adler32_combine64
|
||||
#define adler32_z Cr_z_adler32_z
|
||||
#define compress Cr_z_compress
|
||||
#define compress2 Cr_z_compress2
|
||||
#define compress_z Cr_z_compress_z
|
||||
#define compress2_z Cr_z_compress2_z
|
||||
#define compressBound Cr_z_compressBound
|
||||
#define compressBound_z Cr_z_compressBound_z
|
||||
#define crc32 Cr_z_crc32
|
||||
#define crc32_combine Cr_z_crc32_combine
|
||||
#define crc32_combine64 Cr_z_crc32_combine64
|
||||
#define crc32_combine_gen Cr_z_crc32_combine_gen
|
||||
#define crc32_combine_gen64 Cr_z_crc32_combine_gen64
|
||||
#define crc32_combine_op Cr_z_crc32_combine_op
|
||||
#define crc32_z Cr_z_crc32_z
|
||||
#define deflate Cr_z_deflate
|
||||
#define deflateBound Cr_z_deflateBound
|
||||
#define deflateBound_z Cr_z_deflateBound_z
|
||||
#define deflateCopy Cr_z_deflateCopy
|
||||
#define deflateEnd Cr_z_deflateEnd
|
||||
#define deflateGetDictionary Cr_z_deflateGetDictionary
|
||||
/* #undef deflateInit */
|
||||
/* #undef deflateInit2 */
|
||||
#define deflateInit2_ Cr_z_deflateInit2_
|
||||
#define deflateInit_ Cr_z_deflateInit_
|
||||
#define deflateParams Cr_z_deflateParams
|
||||
#define deflatePending Cr_z_deflatePending
|
||||
#define deflatePrime Cr_z_deflatePrime
|
||||
#define deflateReset Cr_z_deflateReset
|
||||
#define deflateResetKeep Cr_z_deflateResetKeep
|
||||
#define deflateSetDictionary Cr_z_deflateSetDictionary
|
||||
#define deflateSetHeader Cr_z_deflateSetHeader
|
||||
#define deflateTune Cr_z_deflateTune
|
||||
#define deflateUsed Cr_z_deflateUsed
|
||||
#define deflate_copyright Cr_z_deflate_copyright
|
||||
#define get_crc_table Cr_z_get_crc_table
|
||||
#define gz_error Cr_z_gz_error
|
||||
#define gz_intmax Cr_z_gz_intmax
|
||||
#define gz_strwinerror Cr_z_gz_strwinerror
|
||||
#define gzbuffer Cr_z_gzbuffer
|
||||
#define gzclearerr Cr_z_gzclearerr
|
||||
#define gzclose Cr_z_gzclose
|
||||
#define gzclose_r Cr_z_gzclose_r
|
||||
#define gzclose_w Cr_z_gzclose_w
|
||||
#define gzdirect Cr_z_gzdirect
|
||||
#define gzdopen Cr_z_gzdopen
|
||||
#define gzeof Cr_z_gzeof
|
||||
#define gzerror Cr_z_gzerror
|
||||
#define gzflush Cr_z_gzflush
|
||||
#define gzfread Cr_z_gzfread
|
||||
#define gzfwrite Cr_z_gzfwrite
|
||||
#define gzgetc Cr_z_gzgetc
|
||||
#define gzgetc_ Cr_z_gzgetc_
|
||||
#define gzgets Cr_z_gzgets
|
||||
#define gzoffset Cr_z_gzoffset
|
||||
#define gzoffset64 Cr_z_gzoffset64
|
||||
#define gzopen Cr_z_gzopen
|
||||
#define gzopen64 Cr_z_gzopen64
|
||||
#define gzopen_w Cr_z_gzopen_w
|
||||
#define gzprintf Cr_z_gzprintf
|
||||
#define gzputc Cr_z_gzputc
|
||||
#define gzputs Cr_z_gzputs
|
||||
#define gzread Cr_z_gzread
|
||||
#define gzrewind Cr_z_gzrewind
|
||||
#define gzseek Cr_z_gzseek
|
||||
#define gzseek64 Cr_z_gzseek64
|
||||
#define gzsetparams Cr_z_gzsetparams
|
||||
#define gztell Cr_z_gztell
|
||||
#define gztell64 Cr_z_gztell64
|
||||
#define gzungetc Cr_z_gzungetc
|
||||
#define gzvprintf Cr_z_gzvprintf
|
||||
#define gzwrite Cr_z_gzwrite
|
||||
#define inflate Cr_z_inflate
|
||||
#define inflateBack Cr_z_inflateBack
|
||||
#define inflateBackEnd Cr_z_inflateBackEnd
|
||||
/* #undef inflateBackInit */
|
||||
#define inflateBackInit_ Cr_z_inflateBackInit_
|
||||
#define inflateCodesUsed Cr_z_inflateCodesUsed
|
||||
#define inflateCopy Cr_z_inflateCopy
|
||||
#define inflateEnd Cr_z_inflateEnd
|
||||
#define inflateGetDictionary Cr_z_inflateGetDictionary
|
||||
#define inflateGetHeader Cr_z_inflateGetHeader
|
||||
/* #undef inflateInit */
|
||||
/* #undef inflateInit2 */
|
||||
#define inflateInit2_ Cr_z_inflateInit2_
|
||||
#define inflateInit_ Cr_z_inflateInit_
|
||||
#define inflateMark Cr_z_inflateMark
|
||||
#define inflatePrime Cr_z_inflatePrime
|
||||
#define inflateReset Cr_z_inflateReset
|
||||
#define inflateReset2 Cr_z_inflateReset2
|
||||
#define inflateResetKeep Cr_z_inflateResetKeep
|
||||
#define inflateSetDictionary Cr_z_inflateSetDictionary
|
||||
#define inflateSync Cr_z_inflateSync
|
||||
#define inflateSyncPoint Cr_z_inflateSyncPoint
|
||||
#define inflateUndermine Cr_z_inflateUndermine
|
||||
#define inflateValidate Cr_z_inflateValidate
|
||||
#define inflate_copyright Cr_z_inflate_copyright
|
||||
#define inflate_fast Cr_z_inflate_fast
|
||||
#define inflate_table Cr_z_inflate_table
|
||||
#define inflate_fixed Cr_z_inflate_fixed
|
||||
#define uncompress Cr_z_uncompress
|
||||
#define uncompress2 Cr_z_uncompress2
|
||||
#define uncompress_z Cr_z_uncompress_z
|
||||
#define uncompress2_z Cr_z_uncompress2_z
|
||||
#define zError Cr_z_zError
|
||||
#define zcalloc Cr_z_zcalloc
|
||||
#define zcfree Cr_z_zcfree
|
||||
#define zlibCompileFlags Cr_z_zlibCompileFlags
|
||||
#define zlibVersion Cr_z_zlibVersion
|
||||
/* #undef Byte */
|
||||
#define Bytef Cr_z_Bytef
|
||||
#define alloc_func Cr_z_alloc_func
|
||||
#define charf Cr_z_charf
|
||||
#define free_func Cr_z_free_func
|
||||
#define gzFile Cr_z_gzFile
|
||||
#define gz_header Cr_z_gz_header
|
||||
#define gz_headerp Cr_z_gz_headerp
|
||||
#define in_func Cr_z_in_func
|
||||
#define intf Cr_z_intf
|
||||
#define out_func Cr_z_out_func
|
||||
#define uInt Cr_z_uInt
|
||||
#define uIntf Cr_z_uIntf
|
||||
#define uLong Cr_z_uLong
|
||||
#define uLongf Cr_z_uLongf
|
||||
#define voidp Cr_z_voidp
|
||||
#define voidpc Cr_z_voidpc
|
||||
#define voidpf Cr_z_voidpf
|
||||
#define gz_header_s Cr_z_gz_header_s
|
||||
/* #undef internal_state */
|
||||
/* #undef z_off64_t */
|
||||
|
||||
/* An exported symbol that isn't handled by Z_PREFIX in zconf.h */
|
||||
#define z_errmsg Cr_z_z_errmsg
|
||||
|
||||
/* Symbols added in simd.patch */
|
||||
#define copy_with_crc Cr_z_copy_with_crc
|
||||
#define crc_finalize Cr_z_crc_finalize
|
||||
#define crc_fold_512to32 Cr_z_crc_fold_512to32
|
||||
#define crc_fold_copy Cr_z_crc_fold_copy
|
||||
#define crc_fold_init Cr_z_crc_fold_init
|
||||
#define crc_reset Cr_z_crc_reset
|
||||
#define fill_window_sse Cr_z_fill_window_sse
|
||||
#define deflate_read_buf Cr_z_deflate_read_buf
|
||||
#define x86_check_features Cr_z_x86_check_features
|
||||
#define x86_cpu_enable_simd Cr_z_x86_cpu_enable_simd
|
||||
|
||||
/* Symbols added by adler_simd.c */
|
||||
#define adler32_simd_ Cr_z_adler32_simd_
|
||||
#define x86_cpu_enable_ssse3 Cr_z_x86_cpu_enable_ssse3
|
||||
|
||||
/* Symbols added by contrib/optimizations/inffast_chunk */
|
||||
#define inflate_fast_chunk_ Cr_z_inflate_fast_chunk_
|
||||
|
||||
/* Symbols added by crc32_simd.c */
|
||||
#define crc32_sse42_simd_ Cr_z_crc32_sse42_simd_
|
||||
|
||||
/* Symbols added by armv8_crc32 */
|
||||
#define arm_cpu_enable_crc32 Cr_z_arm_cpu_enable_crc32
|
||||
#define arm_cpu_enable_pmull Cr_z_arm_cpu_enable_pmull
|
||||
#define arm_check_features Cr_z_arm_check_features
|
||||
#define armv8_crc32_little Cr_z_armv8_crc32_little
|
||||
#define armv8_crc32_pmull_little Cr_z_armv8_crc32_pmull_little
|
||||
|
||||
/* Symbols added by cpu_features.c */
|
||||
#define cpu_check_features Cr_z_cpu_check_features
|
||||
#define x86_cpu_enable_sse2 Cr_z_x86_cpu_enable_sse2
|
||||
|
||||
#endif /* THIRD_PARTY_ZLIB_CHROMECONF_H_ */
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/* compare256.h
|
||||
*
|
||||
* This does 256-byte match comparison for deflate's longest_match.
|
||||
*
|
||||
* Copyright 2026 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*/
|
||||
#ifndef COMPARE256_H
|
||||
#define COMPARE256_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
/* Safe unaligned 16-bit load. Compilers optimize this into a single load
|
||||
* instruction. */
|
||||
static inline uint16_t read16(const void* p) {
|
||||
uint16_t v;
|
||||
memcpy(&v, p, sizeof(v));
|
||||
return v;
|
||||
}
|
||||
|
||||
/* Finds the byte offset (0..7) of the first difference in non-zero XOR mask
|
||||
* `x`:
|
||||
*/
|
||||
static inline int compare256_diff(uint64_t x) {
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
unsigned long i;
|
||||
_BitScanForward64(&i, x);
|
||||
return (int)i / 8;
|
||||
#else
|
||||
return __builtin_ctzll(x) / 8;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Returns the number of matching leading bytes (0 to 256) between src0 and
|
||||
* src1. Compares 8 bytes per iteration with early exit. */
|
||||
static inline int compare256(const unsigned char* src0,
|
||||
const unsigned char* src1) {
|
||||
int len = 0;
|
||||
do {
|
||||
uint64_t a, b, x;
|
||||
memcpy(&a, src0 + len, sizeof(a));
|
||||
memcpy(&b, src1 + len, sizeof(b));
|
||||
x = a ^ b;
|
||||
if (x)
|
||||
return len + compare256_diff(x);
|
||||
len += (int)sizeof(a);
|
||||
} while (len < 256);
|
||||
return 256;
|
||||
}
|
||||
|
||||
#endif /* COMPARE256_H */
|
||||
+45
-10
@@ -1,5 +1,5 @@
|
||||
/* compress.c -- compress a memory buffer
|
||||
* Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler
|
||||
* Copyright (C) 1995-2026 Jean-loup Gailly, Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@@ -18,13 +18,19 @@
|
||||
compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
|
||||
memory, Z_BUF_ERROR if there was not enough room in the output buffer,
|
||||
Z_STREAM_ERROR if the level parameter is invalid.
|
||||
|
||||
The _z versions of the functions take size_t length arguments.
|
||||
*/
|
||||
int ZEXPORT compress2(Bytef *dest, uLongf *destLen, const Bytef *source,
|
||||
uLong sourceLen, int level) {
|
||||
int ZEXPORT compress2_z(Bytef *dest, z_size_t *destLen, const Bytef *source,
|
||||
z_size_t sourceLen, int level) {
|
||||
z_stream stream;
|
||||
int err;
|
||||
const uInt max = (uInt)-1;
|
||||
uLong left;
|
||||
z_size_t left;
|
||||
|
||||
if ((sourceLen > 0 && source == NULL) ||
|
||||
destLen == NULL || (*destLen > 0 && dest == NULL))
|
||||
return Z_STREAM_ERROR;
|
||||
|
||||
left = *destLen;
|
||||
*destLen = 0;
|
||||
@@ -43,23 +49,36 @@ int ZEXPORT compress2(Bytef *dest, uLongf *destLen, const Bytef *source,
|
||||
|
||||
do {
|
||||
if (stream.avail_out == 0) {
|
||||
stream.avail_out = left > (uLong)max ? max : (uInt)left;
|
||||
stream.avail_out = left > (z_size_t)max ? max : (uInt)left;
|
||||
left -= stream.avail_out;
|
||||
}
|
||||
if (stream.avail_in == 0) {
|
||||
stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen;
|
||||
stream.avail_in = sourceLen > (z_size_t)max ? max :
|
||||
(uInt)sourceLen;
|
||||
sourceLen -= stream.avail_in;
|
||||
}
|
||||
err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH);
|
||||
} while (err == Z_OK);
|
||||
|
||||
*destLen = stream.total_out;
|
||||
*destLen = (z_size_t)(stream.next_out - dest);
|
||||
deflateEnd(&stream);
|
||||
return err == Z_STREAM_END ? Z_OK : err;
|
||||
}
|
||||
|
||||
int ZEXPORT compress2(Bytef *dest, uLongf *destLen, const Bytef *source,
|
||||
uLong sourceLen, int level) {
|
||||
int ret;
|
||||
z_size_t got = *destLen;
|
||||
ret = compress2_z(dest, &got, source, sourceLen, level);
|
||||
*destLen = (uLong)got;
|
||||
return ret;
|
||||
}
|
||||
/* ===========================================================================
|
||||
*/
|
||||
int ZEXPORT compress_z(Bytef *dest, z_size_t *destLen, const Bytef *source,
|
||||
z_size_t sourceLen) {
|
||||
return compress2_z(dest, destLen, source, sourceLen,
|
||||
Z_DEFAULT_COMPRESSION);
|
||||
}
|
||||
int ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source,
|
||||
uLong sourceLen) {
|
||||
return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
|
||||
@@ -69,7 +88,23 @@ int ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source,
|
||||
If the default memLevel or windowBits for deflateInit() is changed, then
|
||||
this function needs to be updated.
|
||||
*/
|
||||
z_size_t ZEXPORT compressBound_z(z_size_t sourceLen) {
|
||||
z_size_t bound = sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
|
||||
(sourceLen >> 25) + 13;
|
||||
|
||||
/* FIXME(cavalcantii): usage of CRC32 Castagnoli as a hash function
|
||||
* for the hash table of symbols used for compression has a side effect
|
||||
* where for compression level [4, 5] it will increase the output buffer size
|
||||
* by 0.1% (i.e. less than 1%) for a high entropy input (i.e. random data).
|
||||
* To avoid a scenario where client code would fail, for safety we increase
|
||||
* the expected output size by 0.8% (i.e. 8x more than the worst scenario).
|
||||
* See: http://crbug.com/990489
|
||||
*/
|
||||
bound += bound >> 7; // Equivalent to 1.0078125
|
||||
|
||||
return bound < sourceLen ? (z_size_t)-1 : bound;
|
||||
}
|
||||
uLong ZEXPORT compressBound(uLong sourceLen) {
|
||||
return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
|
||||
(sourceLen >> 25) + 13;
|
||||
z_size_t bound = compressBound_z(sourceLen);
|
||||
return (uLong)bound != bound ? (uLong)-1 : (uLong)bound;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,564 @@
|
||||
/* chunkcopy.h -- fast chunk copy and set operations
|
||||
* Copyright (C) 2017 ARM, Inc.
|
||||
* Copyright 2017 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef CHUNKCOPY_H
|
||||
#define CHUNKCOPY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "zutil.h"
|
||||
|
||||
#define Z_STATIC_ASSERT(name, assert) typedef char name[(assert) ? 1 : -1]
|
||||
|
||||
#if __STDC_VERSION__ >= 199901L
|
||||
#define Z_RESTRICT restrict
|
||||
#else
|
||||
#define Z_RESTRICT
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__) || defined(__llvm__)
|
||||
#define Z_BUILTIN_MEMCPY __builtin_memcpy
|
||||
#define Z_BUILTIN_MEMSET __builtin_memset
|
||||
#else
|
||||
#define Z_BUILTIN_MEMCPY zmemcpy
|
||||
#define Z_BUILTIN_MEMSET zmemset
|
||||
#endif
|
||||
|
||||
#if defined(INFLATE_CHUNK_SIMD_NEON)
|
||||
#include <arm_neon.h>
|
||||
typedef uint8x16_t z_vec128i_t;
|
||||
#elif defined(INFLATE_CHUNK_SIMD_SSE2)
|
||||
#include <emmintrin.h>
|
||||
typedef __m128i z_vec128i_t;
|
||||
#elif defined(INFLATE_CHUNK_GENERIC)
|
||||
typedef struct { uint8_t x[16]; } z_vec128i_t;
|
||||
#else
|
||||
#error chunkcopy.h inflate chunk SIMD is not defined for your build target
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Suppress MSan errors about copying uninitialized bytes (crbug.com/1376033).
|
||||
*/
|
||||
#define Z_DISABLE_MSAN
|
||||
#if defined(__has_feature)
|
||||
#if __has_feature(memory_sanitizer)
|
||||
#undef Z_DISABLE_MSAN
|
||||
#define Z_DISABLE_MSAN __attribute__((no_sanitize("memory")))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* chunk copy type: the z_vec128i_t type size should be exactly 128-bits
|
||||
* and equal to CHUNKCOPY_CHUNK_SIZE.
|
||||
*/
|
||||
#define CHUNKCOPY_CHUNK_SIZE sizeof(z_vec128i_t)
|
||||
|
||||
Z_STATIC_ASSERT(vector_128_bits_wide,
|
||||
CHUNKCOPY_CHUNK_SIZE == sizeof(int8_t) * 16);
|
||||
|
||||
/*
|
||||
* Ask the compiler to perform a wide, unaligned load with a machine
|
||||
* instruction appropriate for the z_vec128i_t type.
|
||||
*/
|
||||
static inline z_vec128i_t loadchunk(
|
||||
const unsigned char FAR* s) Z_DISABLE_MSAN {
|
||||
z_vec128i_t v;
|
||||
Z_BUILTIN_MEMCPY(&v, s, sizeof(v));
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ask the compiler to perform a wide, unaligned store with a machine
|
||||
* instruction appropriate for the z_vec128i_t type.
|
||||
*/
|
||||
static inline void storechunk(
|
||||
unsigned char FAR* d,
|
||||
const z_vec128i_t v) {
|
||||
Z_BUILTIN_MEMCPY(d, &v, sizeof(v));
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a memcpy-like operation, assuming that length is non-zero and that
|
||||
* it's OK to overwrite at least CHUNKCOPY_CHUNK_SIZE bytes of output even if
|
||||
* the length is shorter than this.
|
||||
*
|
||||
* It also guarantees that it will properly unroll the data if the distance
|
||||
* between `out` and `from` is at least CHUNKCOPY_CHUNK_SIZE, which we rely on
|
||||
* in chunkcopy_relaxed().
|
||||
*
|
||||
* Aside from better memory bus utilisation, this means that short copies
|
||||
* (CHUNKCOPY_CHUNK_SIZE bytes or fewer) will fall straight through the loop
|
||||
* without iteration, which will hopefully make the branch prediction more
|
||||
* reliable.
|
||||
*/
|
||||
static inline unsigned char FAR* chunkcopy_core(
|
||||
unsigned char FAR* out,
|
||||
const unsigned char FAR* from,
|
||||
unsigned len) Z_DISABLE_MSAN {
|
||||
const int bump = (--len % CHUNKCOPY_CHUNK_SIZE) + 1;
|
||||
storechunk(out, loadchunk(from));
|
||||
out += bump;
|
||||
from += bump;
|
||||
len /= CHUNKCOPY_CHUNK_SIZE;
|
||||
while (len-- > 0) {
|
||||
storechunk(out, loadchunk(from));
|
||||
out += CHUNKCOPY_CHUNK_SIZE;
|
||||
from += CHUNKCOPY_CHUNK_SIZE;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like chunkcopy_core(), but avoid writing beyond of legal output.
|
||||
*
|
||||
* Accepts an additional pointer to the end of safe output. A generic safe
|
||||
* copy would use (out + len), but it's normally the case that the end of the
|
||||
* output buffer is beyond the end of the current copy, and this can still be
|
||||
* exploited.
|
||||
*/
|
||||
static inline unsigned char FAR* chunkcopy_core_safe(
|
||||
unsigned char FAR* out,
|
||||
const unsigned char FAR* from,
|
||||
unsigned len,
|
||||
unsigned char FAR* limit) {
|
||||
Assert(out + len <= limit, "chunk copy exceeds safety limit");
|
||||
if ((limit - out) < (ptrdiff_t)CHUNKCOPY_CHUNK_SIZE) {
|
||||
const unsigned char FAR* Z_RESTRICT rfrom = from;
|
||||
Assert((uintptr_t)out - (uintptr_t)from >= len,
|
||||
"invalid restrict in chunkcopy_core_safe");
|
||||
Assert((uintptr_t)from - (uintptr_t)out >= len,
|
||||
"invalid restrict in chunkcopy_core_safe");
|
||||
if (len & 8) {
|
||||
Z_BUILTIN_MEMCPY(out, rfrom, 8);
|
||||
out += 8;
|
||||
rfrom += 8;
|
||||
}
|
||||
if (len & 4) {
|
||||
Z_BUILTIN_MEMCPY(out, rfrom, 4);
|
||||
out += 4;
|
||||
rfrom += 4;
|
||||
}
|
||||
if (len & 2) {
|
||||
Z_BUILTIN_MEMCPY(out, rfrom, 2);
|
||||
out += 2;
|
||||
rfrom += 2;
|
||||
}
|
||||
if (len & 1) {
|
||||
*out++ = *rfrom++;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
return chunkcopy_core(out, from, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform short copies until distance can be rewritten as being at least
|
||||
* CHUNKCOPY_CHUNK_SIZE.
|
||||
*
|
||||
* Assumes it's OK to overwrite at least the first 2*CHUNKCOPY_CHUNK_SIZE
|
||||
* bytes of output even if the copy is shorter than this. This assumption
|
||||
* holds within zlib inflate_fast(), which starts every iteration with at
|
||||
* least 258 bytes of output space available (258 being the maximum length
|
||||
* output from a single token; see inffast.c).
|
||||
*/
|
||||
static inline unsigned char FAR* chunkunroll_relaxed(
|
||||
unsigned char FAR* out,
|
||||
unsigned FAR* dist,
|
||||
unsigned FAR* len) Z_DISABLE_MSAN {
|
||||
const unsigned char FAR* from = out - *dist;
|
||||
while (*dist < *len && *dist < CHUNKCOPY_CHUNK_SIZE) {
|
||||
storechunk(out, loadchunk(from));
|
||||
out += *dist;
|
||||
*len -= *dist;
|
||||
*dist += *dist;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
#if defined(INFLATE_CHUNK_SIMD_NEON)
|
||||
/*
|
||||
* v_load64_dup(): load *src as an unaligned 64-bit int and duplicate it in
|
||||
* every 64-bit component of the 128-bit result (64-bit int splat).
|
||||
*/
|
||||
static inline z_vec128i_t v_load64_dup(const void* src) {
|
||||
return vcombine_u8(vld1_u8(src), vld1_u8(src));
|
||||
}
|
||||
|
||||
/*
|
||||
* v_load32_dup(): load *src as an unaligned 32-bit int and duplicate it in
|
||||
* every 32-bit component of the 128-bit result (32-bit int splat).
|
||||
*/
|
||||
static inline z_vec128i_t v_load32_dup(const void* src) {
|
||||
int32_t i32;
|
||||
Z_BUILTIN_MEMCPY(&i32, src, sizeof(i32));
|
||||
return vreinterpretq_u8_s32(vdupq_n_s32(i32));
|
||||
}
|
||||
|
||||
/*
|
||||
* v_load16_dup(): load *src as an unaligned 16-bit int and duplicate it in
|
||||
* every 16-bit component of the 128-bit result (16-bit int splat).
|
||||
*/
|
||||
static inline z_vec128i_t v_load16_dup(const void* src) {
|
||||
int16_t i16;
|
||||
Z_BUILTIN_MEMCPY(&i16, src, sizeof(i16));
|
||||
return vreinterpretq_u8_s16(vdupq_n_s16(i16));
|
||||
}
|
||||
|
||||
/*
|
||||
* v_load8_dup(): load the 8-bit int *src and duplicate it in every 8-bit
|
||||
* component of the 128-bit result (8-bit int splat).
|
||||
*/
|
||||
static inline z_vec128i_t v_load8_dup(const void* src) {
|
||||
return vld1q_dup_u8((const uint8_t*)src);
|
||||
}
|
||||
|
||||
/*
|
||||
* v_store_128(): store the 128-bit vec in a memory destination (that might
|
||||
* not be 16-byte aligned) void* out.
|
||||
*/
|
||||
static inline void v_store_128(void* out, const z_vec128i_t vec) {
|
||||
vst1q_u8(out, vec);
|
||||
}
|
||||
|
||||
#elif defined(INFLATE_CHUNK_SIMD_SSE2)
|
||||
/*
|
||||
* v_load64_dup(): load *src as an unaligned 64-bit int and duplicate it in
|
||||
* every 64-bit component of the 128-bit result (64-bit int splat).
|
||||
*/
|
||||
static inline z_vec128i_t v_load64_dup(const void* src) {
|
||||
int64_t i64;
|
||||
Z_BUILTIN_MEMCPY(&i64, src, sizeof(i64));
|
||||
return _mm_set1_epi64x(i64);
|
||||
}
|
||||
|
||||
/*
|
||||
* v_load32_dup(): load *src as an unaligned 32-bit int and duplicate it in
|
||||
* every 32-bit component of the 128-bit result (32-bit int splat).
|
||||
*/
|
||||
static inline z_vec128i_t v_load32_dup(const void* src) {
|
||||
int32_t i32;
|
||||
Z_BUILTIN_MEMCPY(&i32, src, sizeof(i32));
|
||||
return _mm_set1_epi32(i32);
|
||||
}
|
||||
|
||||
/*
|
||||
* v_load16_dup(): load *src as an unaligned 16-bit int and duplicate it in
|
||||
* every 16-bit component of the 128-bit result (16-bit int splat).
|
||||
*/
|
||||
static inline z_vec128i_t v_load16_dup(const void* src) {
|
||||
int16_t i16;
|
||||
Z_BUILTIN_MEMCPY(&i16, src, sizeof(i16));
|
||||
return _mm_set1_epi16(i16);
|
||||
}
|
||||
|
||||
/*
|
||||
* v_load8_dup(): load the 8-bit int *src and duplicate it in every 8-bit
|
||||
* component of the 128-bit result (8-bit int splat).
|
||||
*/
|
||||
static inline z_vec128i_t v_load8_dup(const void* src) {
|
||||
return _mm_set1_epi8(*(const char*)src);
|
||||
}
|
||||
|
||||
/*
|
||||
* v_store_128(): store the 128-bit vec in a memory destination (that might
|
||||
* not be 16-byte aligned) void* out.
|
||||
*/
|
||||
static inline void v_store_128(void* out, const z_vec128i_t vec) {
|
||||
_mm_storeu_si128((__m128i*)out, vec);
|
||||
}
|
||||
#elif defined(INFLATE_CHUNK_GENERIC)
|
||||
/*
|
||||
* Default implementations for chunk-copy functions rely on memcpy() being
|
||||
* inlined by the compiler for best performance. This is most likely to work
|
||||
* as expected when the length argument is constant (as is the case here) and
|
||||
* the target supports unaligned loads and stores. Since that's not always a
|
||||
* safe assumption, this may need extra compiler arguments such as
|
||||
* `-mno-strict-align` or `-munaligned-access`, or the availability of
|
||||
* extensions like SIMD.
|
||||
*/
|
||||
|
||||
/*
|
||||
* v_load64_dup(): load *src as an unaligned 64-bit int and duplicate it in
|
||||
* every 64-bit component of the 128-bit result (64-bit int splat).
|
||||
*/
|
||||
static inline z_vec128i_t v_load64_dup(const void* src) {
|
||||
int64_t in;
|
||||
Z_BUILTIN_MEMCPY(&in, src, sizeof(in));
|
||||
z_vec128i_t out;
|
||||
for (int i = 0; i < sizeof(out); i += sizeof(in)) {
|
||||
Z_BUILTIN_MEMCPY((uint8_t*)&out + i, &in, sizeof(in));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* v_load32_dup(): load *src as an unaligned 32-bit int and duplicate it in
|
||||
* every 32-bit component of the 128-bit result (32-bit int splat).
|
||||
*/
|
||||
static inline z_vec128i_t v_load32_dup(const void* src) {
|
||||
int32_t in;
|
||||
Z_BUILTIN_MEMCPY(&in, src, sizeof(in));
|
||||
z_vec128i_t out;
|
||||
for (int i = 0; i < sizeof(out); i += sizeof(in)) {
|
||||
Z_BUILTIN_MEMCPY((uint8_t*)&out + i, &in, sizeof(in));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* v_load16_dup(): load *src as an unaligned 16-bit int and duplicate it in
|
||||
* every 16-bit component of the 128-bit result (16-bit int splat).
|
||||
*/
|
||||
static inline z_vec128i_t v_load16_dup(const void* src) {
|
||||
int16_t in;
|
||||
Z_BUILTIN_MEMCPY(&in, src, sizeof(in));
|
||||
z_vec128i_t out;
|
||||
for (int i = 0; i < sizeof(out); i += sizeof(in)) {
|
||||
Z_BUILTIN_MEMCPY((uint8_t*)&out + i, &in, sizeof(in));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* v_load8_dup(): load the 8-bit int *src and duplicate it in every 8-bit
|
||||
* component of the 128-bit result (8-bit int splat).
|
||||
*/
|
||||
static inline z_vec128i_t v_load8_dup(const void* src) {
|
||||
int8_t in = *(const uint8_t*)src;
|
||||
z_vec128i_t out;
|
||||
Z_BUILTIN_MEMSET(&out, in, sizeof(out));
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* v_store_128(): store the 128-bit vec in a memory destination (that might
|
||||
* not be 16-byte aligned) void* out.
|
||||
*/
|
||||
static inline void v_store_128(void* out, const z_vec128i_t vec) {
|
||||
Z_BUILTIN_MEMCPY(out, &vec, sizeof(vec));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Perform an overlapping copy which behaves as a memset() operation, but
|
||||
* supporting periods other than one, and assume that length is non-zero and
|
||||
* that it's OK to overwrite at least CHUNKCOPY_CHUNK_SIZE*3 bytes of output
|
||||
* even if the length is shorter than this.
|
||||
*/
|
||||
static inline unsigned char FAR* chunkset_core(
|
||||
unsigned char FAR* out,
|
||||
unsigned period,
|
||||
unsigned len) {
|
||||
z_vec128i_t v;
|
||||
const int bump = ((len - 1) % sizeof(v)) + 1;
|
||||
|
||||
switch (period) {
|
||||
case 1:
|
||||
v = v_load8_dup(out - 1);
|
||||
v_store_128(out, v);
|
||||
out += bump;
|
||||
len -= bump;
|
||||
while (len > 0) {
|
||||
v_store_128(out, v);
|
||||
out += sizeof(v);
|
||||
len -= sizeof(v);
|
||||
}
|
||||
return out;
|
||||
case 2:
|
||||
v = v_load16_dup(out - 2);
|
||||
v_store_128(out, v);
|
||||
out += bump;
|
||||
len -= bump;
|
||||
if (len > 0) {
|
||||
v = v_load16_dup(out - 2);
|
||||
do {
|
||||
v_store_128(out, v);
|
||||
out += sizeof(v);
|
||||
len -= sizeof(v);
|
||||
} while (len > 0);
|
||||
}
|
||||
return out;
|
||||
case 4:
|
||||
v = v_load32_dup(out - 4);
|
||||
v_store_128(out, v);
|
||||
out += bump;
|
||||
len -= bump;
|
||||
if (len > 0) {
|
||||
v = v_load32_dup(out - 4);
|
||||
do {
|
||||
v_store_128(out, v);
|
||||
out += sizeof(v);
|
||||
len -= sizeof(v);
|
||||
} while (len > 0);
|
||||
}
|
||||
return out;
|
||||
case 8:
|
||||
v = v_load64_dup(out - 8);
|
||||
v_store_128(out, v);
|
||||
out += bump;
|
||||
len -= bump;
|
||||
if (len > 0) {
|
||||
v = v_load64_dup(out - 8);
|
||||
do {
|
||||
v_store_128(out, v);
|
||||
out += sizeof(v);
|
||||
len -= sizeof(v);
|
||||
} while (len > 0);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
out = chunkunroll_relaxed(out, &period, &len);
|
||||
return chunkcopy_core(out, out - period, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a memcpy-like operation, but assume that length is non-zero and that
|
||||
* it's OK to overwrite at least CHUNKCOPY_CHUNK_SIZE bytes of output even if
|
||||
* the length is shorter than this.
|
||||
*
|
||||
* Unlike chunkcopy_core() above, no guarantee is made regarding the behaviour
|
||||
* of overlapping buffers, regardless of the distance between the pointers.
|
||||
* This is reflected in the `restrict`-qualified pointers, allowing the
|
||||
* compiler to re-order loads and stores.
|
||||
*/
|
||||
static inline unsigned char FAR* chunkcopy_relaxed(
|
||||
unsigned char FAR* Z_RESTRICT out,
|
||||
const unsigned char FAR* Z_RESTRICT from,
|
||||
unsigned len) {
|
||||
Assert((uintptr_t)out - (uintptr_t)from >= len,
|
||||
"invalid restrict in chunkcopy_relaxed");
|
||||
Assert((uintptr_t)from - (uintptr_t)out >= len,
|
||||
"invalid restrict in chunkcopy_relaxed");
|
||||
return chunkcopy_core(out, from, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Like chunkcopy_relaxed(), but avoid writing beyond of legal output.
|
||||
*
|
||||
* Unlike chunkcopy_core_safe() above, no guarantee is made regarding the
|
||||
* behaviour of overlapping buffers, regardless of the distance between the
|
||||
* pointers. This is reflected in the `restrict`-qualified pointers, allowing
|
||||
* the compiler to re-order loads and stores.
|
||||
*
|
||||
* Accepts an additional pointer to the end of safe output. A generic safe
|
||||
* copy would use (out + len), but it's normally the case that the end of the
|
||||
* output buffer is beyond the end of the current copy, and this can still be
|
||||
* exploited.
|
||||
*/
|
||||
static inline unsigned char FAR* chunkcopy_safe(
|
||||
unsigned char FAR* out,
|
||||
const unsigned char FAR* Z_RESTRICT from,
|
||||
unsigned len,
|
||||
unsigned char FAR* limit) {
|
||||
Assert(out + len <= limit, "chunk copy exceeds safety limit");
|
||||
Assert((uintptr_t)out - (uintptr_t)from >= len,
|
||||
"invalid restrict in chunkcopy_safe");
|
||||
Assert((uintptr_t)from - (uintptr_t)out >= len,
|
||||
"invalid restrict in chunkcopy_safe");
|
||||
|
||||
return chunkcopy_core_safe(out, from, len, limit);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform chunky copy within the same buffer, where the source and destination
|
||||
* may potentially overlap.
|
||||
*
|
||||
* Assumes that len > 0 on entry, and that it's safe to write at least
|
||||
* CHUNKCOPY_CHUNK_SIZE*3 bytes to the output.
|
||||
*/
|
||||
static inline unsigned char FAR* chunkcopy_lapped_relaxed(
|
||||
unsigned char FAR* out,
|
||||
unsigned dist,
|
||||
unsigned len) {
|
||||
if (dist < len && dist < CHUNKCOPY_CHUNK_SIZE) {
|
||||
return chunkset_core(out, dist, len);
|
||||
}
|
||||
return chunkcopy_core(out, out - dist, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Behave like chunkcopy_lapped_relaxed(), but avoid writing beyond of legal
|
||||
* output.
|
||||
*
|
||||
* Accepts an additional pointer to the end of safe output. A generic safe
|
||||
* copy would use (out + len), but it's normally the case that the end of the
|
||||
* output buffer is beyond the end of the current copy, and this can still be
|
||||
* exploited.
|
||||
*/
|
||||
static inline unsigned char FAR* chunkcopy_lapped_safe(
|
||||
unsigned char FAR* out,
|
||||
unsigned dist,
|
||||
unsigned len,
|
||||
unsigned char FAR* limit) {
|
||||
Assert(out + len <= limit, "chunk copy exceeds safety limit");
|
||||
if ((limit - out) < (ptrdiff_t)(3 * CHUNKCOPY_CHUNK_SIZE)) {
|
||||
/* TODO(cavalcantii): try harder to optimise this */
|
||||
while (len-- > 0) {
|
||||
*out = *(out - dist);
|
||||
out++;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
return chunkcopy_lapped_relaxed(out, dist, len);
|
||||
}
|
||||
|
||||
/* TODO(cavalcanti): see crbug.com/1110083. */
|
||||
static inline unsigned char FAR* chunkcopy_safe_ugly(unsigned char FAR* out,
|
||||
unsigned dist,
|
||||
unsigned len,
|
||||
unsigned char FAR* limit) {
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
/* Speed is the same as using chunkcopy_safe
|
||||
w/ GCC on ARM (tested gcc 6.3 and 7.5) and avoids
|
||||
undefined behavior.
|
||||
*/
|
||||
return chunkcopy_core_safe(out, out - dist, len, limit);
|
||||
#elif defined(__clang__) && defined(ARMV8_OS_ANDROID) && !defined(__aarch64__)
|
||||
/* Seems to perform better on 32bit (i.e. Android). */
|
||||
return chunkcopy_core_safe(out, out - dist, len, limit);
|
||||
#else
|
||||
/* Seems to perform better on 64bit. */
|
||||
return chunkcopy_lapped_safe(out, dist, len, limit);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* The chunk-copy code above deals with writing the decoded DEFLATE data to
|
||||
* the output with SIMD methods to increase decode speed. Reading the input
|
||||
* to the DEFLATE decoder with a wide, SIMD method can also increase decode
|
||||
* speed. This option is supported on little endian machines, and reads the
|
||||
* input data in 64-bit (8 byte) chunks.
|
||||
*/
|
||||
|
||||
#ifdef INFLATE_CHUNK_READ_64LE
|
||||
/*
|
||||
* Buffer the input in a uint64_t (8 bytes) in the wide input reading case.
|
||||
*/
|
||||
typedef uint64_t inflate_holder_t;
|
||||
|
||||
/*
|
||||
* Ask the compiler to perform a wide, unaligned load of a uint64_t using a
|
||||
* machine instruction appropriate for the uint64_t type.
|
||||
*/
|
||||
static inline inflate_holder_t read64le(const unsigned char FAR *in) {
|
||||
inflate_holder_t input;
|
||||
Z_BUILTIN_MEMCPY(&input, in, sizeof(input));
|
||||
return input;
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* Otherwise, buffer the input bits using zlib's default input buffer type.
|
||||
*/
|
||||
typedef unsigned long inflate_holder_t;
|
||||
|
||||
#endif /* INFLATE_CHUNK_READ_64LE */
|
||||
|
||||
#undef Z_STATIC_ASSERT
|
||||
#undef Z_RESTRICT
|
||||
#undef Z_BUILTIN_MEMCPY
|
||||
#undef Z_DISABLE_MSAN
|
||||
|
||||
#endif /* CHUNKCOPY_H */
|
||||
@@ -0,0 +1,376 @@
|
||||
/* inffast_chunk.c -- fast decoding
|
||||
* Copyright (C) 1995-2026 Mark Adler
|
||||
* Copyright 2023 The Chromium Authors
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
#include "zutil.h"
|
||||
#include "inftrees.h"
|
||||
#include "inflate.h"
|
||||
#include "contrib/optimizations/inffast_chunk.h"
|
||||
#include "contrib/optimizations/chunkcopy.h"
|
||||
|
||||
#ifdef ASMINF
|
||||
# pragma message("Assembler code may have bugs -- use at your own risk")
|
||||
#else
|
||||
|
||||
/*
|
||||
Decode literal, length, and distance codes and write out the resulting
|
||||
literal and match bytes until either not enough input or output is
|
||||
available, an end-of-block is encountered, or a data error is encountered.
|
||||
When large enough input and output buffers are supplied to inflate(), for
|
||||
example, a 16K input buffer and a 64K output buffer, more than 95% of the
|
||||
inflate() execution time is spent in this routine.
|
||||
|
||||
Entry assumptions:
|
||||
|
||||
state->mode == LEN
|
||||
strm->avail_in >= INFLATE_FAST_MIN_INPUT (6 or 8 bytes + 7 bytes)
|
||||
strm->avail_out >= INFLATE_FAST_MIN_OUTPUT (258 bytes + 2 bytes)
|
||||
start >= strm->avail_out
|
||||
state->bits < 8
|
||||
(state->hold >> state->bits) == 0
|
||||
strm->next_out[0..strm->avail_out] does not overlap with
|
||||
strm->next_in[0..strm->avail_in]
|
||||
strm->state->window is allocated with an additional
|
||||
CHUNKCOPY_CHUNK_SIZE-1 bytes of padding beyond strm->state->wsize
|
||||
|
||||
On return, state->mode is one of:
|
||||
|
||||
LEN -- ran out of enough output space or enough available input
|
||||
TYPE -- reached end of block code, inflate() to interpret next block
|
||||
BAD -- error in block data
|
||||
|
||||
Notes:
|
||||
|
||||
INFLATE_FAST_MIN_INPUT: 6 or 8 bytes + 7 bytes
|
||||
|
||||
- The maximum input bits used by a length/distance pair is 15 bits for the
|
||||
length code, 5 bits for the length extra, 15 bits for the distance code,
|
||||
and 13 bits for the distance extra. This totals 48 bits, or six bytes.
|
||||
Therefore if strm->avail_in >= 6, then there is enough input to avoid
|
||||
checking for available input while decoding.
|
||||
|
||||
- The wide input data reading option reads 64 input bits at a time. Thus,
|
||||
if strm->avail_in >= 8, then there is enough input to avoid checking for
|
||||
available input while decoding. Reading consumes the input with:
|
||||
|
||||
hold |= read64le(in) << bits;
|
||||
in += 6;
|
||||
bits += 48;
|
||||
|
||||
reporting 6 bytes of new input because |bits| is 0..15 (2 bytes rounded
|
||||
up, worst case) and 6 bytes is enough to decode as noted above. At exit,
|
||||
hold &= (1U << bits) - 1 drops excess input to keep the invariant:
|
||||
|
||||
(state->hold >> state->bits) == 0
|
||||
|
||||
INFLATE_FAST_MIN_OUTPUT: 258 bytes + 2 bytes for literals = 260 bytes
|
||||
|
||||
- The maximum bytes that a single length/distance pair can output is 258
|
||||
bytes, which is the maximum length that can be coded. inflate_fast()
|
||||
requires strm->avail_out >= 260 for each loop to avoid checking for
|
||||
available output space while decoding.
|
||||
*/
|
||||
void ZLIB_INTERNAL inflate_fast_chunk_(z_streamp strm, unsigned start) {
|
||||
struct inflate_state FAR *state;
|
||||
z_const unsigned char FAR *in; /* local strm->next_in */
|
||||
z_const unsigned char FAR *last; /* have enough input while in < last */
|
||||
unsigned char FAR *out; /* local strm->next_out */
|
||||
unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
|
||||
unsigned char FAR *end; /* while out < end, enough space available */
|
||||
unsigned char FAR *limit; /* safety limit for chunky copies */
|
||||
#ifdef INFLATE_STRICT
|
||||
unsigned dmax; /* maximum distance from zlib header */
|
||||
#endif
|
||||
unsigned wsize; /* window size or zero if not using window */
|
||||
unsigned whave; /* valid bytes in the window */
|
||||
unsigned wnext; /* window write index */
|
||||
unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */
|
||||
inflate_holder_t hold; /* local strm->hold */
|
||||
unsigned bits; /* local strm->bits */
|
||||
code const FAR *lcode; /* local strm->lencode */
|
||||
code const FAR *dcode; /* local strm->distcode */
|
||||
unsigned lmask; /* mask for first level of length codes */
|
||||
unsigned dmask; /* mask for first level of distance codes */
|
||||
code const *here; /* retrieved table entry */
|
||||
unsigned op; /* code bits, operation, extra bits, or */
|
||||
/* window position, window bytes to copy */
|
||||
unsigned len; /* match length, unused bytes */
|
||||
unsigned dist; /* match distance */
|
||||
unsigned char FAR *from; /* where to copy match from */
|
||||
|
||||
/* copy state to local variables */
|
||||
state = (struct inflate_state FAR *)strm->state;
|
||||
in = strm->next_in;
|
||||
last = in + (strm->avail_in - (INFLATE_FAST_MIN_INPUT - 1));
|
||||
out = strm->next_out;
|
||||
beg = out - (start - strm->avail_out);
|
||||
end = out + (strm->avail_out - (INFLATE_FAST_MIN_OUTPUT - 1));
|
||||
limit = out + strm->avail_out;
|
||||
#ifdef INFLATE_STRICT
|
||||
dmax = state->dmax;
|
||||
#endif
|
||||
wsize = state->wsize;
|
||||
whave = state->whave;
|
||||
wnext = (state->wnext == 0 && whave >= wsize) ? wsize : state->wnext;
|
||||
window = state->window;
|
||||
hold = state->hold;
|
||||
bits = state->bits;
|
||||
lcode = state->lencode;
|
||||
dcode = state->distcode;
|
||||
lmask = (1U << state->lenbits) - 1;
|
||||
dmask = (1U << state->distbits) - 1;
|
||||
|
||||
#ifdef INFLATE_CHUNK_READ_64LE
|
||||
#define REFILL() do { \
|
||||
Assert(bits < 64, "### Too many bits in inflate_fast."); \
|
||||
hold |= read64le(in) << bits; \
|
||||
in += 7; \
|
||||
in -= bits >> 3; \
|
||||
bits |= 56; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/* decode literals and length/distances until end-of-block or not enough
|
||||
input data or output space */
|
||||
do {
|
||||
#ifdef INFLATE_CHUNK_READ_64LE
|
||||
REFILL();
|
||||
#else
|
||||
if (bits < 15) {
|
||||
hold += (unsigned long)(*in++) << bits;
|
||||
bits += 8;
|
||||
hold += (unsigned long)(*in++) << bits;
|
||||
bits += 8;
|
||||
}
|
||||
#endif
|
||||
here = lcode + (hold & lmask);
|
||||
#ifdef INFLATE_CHUNK_READ_64LE
|
||||
if (here->op == 0) { /* literal */
|
||||
Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ?
|
||||
"inflate: literal '%c'\n" :
|
||||
"inflate: literal 0x%02x\n", here->val));
|
||||
*out++ = (unsigned char)(here->val);
|
||||
hold >>= here->bits;
|
||||
bits -= here->bits;
|
||||
here = lcode + (hold & lmask);
|
||||
if (here->op == 0) { /* literal */
|
||||
Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ?
|
||||
"inflate: 2nd literal '%c'\n" :
|
||||
"inflate: 2nd literal 0x%02x\n", here->val));
|
||||
*out++ = (unsigned char)(here->val);
|
||||
hold >>= here->bits;
|
||||
bits -= here->bits;
|
||||
here = lcode + (hold & lmask);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
dolen:
|
||||
op = (unsigned)(here->bits);
|
||||
hold >>= op;
|
||||
bits -= op;
|
||||
op = (unsigned)(here->op);
|
||||
if (op == 0) { /* literal */
|
||||
Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ?
|
||||
"inflate: literal '%c'\n" :
|
||||
"inflate: literal 0x%02x\n", here->val));
|
||||
*out++ = (unsigned char)(here->val);
|
||||
}
|
||||
else if (op & 16) { /* length base */
|
||||
len = (unsigned)(here->val);
|
||||
op &= 15; /* number of extra bits */
|
||||
if (op) {
|
||||
#ifndef INFLATE_CHUNK_READ_64LE
|
||||
if (bits < op) {
|
||||
hold += (unsigned long)(*in++) << bits;
|
||||
bits += 8;
|
||||
}
|
||||
#endif
|
||||
len += (unsigned)hold & ((1U << op) - 1);
|
||||
hold >>= op;
|
||||
bits -= op;
|
||||
}
|
||||
Tracevv((stderr, "inflate: length %u\n", len));
|
||||
#ifndef INFLATE_CHUNK_READ_64LE
|
||||
if (bits < 15) {
|
||||
hold += (unsigned long)(*in++) << bits;
|
||||
bits += 8;
|
||||
hold += (unsigned long)(*in++) << bits;
|
||||
bits += 8;
|
||||
}
|
||||
#endif
|
||||
here = dcode + (hold & dmask);
|
||||
dodist:
|
||||
op = (unsigned)(here->bits);
|
||||
hold >>= op;
|
||||
bits -= op;
|
||||
op = (unsigned)(here->op);
|
||||
if (op & 16) { /* distance base */
|
||||
dist = (unsigned)(here->val);
|
||||
op &= 15; /* number of extra bits */
|
||||
/* we have two fast-path loads: 10+10 + 15+5 + 15 = 55,
|
||||
but we may need to refill here in the worst case */
|
||||
if (bits < op) {
|
||||
#ifdef INFLATE_CHUNK_READ_64LE
|
||||
REFILL();
|
||||
#else
|
||||
hold += (unsigned long)(*in++) << bits;
|
||||
bits += 8;
|
||||
if (bits < op) {
|
||||
hold += (unsigned long)(*in++) << bits;
|
||||
bits += 8;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
dist += (unsigned)hold & ((1U << op) - 1);
|
||||
#ifdef INFLATE_STRICT
|
||||
if (dist > dmax) {
|
||||
strm->msg = (z_const char *)"invalid distance too far back";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
hold >>= op;
|
||||
bits -= op;
|
||||
Tracevv((stderr, "inflate: distance %u\n", dist));
|
||||
op = (unsigned)(out - beg); /* max distance in output */
|
||||
if (dist > op) { /* see if copy from window */
|
||||
op = dist - op; /* distance back in window */
|
||||
if (op > whave) {
|
||||
if (state->sane) {
|
||||
strm->msg =
|
||||
(z_const char *)"invalid distance too far back";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
|
||||
if (len <= op - whave) {
|
||||
do {
|
||||
*out++ = 0;
|
||||
} while (--len);
|
||||
continue;
|
||||
}
|
||||
len -= op - whave;
|
||||
do {
|
||||
*out++ = 0;
|
||||
} while (--op > whave);
|
||||
if (op == 0) {
|
||||
from = out - dist;
|
||||
do {
|
||||
*out++ = *from++;
|
||||
} while (--len);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
from = window;
|
||||
if (wnext >= op) { /* contiguous in window */
|
||||
from += wnext - op;
|
||||
}
|
||||
else { /* wrap around window */
|
||||
op -= wnext;
|
||||
from += wsize - op;
|
||||
if (op < len) { /* some from end of window */
|
||||
len -= op;
|
||||
out = chunkcopy_safe(out, from, op, limit);
|
||||
from = window; /* more from start of window */
|
||||
op = wnext;
|
||||
/* This (rare) case can create a situation where
|
||||
the first chunkcopy below must be checked.
|
||||
*/
|
||||
}
|
||||
}
|
||||
if (op < len) { /* still need some from output */
|
||||
out = chunkcopy_safe(out, from, op, limit);
|
||||
len -= op;
|
||||
/* When dist is small the amount of data that can be
|
||||
copied from the window is also small, and progress
|
||||
towards the dangerous end of the output buffer is
|
||||
also small. This means that for trivial memsets and
|
||||
for chunkunroll_relaxed() a safety check is
|
||||
unnecessary. However, these conditions may not be
|
||||
entered at all, and in that case it's possible that
|
||||
the main copy is near the end.
|
||||
*/
|
||||
out = chunkunroll_relaxed(out, &dist, &len);
|
||||
out = chunkcopy_safe_ugly(out, dist, len, limit);
|
||||
} else {
|
||||
/* from points to window, so there is no risk of
|
||||
overlapping pointers requiring memset-like behaviour
|
||||
*/
|
||||
out = chunkcopy_safe(out, from, len, limit);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Whole reference is in range of current output. No
|
||||
range checks are necessary because we start with room
|
||||
for at least 258 bytes of output, so unroll and roundoff
|
||||
operations can write beyond `out+len` so long as they
|
||||
stay within 258 bytes of `out`.
|
||||
*/
|
||||
out = chunkcopy_lapped_relaxed(out, dist, len);
|
||||
}
|
||||
}
|
||||
else if ((op & 64) == 0) { /* 2nd level distance code */
|
||||
here = dcode + here->val + (hold & ((1U << op) - 1));
|
||||
goto dodist;
|
||||
}
|
||||
else {
|
||||
strm->msg = (z_const char *)"invalid distance code";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((op & 64) == 0) { /* 2nd level length code */
|
||||
here = lcode + here->val + (hold & ((1U << op) - 1));
|
||||
goto dolen;
|
||||
}
|
||||
else if (op & 32) { /* end-of-block */
|
||||
Tracevv((stderr, "inflate: end of block\n"));
|
||||
state->mode = TYPE;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
strm->msg = (z_const char *)"invalid literal/length code";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
} while (in < last && out < end);
|
||||
|
||||
/* return unused bytes (on entry, bits < 8, so in won't go too far back) */
|
||||
len = bits >> 3;
|
||||
in -= len;
|
||||
bits -= len << 3;
|
||||
hold &= (1U << bits) - 1;
|
||||
|
||||
/* update state and return */
|
||||
strm->next_in = in;
|
||||
strm->next_out = out;
|
||||
strm->avail_in = (unsigned)(in < last ?
|
||||
(INFLATE_FAST_MIN_INPUT - 1) + (last - in) :
|
||||
(INFLATE_FAST_MIN_INPUT - 1) - (in - last));
|
||||
strm->avail_out = (unsigned)(out < end ?
|
||||
(INFLATE_FAST_MIN_OUTPUT - 1) + (end - out) :
|
||||
(INFLATE_FAST_MIN_OUTPUT - 1) - (out - end));
|
||||
state->hold = hold;
|
||||
state->bits = bits;
|
||||
|
||||
Assert((state->hold >> state->bits) == 0, "invalid input data state");
|
||||
}
|
||||
|
||||
/*
|
||||
inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
|
||||
- Using bit fields for code structure
|
||||
- Different op definition to avoid & for extra bits (do & for table bits)
|
||||
- Three separate decoding do-loops for direct, window, and wnext == 0
|
||||
- Special case for distance > 1 copies to do overlapped load and store copy
|
||||
- Explicit branch predictions (based on measured branch probabilities)
|
||||
- Deferring match copy and interspersed it with decoding subsequent codes
|
||||
- Swapping literal/length else
|
||||
- Swapping window/direct else
|
||||
- Larger unrolled copy loops (three is about right)
|
||||
- Moving len -= 3 statement into middle of loop
|
||||
*/
|
||||
|
||||
#endif /* !ASMINF */
|
||||
@@ -0,0 +1,42 @@
|
||||
/* inffast_chunk.h -- header to use inffast_chunk.c
|
||||
* Copyright (C) 1995-2003, 2010 Mark Adler
|
||||
* Copyright (C) 2017 ARM, Inc.
|
||||
* Copyright 2023 The Chromium Authors
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* WARNING: this file should *not* be used by applications. It is
|
||||
part of the implementation of the compression library and is
|
||||
subject to change. Applications should only use zlib.h.
|
||||
*/
|
||||
|
||||
#include "inffast.h"
|
||||
|
||||
/* INFLATE_FAST_MIN_INPUT:
|
||||
The minimum number of input bytes needed so that we can safely call
|
||||
inflate_fast() with only one up-front bounds check. One
|
||||
length/distance code pair (15 bits for the length code, 5 bits for length
|
||||
extra, 15 bits for the distance code, 13 bits for distance extra) requires
|
||||
reading up to 48 input bits. Additionally, in the same iteraction, we may
|
||||
decode two literals from the root-table (requiring MIN_OUTPUT = 258 + 2).
|
||||
|
||||
Each root-table entry is up to 10 bits, for a total of 68 input bits each
|
||||
iteraction.
|
||||
|
||||
The refill variant reads 8 bytes from the buffer at a time, and advances
|
||||
the input pointer by up to 7 bytes, ensuring there are at least 56-bits
|
||||
available in the bit-buffer. The technique was documented by Fabian Giesen
|
||||
on his blog as variant 4 in the article 'Reading bits in far too many ways':
|
||||
https://fgiesen.wordpress.com/2018/02/20/
|
||||
|
||||
In the worst case, we may refill twice in the same iteraction, requiring
|
||||
MIN_INPUT = 8 + 7.
|
||||
*/
|
||||
#ifdef INFLATE_CHUNK_READ_64LE
|
||||
#undef INFLATE_FAST_MIN_INPUT
|
||||
#define INFLATE_FAST_MIN_INPUT 15
|
||||
#undef INFLATE_FAST_MIN_OUTPUT
|
||||
#define INFLATE_FAST_MIN_OUTPUT 260
|
||||
#endif
|
||||
|
||||
void ZLIB_INTERNAL inflate_fast_chunk_(z_streamp strm, unsigned start);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,80 @@
|
||||
/* insert_string.h
|
||||
*
|
||||
* Copyright 2019 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef INSERT_STRING_H
|
||||
#define INSERT_STRING_H
|
||||
|
||||
#ifndef INLINE
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define INLINE __inline
|
||||
#else
|
||||
#define INLINE inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Some applications need to match zlib DEFLATE output exactly [3]. Use the
|
||||
* canonical zlib Rabin-Karp rolling hash [1,2] in that case.
|
||||
*
|
||||
* [1] For a description of the Rabin and Karp algorithm, see "Algorithms"
|
||||
* book by R. Sedgewick, Addison-Wesley, p252.
|
||||
* [2] https://www.euccas.me/zlib/#zlib_rabin_karp and also "rolling hash"
|
||||
* https://en.wikipedia.org/wiki/Rolling_hash
|
||||
* [3] crbug.com/1316541 AOSP incremental client APK package OTA upgrades.
|
||||
*/
|
||||
#ifdef CHROMIUM_ZLIB_NO_CASTAGNOLI
|
||||
#define USE_ZLIB_RABIN_KARP_ROLLING_HASH
|
||||
#endif
|
||||
|
||||
/* ===========================================================================
|
||||
* Update a hash value with the given input byte (Rabin-Karp rolling hash).
|
||||
* IN assertion: all calls to UPDATE_HASH are made with consecutive input
|
||||
* characters, so that a running hash key can be computed from the previous
|
||||
* key instead of complete recalculation each time.
|
||||
*/
|
||||
#define UPDATE_HASH(s, h, c) (h = (((h) << s->hash_shift) ^ (c)) & s->hash_mask)
|
||||
|
||||
/* ===========================================================================
|
||||
* Insert string str in the dictionary and set match_head to the previous head
|
||||
* of the hash chain (the most recent string with same hash key). Return
|
||||
* the previous length of the hash chain.
|
||||
* If this file is compiled with -DFASTEST, the compression level is forced
|
||||
* to 1, and no hash chains are maintained.
|
||||
* IN assertion: all calls to INSERT_STRING are made with consecutive input
|
||||
* characters and the first MIN_MATCH bytes of str are valid (except for
|
||||
* the last MIN_MATCH-1 bytes of the input file).
|
||||
*/
|
||||
local INLINE Pos insert_string(deflate_state* const s, const Pos str) {
|
||||
Pos ret;
|
||||
/* insert_string dictionary insertion: ANZAC++ hasher
|
||||
* significantly improves data compression speed.
|
||||
*
|
||||
* Note: the generated compressed output is a valid DEFLATE stream, but will
|
||||
* differ from canonical zlib output.
|
||||
*/
|
||||
#if defined(USE_ZLIB_RABIN_KARP_ROLLING_HASH)
|
||||
UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH - 1)]);
|
||||
#else
|
||||
uint32_t value;
|
||||
// Validated for little endian archs (i.e. x86, Arm). YMMV for big endian.
|
||||
zmemcpy(&value, &s->window[str], sizeof(value));
|
||||
s->ins_h = ((value * 66521 + 66521) >> 16) & s->hash_mask;
|
||||
#endif
|
||||
|
||||
#ifdef FASTEST
|
||||
ret = s->head[s->ins_h];
|
||||
#else
|
||||
ret = s->prev[str & s->w_mask] = s->head[s->ins_h];
|
||||
#endif
|
||||
s->head[s->ins_h] = str;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* INSERT_STRING_H */
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
/* cpu_features.c -- Processor features detection.
|
||||
*
|
||||
* Copyright 2018 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*/
|
||||
|
||||
#include "cpu_features.h"
|
||||
#include "zutil.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#elif defined(ADLER32_SIMD_SSSE3)
|
||||
#include <cpuid.h>
|
||||
#endif
|
||||
|
||||
/* TODO(cavalcantii): remove checks for x86_flags on deflate.
|
||||
*/
|
||||
#if defined(ARMV8_OS_MACOS)
|
||||
/* Crypto extensions (crc32/pmull) are a baseline feature in ARMv8.1-A, and
|
||||
* OSX running on arm64 is new enough that these can be assumed without
|
||||
* runtime detection.
|
||||
*/
|
||||
int ZLIB_INTERNAL arm_cpu_enable_crc32 = 1;
|
||||
int ZLIB_INTERNAL arm_cpu_enable_pmull = 1;
|
||||
#else
|
||||
int ZLIB_INTERNAL arm_cpu_enable_crc32 = 0;
|
||||
int ZLIB_INTERNAL arm_cpu_enable_pmull = 0;
|
||||
#endif
|
||||
int ZLIB_INTERNAL x86_cpu_enable_sse2 = 0;
|
||||
int ZLIB_INTERNAL x86_cpu_enable_ssse3 = 0;
|
||||
int ZLIB_INTERNAL x86_cpu_enable_simd = 0;
|
||||
int ZLIB_INTERNAL x86_cpu_enable_avx512 = 0;
|
||||
|
||||
int ZLIB_INTERNAL riscv_cpu_enable_rvv = 0;
|
||||
int ZLIB_INTERNAL riscv_cpu_enable_vclmul = 0;
|
||||
|
||||
#ifndef CPU_NO_SIMD
|
||||
|
||||
#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || \
|
||||
defined(ARMV8_OS_FUCHSIA) || defined(ARMV8_OS_IOS)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#if defined(ARMV8_OS_ANDROID)
|
||||
#include <cpu-features.h>
|
||||
#elif defined(ARMV8_OS_LINUX)
|
||||
#include <asm/hwcap.h>
|
||||
#include <sys/auxv.h>
|
||||
#elif defined(ARMV8_OS_FUCHSIA)
|
||||
#include <zircon/features.h>
|
||||
#include <zircon/syscalls.h>
|
||||
#include <zircon/types.h>
|
||||
#elif defined(ARMV8_OS_WINDOWS) || defined(X86_WINDOWS)
|
||||
#include <windows.h>
|
||||
#elif defined(ARMV8_OS_IOS)
|
||||
#include <sys/sysctl.h>
|
||||
#elif !defined(_MSC_VER)
|
||||
#include <pthread.h>
|
||||
#else
|
||||
#error cpu_features.c CPU feature detection in not defined for your platform
|
||||
#endif
|
||||
|
||||
#if !defined(CPU_NO_SIMD) && !defined(ARMV8_OS_MACOS)
|
||||
static void _cpu_check_features(void);
|
||||
#endif
|
||||
|
||||
#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || \
|
||||
defined(ARMV8_OS_MACOS) || defined(ARMV8_OS_FUCHSIA) || \
|
||||
defined(X86_NOT_WINDOWS) || defined(ARMV8_OS_IOS) || \
|
||||
defined(RISCV_RVV)
|
||||
#if !defined(ARMV8_OS_MACOS)
|
||||
// _cpu_check_features() doesn't need to do anything on mac/arm since all
|
||||
// features are known at build time, so don't call it.
|
||||
// Do provide cpu_check_features() (with a no-op implementation) so that we
|
||||
// don't have to make all callers of it check for mac/arm.
|
||||
static pthread_once_t cpu_check_inited_once = PTHREAD_ONCE_INIT;
|
||||
#endif
|
||||
void ZLIB_INTERNAL cpu_check_features(void)
|
||||
{
|
||||
#if !defined(ARMV8_OS_MACOS)
|
||||
pthread_once(&cpu_check_inited_once, _cpu_check_features);
|
||||
#endif
|
||||
}
|
||||
#elif defined(ARMV8_OS_WINDOWS) || defined(X86_WINDOWS)
|
||||
static INIT_ONCE cpu_check_inited_once = INIT_ONCE_STATIC_INIT;
|
||||
static BOOL CALLBACK _cpu_check_features_forwarder(PINIT_ONCE once, PVOID param, PVOID* context)
|
||||
{
|
||||
_cpu_check_features();
|
||||
return TRUE;
|
||||
}
|
||||
void ZLIB_INTERNAL cpu_check_features(void)
|
||||
{
|
||||
InitOnceExecuteOnce(&cpu_check_inited_once, _cpu_check_features_forwarder,
|
||||
NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (defined(__ARM_NEON__) || defined(__ARM_NEON))
|
||||
#if !defined(ARMV8_OS_MACOS)
|
||||
/*
|
||||
* See http://bit.ly/2CcoEsr for run-time detection of ARM features and also
|
||||
* crbug.com/931275 for android_getCpuFeatures() use in the Android sandbox.
|
||||
*/
|
||||
static void _cpu_check_features(void)
|
||||
{
|
||||
#if defined(ARMV8_OS_ANDROID) && defined(__aarch64__)
|
||||
uint64_t features = android_getCpuFeatures();
|
||||
arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM64_FEATURE_CRC32);
|
||||
arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM64_FEATURE_PMULL);
|
||||
#elif defined(ARMV8_OS_ANDROID) /* aarch32 */
|
||||
uint64_t features = android_getCpuFeatures();
|
||||
arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM_FEATURE_CRC32);
|
||||
arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM_FEATURE_PMULL);
|
||||
#elif defined(ARMV8_OS_LINUX) && defined(__aarch64__)
|
||||
unsigned long features = getauxval(AT_HWCAP);
|
||||
arm_cpu_enable_crc32 = !!(features & HWCAP_CRC32);
|
||||
arm_cpu_enable_pmull = !!(features & HWCAP_PMULL);
|
||||
#elif defined(ARMV8_OS_LINUX) && (defined(__ARM_NEON) || defined(__ARM_NEON__))
|
||||
/* Query HWCAP2 for ARMV8-A SoCs running in aarch32 mode */
|
||||
unsigned long features = getauxval(AT_HWCAP2);
|
||||
arm_cpu_enable_crc32 = !!(features & HWCAP2_CRC32);
|
||||
arm_cpu_enable_pmull = !!(features & HWCAP2_PMULL);
|
||||
#elif defined(ARMV8_OS_FUCHSIA)
|
||||
uint32_t features;
|
||||
zx_status_t rc = zx_system_get_features(ZX_FEATURE_KIND_CPU, &features);
|
||||
if (rc != ZX_OK || (features & ZX_ARM64_FEATURE_ISA_ASIMD) == 0)
|
||||
return; /* Report nothing if ASIMD(NEON) is missing */
|
||||
arm_cpu_enable_crc32 = !!(features & ZX_ARM64_FEATURE_ISA_CRC32);
|
||||
arm_cpu_enable_pmull = !!(features & ZX_ARM64_FEATURE_ISA_PMULL);
|
||||
#elif defined(ARMV8_OS_WINDOWS)
|
||||
arm_cpu_enable_crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
|
||||
arm_cpu_enable_pmull = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
|
||||
#elif defined(ARMV8_OS_IOS)
|
||||
// Determine what features are supported dynamically. This code is applicable to macOS
|
||||
// as well if we wish to do that dynamically on that platform in the future.
|
||||
// See https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics
|
||||
int val = 0;
|
||||
size_t len = sizeof(val);
|
||||
arm_cpu_enable_crc32 = sysctlbyname("hw.optional.armv8_crc32", &val, &len, 0, 0) == 0
|
||||
&& val != 0;
|
||||
val = 0;
|
||||
len = sizeof(val);
|
||||
arm_cpu_enable_pmull = sysctlbyname("hw.optional.arm.FEAT_PMULL", &val, &len, 0, 0) == 0
|
||||
&& val != 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#elif defined(X86_NOT_WINDOWS) || defined(X86_WINDOWS)
|
||||
/*
|
||||
* iOS@x86 (i.e. emulator) is another special case where we disable
|
||||
* SIMD optimizations.
|
||||
*/
|
||||
#ifndef CPU_NO_SIMD
|
||||
/* On x86 we simply use a instruction to check the CPU features.
|
||||
* (i.e. CPUID).
|
||||
*/
|
||||
#ifdef CRC32_SIMD_AVX512_PCLMUL
|
||||
#include <immintrin.h>
|
||||
#include <xsaveintrin.h>
|
||||
#endif
|
||||
/* _xgetbv() below needs the xsave ISA. Annotate it here so the build does not
|
||||
* need -mxsave. */
|
||||
#if defined(CRC32_SIMD_AVX512_PCLMUL) && (defined(__GNUC__) || defined(__clang__))
|
||||
__attribute__((__target__("xsave")))
|
||||
#endif
|
||||
static void _cpu_check_features(void)
|
||||
{
|
||||
int x86_cpu_has_sse2;
|
||||
int x86_cpu_has_ssse3;
|
||||
int x86_cpu_has_sse42;
|
||||
int x86_cpu_has_pclmulqdq;
|
||||
int abcd[4];
|
||||
|
||||
#ifdef _MSC_VER
|
||||
__cpuid(abcd, 1);
|
||||
#else
|
||||
__cpuid(1, abcd[0], abcd[1], abcd[2], abcd[3]);
|
||||
#endif
|
||||
|
||||
x86_cpu_has_sse2 = abcd[3] & 0x4000000;
|
||||
x86_cpu_has_ssse3 = abcd[2] & 0x000200;
|
||||
x86_cpu_has_sse42 = abcd[2] & 0x100000;
|
||||
x86_cpu_has_pclmulqdq = abcd[2] & 0x2;
|
||||
|
||||
x86_cpu_enable_sse2 = x86_cpu_has_sse2;
|
||||
|
||||
x86_cpu_enable_ssse3 = x86_cpu_has_ssse3;
|
||||
|
||||
x86_cpu_enable_simd = x86_cpu_has_sse2 &&
|
||||
x86_cpu_has_sse42 &&
|
||||
x86_cpu_has_pclmulqdq;
|
||||
|
||||
#ifdef CRC32_SIMD_AVX512_PCLMUL
|
||||
x86_cpu_enable_avx512 = _xgetbv(0) & 0x00000040;
|
||||
#endif
|
||||
}
|
||||
#endif // x86 & NO_SIMD
|
||||
|
||||
#elif defined(RISCV_RVV)
|
||||
#include <sys/auxv.h>
|
||||
|
||||
#ifndef ZLIB_HWCAP_RVV
|
||||
#define ZLIB_HWCAP_RVV (1 << ('v' - 'a'))
|
||||
#endif
|
||||
|
||||
/* TODO(cavalcantii)
|
||||
* - add support for Android@RISCV i.e. __riscv_hwprobe().
|
||||
* - detect vclmul (crypto extensions).
|
||||
*/
|
||||
static void _cpu_check_features(void)
|
||||
{
|
||||
unsigned long features = getauxval(AT_HWCAP);
|
||||
riscv_cpu_enable_rvv = !!(features & ZLIB_HWCAP_RVV);
|
||||
}
|
||||
#endif // ARM | x86 | RISCV
|
||||
#endif // NO SIMD CPU
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/* cpu_features.h -- Processor features detection.
|
||||
*
|
||||
* Copyright 2018 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*/
|
||||
|
||||
#include "zlib.h"
|
||||
|
||||
/* TODO(cavalcantii): remove checks for x86_flags on deflate.
|
||||
*/
|
||||
extern int arm_cpu_enable_crc32;
|
||||
extern int arm_cpu_enable_pmull;
|
||||
extern int x86_cpu_enable_sse2;
|
||||
extern int x86_cpu_enable_ssse3;
|
||||
extern int x86_cpu_enable_simd;
|
||||
extern int x86_cpu_enable_avx512;
|
||||
|
||||
extern int riscv_cpu_enable_rvv;
|
||||
extern int riscv_cpu_enable_vclmul;
|
||||
|
||||
void cpu_check_features(void);
|
||||
Vendored
+201
-124
@@ -1,5 +1,5 @@
|
||||
/* crc32.c -- compute the CRC-32 of a data stream
|
||||
* Copyright (C) 1995-2022 Mark Adler
|
||||
* Copyright (C) 1995-2026 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*
|
||||
* This interleaved implementation of a CRC makes use of pipelined multiple
|
||||
@@ -24,11 +24,24 @@
|
||||
# include <stdio.h>
|
||||
# ifndef DYNAMIC_CRC_TABLE
|
||||
# define DYNAMIC_CRC_TABLE
|
||||
# endif /* !DYNAMIC_CRC_TABLE */
|
||||
#endif /* MAKECRCH */
|
||||
# endif
|
||||
#endif
|
||||
#ifdef DYNAMIC_CRC_TABLE
|
||||
# define Z_ONCE
|
||||
#endif
|
||||
|
||||
#include "deflate.h"
|
||||
#include "cpu_features.h"
|
||||
#include "zutil.h" /* for Z_U4, Z_U8, z_crc_t, and FAR definitions */
|
||||
|
||||
#ifdef HAVE_S390X_VX
|
||||
# include "contrib/crc32vx/crc32_vx_hooks.h"
|
||||
#endif
|
||||
|
||||
#if defined(CRC32_SIMD_SSE42_PCLMUL) || defined(CRC32_ARMV8_CRC32)
|
||||
#include "crc32_simd.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
A CRC of a message is computed on N braids of words in the message, where
|
||||
each word consists of W bytes (4 or 8). If N is 3, for example, then three
|
||||
@@ -99,11 +112,12 @@
|
||||
#endif
|
||||
|
||||
/* If available, use the ARM processor CRC32 instruction. */
|
||||
#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8
|
||||
# define ARMCRC32
|
||||
#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && \
|
||||
defined(W) && W == 8 && defined(USE_CANONICAL_ARMV8_CRC32)
|
||||
# define ARMCRC32_CANONICAL_ZLIB
|
||||
#endif
|
||||
|
||||
#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE))
|
||||
#if defined(W) && (!defined(ARMCRC32_CANONICAL_ZLIB) || defined(DYNAMIC_CRC_TABLE))
|
||||
/*
|
||||
Swap the bytes in a z_word_t to convert between little and big endian. Any
|
||||
self-respecting compiler will optimize this to a single machine byte-swap
|
||||
@@ -152,10 +166,10 @@ local z_word_t byte_swap(z_word_t word) {
|
||||
Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial,
|
||||
reflected. For speed, this requires that a not be zero.
|
||||
*/
|
||||
local z_crc_t multmodp(z_crc_t a, z_crc_t b) {
|
||||
z_crc_t m, p;
|
||||
local uLong multmodp(uLong a, uLong b) {
|
||||
uLong m, p;
|
||||
|
||||
m = (z_crc_t)1 << 31;
|
||||
m = (uLong)1 << 31;
|
||||
p = 0;
|
||||
for (;;) {
|
||||
if (a & m) {
|
||||
@@ -171,12 +185,12 @@ local z_crc_t multmodp(z_crc_t a, z_crc_t b) {
|
||||
|
||||
/*
|
||||
Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been
|
||||
initialized.
|
||||
initialized. n must not be negative.
|
||||
*/
|
||||
local z_crc_t x2nmodp(z_off64_t n, unsigned k) {
|
||||
z_crc_t p;
|
||||
local uLong x2nmodp(z_off64_t n, unsigned k) {
|
||||
uLong p;
|
||||
|
||||
p = (z_crc_t)1 << 31; /* x^0 == 1 */
|
||||
p = (uLong)1 << 31; /* x^0 == 1 */
|
||||
while (n) {
|
||||
if (n & 1)
|
||||
p = multmodp(x2n_table[k & 31], p);
|
||||
@@ -204,83 +218,8 @@ local z_crc_t FAR crc_table[256];
|
||||
local void write_table64(FILE *, const z_word_t FAR *, int);
|
||||
#endif /* MAKECRCH */
|
||||
|
||||
/*
|
||||
Define a once() function depending on the availability of atomics. If this is
|
||||
compiled with DYNAMIC_CRC_TABLE defined, and if CRCs will be computed in
|
||||
multiple threads, and if atomics are not available, then get_crc_table() must
|
||||
be called to initialize the tables and must return before any threads are
|
||||
allowed to compute or combine CRCs.
|
||||
*/
|
||||
|
||||
/* Definition of once functionality. */
|
||||
typedef struct once_s once_t;
|
||||
|
||||
/* Check for the availability of atomics. */
|
||||
#if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \
|
||||
!defined(__STDC_NO_ATOMICS__)
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
/* Structure for once(), which must be initialized with ONCE_INIT. */
|
||||
struct once_s {
|
||||
atomic_flag begun;
|
||||
atomic_int done;
|
||||
};
|
||||
#define ONCE_INIT {ATOMIC_FLAG_INIT, 0}
|
||||
|
||||
/*
|
||||
Run the provided init() function exactly once, even if multiple threads
|
||||
invoke once() at the same time. The state must be a once_t initialized with
|
||||
ONCE_INIT.
|
||||
*/
|
||||
local void once(once_t *state, void (*init)(void)) {
|
||||
if (!atomic_load(&state->done)) {
|
||||
if (atomic_flag_test_and_set(&state->begun))
|
||||
while (!atomic_load(&state->done))
|
||||
;
|
||||
else {
|
||||
init();
|
||||
atomic_store(&state->done, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else /* no atomics */
|
||||
|
||||
/* Structure for once(), which must be initialized with ONCE_INIT. */
|
||||
struct once_s {
|
||||
volatile int begun;
|
||||
volatile int done;
|
||||
};
|
||||
#define ONCE_INIT {0, 0}
|
||||
|
||||
/* Test and set. Alas, not atomic, but tries to minimize the period of
|
||||
vulnerability. */
|
||||
local int test_and_set(int volatile *flag) {
|
||||
int was;
|
||||
|
||||
was = *flag;
|
||||
*flag = 1;
|
||||
return was;
|
||||
}
|
||||
|
||||
/* Run the provided init() function once. This is not thread-safe. */
|
||||
local void once(once_t *state, void (*init)(void)) {
|
||||
if (!state->done) {
|
||||
if (test_and_set(&state->begun))
|
||||
while (!state->done)
|
||||
;
|
||||
else {
|
||||
init();
|
||||
state->done = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* State for once(). */
|
||||
local once_t made = ONCE_INIT;
|
||||
local z_once_t made = Z_ONCE_INIT;
|
||||
|
||||
/*
|
||||
Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
|
||||
@@ -306,8 +245,8 @@ local once_t made = ONCE_INIT;
|
||||
information needed to generate CRCs on data a byte at a time for all
|
||||
combinations of CRC register values and incoming bytes.
|
||||
*/
|
||||
|
||||
local void make_crc_table(void) {
|
||||
local void make_crc_table(void)
|
||||
{
|
||||
unsigned i, j, n;
|
||||
z_crc_t p;
|
||||
|
||||
@@ -326,7 +265,7 @@ local void make_crc_table(void) {
|
||||
p = (z_crc_t)1 << 30; /* x^1 */
|
||||
x2n_table[0] = p;
|
||||
for (n = 1; n < 32; n++)
|
||||
x2n_table[n] = p = multmodp(p, p);
|
||||
x2n_table[n] = p = (z_crc_t)multmodp(p, p);
|
||||
|
||||
#ifdef W
|
||||
/* initialize the braiding tables -- needs x2n_table[] */
|
||||
@@ -529,11 +468,11 @@ local void braid(z_crc_t ltl[][256], z_word_t big[][256], int n, int w) {
|
||||
int k;
|
||||
z_crc_t i, p, q;
|
||||
for (k = 0; k < w; k++) {
|
||||
p = x2nmodp((n * w + 3 - k) << 3, 0);
|
||||
p = (z_crc_t)x2nmodp((n * w + 3 - k) << 3, 0);
|
||||
ltl[k][0] = 0;
|
||||
big[w - 1 - k][0] = 0;
|
||||
for (i = 1; i < 256; i++) {
|
||||
ltl[k][i] = q = multmodp(i << 24, p);
|
||||
ltl[k][i] = q = (z_crc_t)multmodp(i << 24, p);
|
||||
big[w - 1 - k][i] = byte_swap(q);
|
||||
}
|
||||
}
|
||||
@@ -548,7 +487,7 @@ local void braid(z_crc_t ltl[][256], z_word_t big[][256], int n, int w) {
|
||||
*/
|
||||
const z_crc_t FAR * ZEXPORT get_crc_table(void) {
|
||||
#ifdef DYNAMIC_CRC_TABLE
|
||||
once(&made, make_crc_table);
|
||||
z_once(&made, make_crc_table);
|
||||
#endif /* DYNAMIC_CRC_TABLE */
|
||||
return (const z_crc_t FAR *)crc_table;
|
||||
}
|
||||
@@ -562,7 +501,7 @@ const z_crc_t FAR * ZEXPORT get_crc_table(void) {
|
||||
* -march=armv8-a+crc, or -march=native if the compile machine has the crc32
|
||||
* instructions.
|
||||
*/
|
||||
#ifdef ARMCRC32
|
||||
#if ARMCRC32_CANONICAL_ZLIB
|
||||
|
||||
/*
|
||||
Constants empirically determined to maximize speed. These values are from
|
||||
@@ -572,9 +511,8 @@ const z_crc_t FAR * ZEXPORT get_crc_table(void) {
|
||||
#define Z_BATCH_ZEROS 0xa10d3d0c /* computed from Z_BATCH = 3990 */
|
||||
#define Z_BATCH_MIN 800 /* fewest words in a final batch */
|
||||
|
||||
unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf,
|
||||
z_size_t len) {
|
||||
z_crc_t val;
|
||||
uLong ZEXPORT crc32_z(uLong crc, const unsigned char FAR *buf, z_size_t len) {
|
||||
uLong val;
|
||||
z_word_t crc1, crc2;
|
||||
const z_word_t *word;
|
||||
z_word_t val0, val1, val2;
|
||||
@@ -585,7 +523,7 @@ unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf,
|
||||
if (buf == Z_NULL) return 0;
|
||||
|
||||
#ifdef DYNAMIC_CRC_TABLE
|
||||
once(&made, make_crc_table);
|
||||
z_once(&made, make_crc_table);
|
||||
#endif /* DYNAMIC_CRC_TABLE */
|
||||
|
||||
/* Pre-condition the CRC */
|
||||
@@ -640,7 +578,7 @@ unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf,
|
||||
}
|
||||
word += 3 * last;
|
||||
num -= 3 * last;
|
||||
val = x2nmodp(last, 6);
|
||||
val = x2nmodp((int)last, 6);
|
||||
crc = multmodp(val, crc) ^ crc1;
|
||||
crc = multmodp(val, crc) ^ crc2;
|
||||
}
|
||||
@@ -691,15 +629,79 @@ local z_word_t crc_word_big(z_word_t data) {
|
||||
#endif
|
||||
|
||||
/* ========================================================================= */
|
||||
unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf,
|
||||
z_size_t len) {
|
||||
/* Return initial CRC, if requested. */
|
||||
if (buf == Z_NULL) return 0;
|
||||
uLong ZEXPORT crc32_z(uLong crc, const unsigned char FAR *buf, z_size_t len) {
|
||||
|
||||
/* If no optimizations are enabled, do it as canonical zlib. */
|
||||
#if !defined(CRC32_SIMD_SSE42_PCLMUL) && !defined(CRC32_ARMV8_CRC32) && \
|
||||
!defined(RISCV_RVV) && !defined(CRC32_SIMD_AVX512_PCLMUL)
|
||||
if (buf == Z_NULL) {
|
||||
return 0UL;
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* zlib convention is to call crc32(0, NULL, 0); before making
|
||||
* calls to crc32(). So this is a good, early (and infrequent)
|
||||
* place to cache CPU features if needed for those later, more
|
||||
* interesting crc32() calls.
|
||||
*/
|
||||
if (buf == Z_NULL) {
|
||||
if (!len)
|
||||
cpu_check_features();
|
||||
return 0UL;
|
||||
}
|
||||
#endif
|
||||
/* If AVX-512 is enabled, we will use it for longer inputs and fallback
|
||||
* to SSE4.2 and eventually the portable implementation to handle the tail.
|
||||
*/
|
||||
#if defined(CRC32_SIMD_AVX512_PCLMUL)
|
||||
if (x86_cpu_enable_avx512 && len >= Z_CRC32_AVX512_MINIMUM_LENGTH) {
|
||||
/* crc32 64-byte chunks */
|
||||
z_size_t chunk_size = len & ~Z_CRC32_AVX512_CHUNKSIZE_MASK;
|
||||
crc = ~crc32_avx512_simd_(buf, chunk_size, ~(uint32_t)crc);
|
||||
/* check remaining data */
|
||||
len -= chunk_size;
|
||||
if (!len)
|
||||
return crc;
|
||||
/* Fall into the default crc32 for the remaining data. */
|
||||
buf += chunk_size;
|
||||
}
|
||||
#endif
|
||||
#if defined(CRC32_SIMD_SSE42_PCLMUL)
|
||||
if (x86_cpu_enable_simd && len >= Z_CRC32_SSE42_MINIMUM_LENGTH) {
|
||||
/* crc32 16-byte chunks */
|
||||
z_size_t chunk_size = len & ~Z_CRC32_SSE42_CHUNKSIZE_MASK;
|
||||
crc = ~crc32_sse42_simd_(buf, chunk_size, ~(uint32_t)crc);
|
||||
/* check remaining data */
|
||||
len -= chunk_size;
|
||||
if (!len)
|
||||
return crc;
|
||||
/* Fall into the default crc32 for the remaining data. */
|
||||
buf += chunk_size;
|
||||
}
|
||||
#elif defined(CRC32_ARMV8_CRC32)
|
||||
if (arm_cpu_enable_crc32) {
|
||||
#if defined(__aarch64__)
|
||||
/* PMULL is 64bit only, plus code needs at least a 64 bytes buffer. */
|
||||
if (arm_cpu_enable_pmull && (len > Z_CRC32_PMULL_MINIMUM_LENGTH)) {
|
||||
const size_t chunk_size = len & ~Z_CRC32_PMULL_CHUNKSIZE_MASK;
|
||||
crc = ~armv8_crc32_pmull_little(buf, chunk_size, ~(uint32_t)crc);
|
||||
/* Check remaining data. */
|
||||
len -= chunk_size;
|
||||
if (!len)
|
||||
return crc;
|
||||
|
||||
/* Fall through for the remaining data. */
|
||||
buf += chunk_size;
|
||||
}
|
||||
#endif
|
||||
/* This is scalar and self contained, used on Armv8@32bit or tail. */
|
||||
return armv8_crc32_little(buf, len, crc);
|
||||
}
|
||||
#endif /* CRC32_SIMD */
|
||||
|
||||
#ifdef DYNAMIC_CRC_TABLE
|
||||
once(&made, make_crc_table);
|
||||
z_once(&made, make_crc_table);
|
||||
#endif /* DYNAMIC_CRC_TABLE */
|
||||
|
||||
/* Pre-condition the CRC */
|
||||
crc = (~crc) & 0xffffffff;
|
||||
|
||||
@@ -1012,28 +1014,56 @@ unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf,
|
||||
#endif
|
||||
|
||||
/* ========================================================================= */
|
||||
unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf,
|
||||
uInt len) {
|
||||
return crc32_z(crc, buf, len);
|
||||
}
|
||||
uLong ZEXPORT crc32(uLong crc, const unsigned char FAR *buf, uInt len) {
|
||||
#ifdef HAVE_S390X_VX
|
||||
return crc32_z_hook(crc, buf, len);
|
||||
#endif
|
||||
|
||||
/* ========================================================================= */
|
||||
uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) {
|
||||
#ifdef DYNAMIC_CRC_TABLE
|
||||
once(&made, make_crc_table);
|
||||
#endif /* DYNAMIC_CRC_TABLE */
|
||||
return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff);
|
||||
}
|
||||
/* Some bots compile with optimizations disabled, others will emulate
|
||||
* ARM on x86 and other weird combinations.
|
||||
*/
|
||||
#if defined(CRC32_SIMD_SSE42_PCLMUL) || defined(CRC32_ARMV8_CRC32) \
|
||||
|| defined(RISCV_RVV)
|
||||
/* We got to verify CPU features, so exploit the common usage pattern
|
||||
* of calling this function with Z_NULL for an initial valid crc value.
|
||||
* This allows to cache the result of the feature check and avoid extraneous
|
||||
* function calls.
|
||||
*/
|
||||
if (buf == Z_NULL) {
|
||||
if (!len) /* Assume user is calling crc32(0, NULL, 0); */
|
||||
cpu_check_features();
|
||||
return 0UL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ========================================================================= */
|
||||
uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2) {
|
||||
return crc32_combine64(crc1, crc2, (z_off64_t)len2);
|
||||
#if defined(CRC32_ARMV8_CRC32)
|
||||
if (arm_cpu_enable_crc32) {
|
||||
#if defined(__aarch64__)
|
||||
/* PMULL is 64bit only, plus code needs at least a 64 bytes buffer. */
|
||||
if (arm_cpu_enable_pmull && (len > Z_CRC32_PMULL_MINIMUM_LENGTH)) {
|
||||
const size_t chunk_size = len & ~Z_CRC32_PMULL_CHUNKSIZE_MASK;
|
||||
crc = ~armv8_crc32_pmull_little(buf, chunk_size, ~(uint32_t)crc);
|
||||
/* Check remaining data. */
|
||||
len -= chunk_size;
|
||||
if (!len)
|
||||
return crc;
|
||||
|
||||
/* Fall through for the remaining data. */
|
||||
buf += chunk_size;
|
||||
}
|
||||
#endif
|
||||
return armv8_crc32_little(buf, len, crc); /* Armv8@32bit or tail. */
|
||||
}
|
||||
#endif
|
||||
return crc32_z(crc, buf, len); /* Armv7 or Armv8 w/o crypto extensions. */
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
uLong ZEXPORT crc32_combine_gen64(z_off64_t len2) {
|
||||
if (len2 < 0)
|
||||
return 0;
|
||||
#ifdef DYNAMIC_CRC_TABLE
|
||||
once(&made, make_crc_table);
|
||||
z_once(&made, make_crc_table);
|
||||
#endif /* DYNAMIC_CRC_TABLE */
|
||||
return x2nmodp(len2, 3);
|
||||
}
|
||||
@@ -1042,8 +1072,55 @@ uLong ZEXPORT crc32_combine_gen64(z_off64_t len2) {
|
||||
uLong ZEXPORT crc32_combine_gen(z_off_t len2) {
|
||||
return crc32_combine_gen64((z_off64_t)len2);
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op) {
|
||||
return multmodp(op, crc1) ^ (crc2 & 0xffffffff);
|
||||
if (op == 0)
|
||||
return 0;
|
||||
return multmodp(op, crc1 & 0xffffffff) ^ (crc2 & 0xffffffff);
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) {
|
||||
return crc32_combine_op(crc1, crc2, crc32_combine_gen64(len2));
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2) {
|
||||
return crc32_combine64(crc1, crc2, (z_off64_t)len2);
|
||||
}
|
||||
|
||||
ZLIB_INTERNAL void crc_reset(deflate_state *const s)
|
||||
{
|
||||
#ifdef CRC32_SIMD_SSE42_PCLMUL
|
||||
if (x86_cpu_enable_simd) {
|
||||
crc_fold_init(s);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
s->strm->adler = crc32(0L, Z_NULL, 0);
|
||||
}
|
||||
|
||||
ZLIB_INTERNAL void crc_finalize(deflate_state *const s)
|
||||
{
|
||||
#ifdef QAT_COMPRESSION_ENABLED
|
||||
if (s->qat_s) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef CRC32_SIMD_SSE42_PCLMUL
|
||||
if (x86_cpu_enable_simd)
|
||||
s->strm->adler = crc_fold_512to32(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
ZLIB_INTERNAL void copy_with_crc(z_streamp strm, Bytef *dst, long size)
|
||||
{
|
||||
#ifdef CRC32_SIMD_SSE42_PCLMUL
|
||||
if (x86_cpu_enable_simd) {
|
||||
crc_fold_copy(strm->state, dst, strm->next_in, size);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
zmemcpy(dst, strm->next_in, size);
|
||||
strm->adler = crc32(strm->adler, dst, size);
|
||||
}
|
||||
|
||||
+628
@@ -0,0 +1,628 @@
|
||||
/* crc32_simd.c
|
||||
*
|
||||
* Copyright 2017 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*/
|
||||
|
||||
#include "crc32_simd.h"
|
||||
#if defined(CRC32_SIMD_AVX512_PCLMUL)
|
||||
|
||||
/*
|
||||
* crc32_avx512_simd_(): compute the crc32 of the buffer, where the buffer
|
||||
* length must be at least 256, and a multiple of 64. Based on:
|
||||
*
|
||||
* "Fast CRC Computation for Generic Polynomials Using PCLMULQDQ Instruction"
|
||||
* V. Gopal, E. Ozturk, et al., 2009, http://intel.ly/2ySEwL0
|
||||
*/
|
||||
|
||||
#include <emmintrin.h>
|
||||
#include <smmintrin.h>
|
||||
#include <wmmintrin.h>
|
||||
#include <immintrin.h>
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
__attribute__((__target__("avx512f,pclmul,vpclmulqdq")))
|
||||
#endif
|
||||
uint32_t ZLIB_INTERNAL crc32_avx512_simd_( /* AVX512+PCLMUL */
|
||||
const unsigned char *buf,
|
||||
z_size_t len,
|
||||
uint32_t crc)
|
||||
{
|
||||
/*
|
||||
* Definitions of the bit-reflected domain constants k1,k2,k3,k4
|
||||
* are similar to those given at the end of the paper, and remaining
|
||||
* constants and CRC32+Barrett polynomials remain unchanged.
|
||||
*
|
||||
* Replace the index of x from 128 to 512. As follows:
|
||||
* k1 = ( x ^ ( 512 * 4 + 32 ) mod P(x) << 32 )' << 1 = 0x011542778a
|
||||
* k2 = ( x ^ ( 512 * 4 - 32 ) mod P(x) << 32 )' << 1 = 0x01322d1430
|
||||
* k3 = ( x ^ ( 512 + 32 ) mod P(x) << 32 )' << 1 = 0x0154442bd4
|
||||
* k4 = ( x ^ ( 512 - 32 ) mod P(x) << 32 )' << 1 = 0x01c6e41596
|
||||
*/
|
||||
static const uint64_t zalign(64) k1k2[] = { 0x011542778a, 0x01322d1430,
|
||||
0x011542778a, 0x01322d1430,
|
||||
0x011542778a, 0x01322d1430,
|
||||
0x011542778a, 0x01322d1430 };
|
||||
static const uint64_t zalign(64) k3k4[] = { 0x0154442bd4, 0x01c6e41596,
|
||||
0x0154442bd4, 0x01c6e41596,
|
||||
0x0154442bd4, 0x01c6e41596,
|
||||
0x0154442bd4, 0x01c6e41596 };
|
||||
static const uint64_t zalign(16) k5k6[] = { 0x01751997d0, 0x00ccaa009e };
|
||||
static const uint64_t zalign(16) k7k8[] = { 0x0163cd6124, 0x0000000000 };
|
||||
static const uint64_t zalign(16) poly[] = { 0x01db710641, 0x01f7011641 };
|
||||
__m512i x0, x1, x2, x3, x4, x5, x6, x7, x8, y5, y6, y7, y8;
|
||||
__m128i a0, a1, a2, a3;
|
||||
|
||||
/*
|
||||
* There's at least one block of 256.
|
||||
*/
|
||||
x1 = _mm512_loadu_si512((__m512i *)(buf + 0x00));
|
||||
x2 = _mm512_loadu_si512((__m512i *)(buf + 0x40));
|
||||
x3 = _mm512_loadu_si512((__m512i *)(buf + 0x80));
|
||||
x4 = _mm512_loadu_si512((__m512i *)(buf + 0xC0));
|
||||
|
||||
x1 = _mm512_xor_si512(x1, _mm512_castsi128_si512(_mm_cvtsi32_si128(crc)));
|
||||
|
||||
x0 = _mm512_load_si512((__m512i *)k1k2);
|
||||
|
||||
buf += 256;
|
||||
len -= 256;
|
||||
|
||||
/*
|
||||
* Parallel fold blocks of 256, if any.
|
||||
*/
|
||||
while (len >= 256)
|
||||
{
|
||||
x5 = _mm512_clmulepi64_epi128(x1, x0, 0x00);
|
||||
x6 = _mm512_clmulepi64_epi128(x2, x0, 0x00);
|
||||
x7 = _mm512_clmulepi64_epi128(x3, x0, 0x00);
|
||||
x8 = _mm512_clmulepi64_epi128(x4, x0, 0x00);
|
||||
|
||||
|
||||
x1 = _mm512_clmulepi64_epi128(x1, x0, 0x11);
|
||||
x2 = _mm512_clmulepi64_epi128(x2, x0, 0x11);
|
||||
x3 = _mm512_clmulepi64_epi128(x3, x0, 0x11);
|
||||
x4 = _mm512_clmulepi64_epi128(x4, x0, 0x11);
|
||||
|
||||
y5 = _mm512_loadu_si512((__m512i *)(buf + 0x00));
|
||||
y6 = _mm512_loadu_si512((__m512i *)(buf + 0x40));
|
||||
y7 = _mm512_loadu_si512((__m512i *)(buf + 0x80));
|
||||
y8 = _mm512_loadu_si512((__m512i *)(buf + 0xC0));
|
||||
|
||||
x1 = _mm512_xor_si512(x1, x5);
|
||||
x2 = _mm512_xor_si512(x2, x6);
|
||||
x3 = _mm512_xor_si512(x3, x7);
|
||||
x4 = _mm512_xor_si512(x4, x8);
|
||||
|
||||
x1 = _mm512_xor_si512(x1, y5);
|
||||
x2 = _mm512_xor_si512(x2, y6);
|
||||
x3 = _mm512_xor_si512(x3, y7);
|
||||
x4 = _mm512_xor_si512(x4, y8);
|
||||
|
||||
buf += 256;
|
||||
len -= 256;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fold into 512-bits.
|
||||
*/
|
||||
x0 = _mm512_load_si512((__m512i *)k3k4);
|
||||
|
||||
x5 = _mm512_clmulepi64_epi128(x1, x0, 0x00);
|
||||
x1 = _mm512_clmulepi64_epi128(x1, x0, 0x11);
|
||||
x1 = _mm512_xor_si512(x1, x2);
|
||||
x1 = _mm512_xor_si512(x1, x5);
|
||||
|
||||
x5 = _mm512_clmulepi64_epi128(x1, x0, 0x00);
|
||||
x1 = _mm512_clmulepi64_epi128(x1, x0, 0x11);
|
||||
x1 = _mm512_xor_si512(x1, x3);
|
||||
x1 = _mm512_xor_si512(x1, x5);
|
||||
|
||||
x5 = _mm512_clmulepi64_epi128(x1, x0, 0x00);
|
||||
x1 = _mm512_clmulepi64_epi128(x1, x0, 0x11);
|
||||
x1 = _mm512_xor_si512(x1, x4);
|
||||
x1 = _mm512_xor_si512(x1, x5);
|
||||
|
||||
/*
|
||||
* Single fold blocks of 64, if any.
|
||||
*/
|
||||
while (len >= 64)
|
||||
{
|
||||
x2 = _mm512_loadu_si512((__m512i *)buf);
|
||||
|
||||
x5 = _mm512_clmulepi64_epi128(x1, x0, 0x00);
|
||||
x1 = _mm512_clmulepi64_epi128(x1, x0, 0x11);
|
||||
x1 = _mm512_xor_si512(x1, x2);
|
||||
x1 = _mm512_xor_si512(x1, x5);
|
||||
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fold 512-bits to 384-bits.
|
||||
*/
|
||||
a0 = _mm_load_si128((__m128i *)k5k6);
|
||||
|
||||
a1 = _mm512_extracti32x4_epi32(x1, 0);
|
||||
a2 = _mm512_extracti32x4_epi32(x1, 1);
|
||||
|
||||
a3 = _mm_clmulepi64_si128(a1, a0, 0x00);
|
||||
a1 = _mm_clmulepi64_si128(a1, a0, 0x11);
|
||||
|
||||
a1 = _mm_xor_si128(a1, a3);
|
||||
a1 = _mm_xor_si128(a1, a2);
|
||||
|
||||
/*
|
||||
* Fold 384-bits to 256-bits.
|
||||
*/
|
||||
a2 = _mm512_extracti32x4_epi32(x1, 2);
|
||||
a3 = _mm_clmulepi64_si128(a1, a0, 0x00);
|
||||
a1 = _mm_clmulepi64_si128(a1, a0, 0x11);
|
||||
a1 = _mm_xor_si128(a1, a3);
|
||||
a1 = _mm_xor_si128(a1, a2);
|
||||
|
||||
/*
|
||||
* Fold 256-bits to 128-bits.
|
||||
*/
|
||||
a2 = _mm512_extracti32x4_epi32(x1, 3);
|
||||
a3 = _mm_clmulepi64_si128(a1, a0, 0x00);
|
||||
a1 = _mm_clmulepi64_si128(a1, a0, 0x11);
|
||||
a1 = _mm_xor_si128(a1, a3);
|
||||
a1 = _mm_xor_si128(a1, a2);
|
||||
|
||||
/*
|
||||
* Fold 128-bits to 64-bits.
|
||||
*/
|
||||
a2 = _mm_clmulepi64_si128(a1, a0, 0x10);
|
||||
a3 = _mm_setr_epi32(~0, 0, ~0, 0);
|
||||
a1 = _mm_srli_si128(a1, 8);
|
||||
a1 = _mm_xor_si128(a1, a2);
|
||||
|
||||
a0 = _mm_loadl_epi64((__m128i*)k7k8);
|
||||
a2 = _mm_srli_si128(a1, 4);
|
||||
a1 = _mm_and_si128(a1, a3);
|
||||
a1 = _mm_clmulepi64_si128(a1, a0, 0x00);
|
||||
a1 = _mm_xor_si128(a1, a2);
|
||||
|
||||
/*
|
||||
* Barret reduce to 32-bits.
|
||||
*/
|
||||
a0 = _mm_load_si128((__m128i*)poly);
|
||||
|
||||
a2 = _mm_and_si128(a1, a3);
|
||||
a2 = _mm_clmulepi64_si128(a2, a0, 0x10);
|
||||
a2 = _mm_and_si128(a2, a3);
|
||||
a2 = _mm_clmulepi64_si128(a2, a0, 0x00);
|
||||
a1 = _mm_xor_si128(a1, a2);
|
||||
|
||||
/*
|
||||
* Return the crc32.
|
||||
*/
|
||||
return _mm_extract_epi32(a1, 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
#if defined(CRC32_SIMD_SSE42_PCLMUL)
|
||||
|
||||
/*
|
||||
* crc32_sse42_simd_(): compute the crc32 of the buffer, where the buffer
|
||||
* length must be at least 64, and a multiple of 16.
|
||||
*/
|
||||
|
||||
#include <emmintrin.h>
|
||||
#include <smmintrin.h>
|
||||
#include <wmmintrin.h>
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
__attribute__((__target__("sse4.2,pclmul")))
|
||||
#endif
|
||||
uint32_t ZLIB_INTERNAL crc32_sse42_simd_( /* SSE4.2+PCLMUL */
|
||||
const unsigned char *buf,
|
||||
z_size_t len,
|
||||
uint32_t crc)
|
||||
{
|
||||
/*
|
||||
* Definitions of the bit-reflected domain constants k1,k2,k3, etc and
|
||||
* the CRC32+Barrett polynomials given at the end of the paper.
|
||||
*/
|
||||
static const uint64_t zalign(16) k1k2[] = { 0x0154442bd4, 0x01c6e41596 };
|
||||
static const uint64_t zalign(16) k3k4[] = { 0x01751997d0, 0x00ccaa009e };
|
||||
static const uint64_t zalign(16) k5k0[] = { 0x0163cd6124, 0x0000000000 };
|
||||
static const uint64_t zalign(16) poly[] = { 0x01db710641, 0x01f7011641 };
|
||||
|
||||
__m128i x0, x1, x2, x3, x4, x5, x6, x7, x8, y5, y6, y7, y8;
|
||||
|
||||
/*
|
||||
* There's at least one block of 64.
|
||||
*/
|
||||
x1 = _mm_loadu_si128((__m128i *)(buf + 0x00));
|
||||
x2 = _mm_loadu_si128((__m128i *)(buf + 0x10));
|
||||
x3 = _mm_loadu_si128((__m128i *)(buf + 0x20));
|
||||
x4 = _mm_loadu_si128((__m128i *)(buf + 0x30));
|
||||
|
||||
x1 = _mm_xor_si128(x1, _mm_cvtsi32_si128(crc));
|
||||
|
||||
x0 = _mm_load_si128((__m128i *)k1k2);
|
||||
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
|
||||
/*
|
||||
* Parallel fold blocks of 64, if any.
|
||||
*/
|
||||
while (len >= 64)
|
||||
{
|
||||
x5 = _mm_clmulepi64_si128(x1, x0, 0x00);
|
||||
x6 = _mm_clmulepi64_si128(x2, x0, 0x00);
|
||||
x7 = _mm_clmulepi64_si128(x3, x0, 0x00);
|
||||
x8 = _mm_clmulepi64_si128(x4, x0, 0x00);
|
||||
|
||||
x1 = _mm_clmulepi64_si128(x1, x0, 0x11);
|
||||
x2 = _mm_clmulepi64_si128(x2, x0, 0x11);
|
||||
x3 = _mm_clmulepi64_si128(x3, x0, 0x11);
|
||||
x4 = _mm_clmulepi64_si128(x4, x0, 0x11);
|
||||
|
||||
y5 = _mm_loadu_si128((__m128i *)(buf + 0x00));
|
||||
y6 = _mm_loadu_si128((__m128i *)(buf + 0x10));
|
||||
y7 = _mm_loadu_si128((__m128i *)(buf + 0x20));
|
||||
y8 = _mm_loadu_si128((__m128i *)(buf + 0x30));
|
||||
|
||||
x1 = _mm_xor_si128(x1, x5);
|
||||
x2 = _mm_xor_si128(x2, x6);
|
||||
x3 = _mm_xor_si128(x3, x7);
|
||||
x4 = _mm_xor_si128(x4, x8);
|
||||
|
||||
x1 = _mm_xor_si128(x1, y5);
|
||||
x2 = _mm_xor_si128(x2, y6);
|
||||
x3 = _mm_xor_si128(x3, y7);
|
||||
x4 = _mm_xor_si128(x4, y8);
|
||||
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fold into 128-bits.
|
||||
*/
|
||||
x0 = _mm_load_si128((__m128i *)k3k4);
|
||||
|
||||
x5 = _mm_clmulepi64_si128(x1, x0, 0x00);
|
||||
x1 = _mm_clmulepi64_si128(x1, x0, 0x11);
|
||||
x1 = _mm_xor_si128(x1, x2);
|
||||
x1 = _mm_xor_si128(x1, x5);
|
||||
|
||||
x5 = _mm_clmulepi64_si128(x1, x0, 0x00);
|
||||
x1 = _mm_clmulepi64_si128(x1, x0, 0x11);
|
||||
x1 = _mm_xor_si128(x1, x3);
|
||||
x1 = _mm_xor_si128(x1, x5);
|
||||
|
||||
x5 = _mm_clmulepi64_si128(x1, x0, 0x00);
|
||||
x1 = _mm_clmulepi64_si128(x1, x0, 0x11);
|
||||
x1 = _mm_xor_si128(x1, x4);
|
||||
x1 = _mm_xor_si128(x1, x5);
|
||||
|
||||
/*
|
||||
* Single fold blocks of 16, if any.
|
||||
*/
|
||||
while (len >= 16)
|
||||
{
|
||||
x2 = _mm_loadu_si128((__m128i *)buf);
|
||||
|
||||
x5 = _mm_clmulepi64_si128(x1, x0, 0x00);
|
||||
x1 = _mm_clmulepi64_si128(x1, x0, 0x11);
|
||||
x1 = _mm_xor_si128(x1, x2);
|
||||
x1 = _mm_xor_si128(x1, x5);
|
||||
|
||||
buf += 16;
|
||||
len -= 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fold 128-bits to 64-bits.
|
||||
*/
|
||||
x2 = _mm_clmulepi64_si128(x1, x0, 0x10);
|
||||
x3 = _mm_setr_epi32(~0, 0, ~0, 0);
|
||||
x1 = _mm_srli_si128(x1, 8);
|
||||
x1 = _mm_xor_si128(x1, x2);
|
||||
|
||||
x0 = _mm_loadl_epi64((__m128i*)k5k0);
|
||||
|
||||
x2 = _mm_srli_si128(x1, 4);
|
||||
x1 = _mm_and_si128(x1, x3);
|
||||
x1 = _mm_clmulepi64_si128(x1, x0, 0x00);
|
||||
x1 = _mm_xor_si128(x1, x2);
|
||||
|
||||
/*
|
||||
* Barret reduce to 32-bits.
|
||||
*/
|
||||
x0 = _mm_load_si128((__m128i*)poly);
|
||||
|
||||
x2 = _mm_and_si128(x1, x3);
|
||||
x2 = _mm_clmulepi64_si128(x2, x0, 0x10);
|
||||
x2 = _mm_and_si128(x2, x3);
|
||||
x2 = _mm_clmulepi64_si128(x2, x0, 0x00);
|
||||
x1 = _mm_xor_si128(x1, x2);
|
||||
|
||||
/*
|
||||
* Return the crc32.
|
||||
*/
|
||||
return _mm_extract_epi32(x1, 1);
|
||||
}
|
||||
|
||||
#elif defined(CRC32_ARMV8_CRC32)
|
||||
|
||||
/* CRC32 checksums using ARMv8-a crypto instructions.
|
||||
*/
|
||||
|
||||
#if defined(__clang__)
|
||||
/* We need some extra types for using PMULL.
|
||||
*/
|
||||
#if defined(__aarch64__)
|
||||
#include <arm_neon.h>
|
||||
#include <arm_acle.h>
|
||||
#endif
|
||||
|
||||
/* CRC32 intrinsics are #ifdef'ed out of arm_acle.h unless we build with an
|
||||
* armv8 target, which is incompatible with ThinLTO optimizations on Android.
|
||||
* (Namely, mixing and matching different module-level targets makes ThinLTO
|
||||
* warn, and Android defaults to armv7-a. This restriction does not apply to
|
||||
* function-level `target`s, however.)
|
||||
*
|
||||
* Since we only need four crc intrinsics, and since clang's implementation of
|
||||
* those are just wrappers around compiler builtins, it's simplest to #define
|
||||
* those builtins directly. If this #define list grows too much (or we depend on
|
||||
* an intrinsic that isn't a trivial wrapper), we may have to find a better way
|
||||
* to go about this.
|
||||
*
|
||||
* NOTE: clang currently complains that "'+soft-float-abi' is not a recognized
|
||||
* feature for this target (ignoring feature)." This appears to be a harmless
|
||||
* bug in clang.
|
||||
*
|
||||
* These definitions must appear *after* including arm_acle.h otherwise that
|
||||
* header may end up defining functions named __builtin_arm_crc32* that call
|
||||
* themselves, creating an infinite loop when the intrinsic is called.
|
||||
*/
|
||||
/* XXX: Cannot hook into builtins with XCode for arm64. */
|
||||
#if !defined(ARMV8_OS_MACOS)
|
||||
#define __crc32b __builtin_arm_crc32b
|
||||
#define __crc32d __builtin_arm_crc32d
|
||||
#define __crc32w __builtin_arm_crc32w
|
||||
#define __crc32cw __builtin_arm_crc32cw
|
||||
#endif
|
||||
|
||||
#if defined(__aarch64__)
|
||||
#define TARGET_ARMV8_WITH_CRC __attribute__((target("arch=armv8-a+aes+crc")))
|
||||
#else // !defined(__aarch64__)
|
||||
#define TARGET_ARMV8_WITH_CRC __attribute__((target("crc")))
|
||||
#endif // defined(__aarch64__)
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
/* For GCC, we are setting CRC extensions at module level, so ThinLTO is not
|
||||
* allowed. We can just include arm_acle.h.
|
||||
*/
|
||||
#include <arm_acle.h>
|
||||
#include <arm_neon.h>
|
||||
#define TARGET_ARMV8_WITH_CRC __attribute__((target("arch=armv8-a+crc+crypto")))
|
||||
#else // !defined(__GNUC__) && !defined(_aarch64__)
|
||||
#error ARM CRC32 SIMD extensions only supported for Clang and GCC
|
||||
#endif
|
||||
|
||||
TARGET_ARMV8_WITH_CRC
|
||||
uint32_t ZLIB_INTERNAL armv8_crc32_little(
|
||||
const unsigned char *buf,
|
||||
z_size_t len,
|
||||
uint32_t crc)
|
||||
{
|
||||
uint32_t c = (uint32_t) ~crc;
|
||||
|
||||
while (len && ((uintptr_t)buf & 7)) {
|
||||
c = __crc32b(c, *buf++);
|
||||
--len;
|
||||
}
|
||||
|
||||
const uint64_t *buf8 = (const uint64_t *)buf;
|
||||
|
||||
while (len >= 64) {
|
||||
c = __crc32d(c, *buf8++);
|
||||
c = __crc32d(c, *buf8++);
|
||||
c = __crc32d(c, *buf8++);
|
||||
c = __crc32d(c, *buf8++);
|
||||
|
||||
c = __crc32d(c, *buf8++);
|
||||
c = __crc32d(c, *buf8++);
|
||||
c = __crc32d(c, *buf8++);
|
||||
c = __crc32d(c, *buf8++);
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
while (len >= 8) {
|
||||
c = __crc32d(c, *buf8++);
|
||||
len -= 8;
|
||||
}
|
||||
|
||||
buf = (const unsigned char *)buf8;
|
||||
|
||||
while (len--) {
|
||||
c = __crc32b(c, *buf++);
|
||||
}
|
||||
|
||||
return ~c;
|
||||
}
|
||||
|
||||
#if defined(__aarch64__) || defined(ARMV8_OS_MACOS) /* aarch64 specific code. */
|
||||
|
||||
/*
|
||||
* crc32_pmull_simd_(): compute the crc32 of the buffer, where the buffer
|
||||
* length must be at least 64, and a multiple of 16. Based on:
|
||||
*
|
||||
* "Fast CRC Computation for Generic Polynomials Using PCLMULQDQ Instruction"
|
||||
* V. Gopal, E. Ozturk, et al., 2009, http://intel.ly/2ySEwL0
|
||||
*/
|
||||
TARGET_ARMV8_WITH_CRC
|
||||
static inline uint8x16_t pmull_lo(const uint64x2_t a, const uint64x2_t b)
|
||||
{
|
||||
uint8x16_t r;
|
||||
__asm__ __volatile__ ("pmull %0.1q, %1.1d, %2.1d \n\t"
|
||||
: "=w" (r) : "w" (a), "w" (b) );
|
||||
return r;
|
||||
}
|
||||
|
||||
TARGET_ARMV8_WITH_CRC
|
||||
static inline uint8x16_t pmull_01(const uint64x2_t a, const uint64x2_t b)
|
||||
{
|
||||
uint8x16_t r;
|
||||
__asm__ __volatile__ ("pmull %0.1q, %1.1d, %2.1d \n\t"
|
||||
: "=w" (r) : "w" (a), "w" (vgetq_lane_u64(b, 1)) );
|
||||
return r;
|
||||
}
|
||||
|
||||
TARGET_ARMV8_WITH_CRC
|
||||
static inline uint8x16_t pmull_hi(const uint64x2_t a, const uint64x2_t b)
|
||||
{
|
||||
uint8x16_t r;
|
||||
__asm__ __volatile__ ("pmull2 %0.1q, %1.2d, %2.2d \n\t"
|
||||
: "=w" (r) : "w" (a), "w" (b) );
|
||||
return r;
|
||||
}
|
||||
|
||||
TARGET_ARMV8_WITH_CRC
|
||||
uint32_t ZLIB_INTERNAL armv8_crc32_pmull_little(
|
||||
const unsigned char *buf,
|
||||
z_size_t len,
|
||||
uint32_t crc)
|
||||
{
|
||||
/*
|
||||
* Definitions of the bit-reflected domain constants k1,k2,k3, etc and
|
||||
* the CRC32+Barrett polynomials given at the end of the paper.
|
||||
*/
|
||||
static const uint64_t zalign(16) k1k2[] = { 0x0154442bd4, 0x01c6e41596 };
|
||||
static const uint64_t zalign(16) k3k4[] = { 0x01751997d0, 0x00ccaa009e };
|
||||
static const uint64_t zalign(16) k5k0[] = { 0x0163cd6124, 0x0000000000 };
|
||||
static const uint64_t zalign(16) poly[] = { 0x01db710641, 0x01f7011641 };
|
||||
|
||||
uint64x2_t x0, x1, x2, x3, x4, x5, x6, x7, x8, y5, y6, y7, y8;
|
||||
|
||||
/*
|
||||
* There's at least one block of 64.
|
||||
*/
|
||||
x1 = vld1q_u64((const uint64_t *)(buf + 0x00));
|
||||
x2 = vld1q_u64((const uint64_t *)(buf + 0x10));
|
||||
x3 = vld1q_u64((const uint64_t *)(buf + 0x20));
|
||||
x4 = vld1q_u64((const uint64_t *)(buf + 0x30));
|
||||
|
||||
x1 = veorq_u64(x1, (uint64x2_t) vsetq_lane_u32(crc, vdupq_n_u32(0), 0));
|
||||
|
||||
x0 = vld1q_u64(k1k2);
|
||||
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
|
||||
/*
|
||||
* Parallel fold blocks of 64, if any.
|
||||
*/
|
||||
while (len >= 64)
|
||||
{
|
||||
x5 = (uint64x2_t) pmull_lo(x1, x0);
|
||||
x6 = (uint64x2_t) pmull_lo(x2, x0);
|
||||
x7 = (uint64x2_t) pmull_lo(x3, x0);
|
||||
x8 = (uint64x2_t) pmull_lo(x4, x0);
|
||||
|
||||
y5 = vld1q_u64((const uint64_t *)(buf + 0x00));
|
||||
y6 = vld1q_u64((const uint64_t *)(buf + 0x10));
|
||||
y7 = vld1q_u64((const uint64_t *)(buf + 0x20));
|
||||
y8 = vld1q_u64((const uint64_t *)(buf + 0x30));
|
||||
|
||||
x1 = (uint64x2_t) pmull_hi(x1, x0);
|
||||
x2 = (uint64x2_t) pmull_hi(x2, x0);
|
||||
x3 = (uint64x2_t) pmull_hi(x3, x0);
|
||||
x4 = (uint64x2_t) pmull_hi(x4, x0);
|
||||
|
||||
x1 = veorq_u64(x1, x5);
|
||||
x2 = veorq_u64(x2, x6);
|
||||
x3 = veorq_u64(x3, x7);
|
||||
x4 = veorq_u64(x4, x8);
|
||||
|
||||
x1 = veorq_u64(x1, y5);
|
||||
x2 = veorq_u64(x2, y6);
|
||||
x3 = veorq_u64(x3, y7);
|
||||
x4 = veorq_u64(x4, y8);
|
||||
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fold into 128-bits.
|
||||
*/
|
||||
x0 = vld1q_u64(k3k4);
|
||||
|
||||
x5 = (uint64x2_t) pmull_lo(x1, x0);
|
||||
x1 = (uint64x2_t) pmull_hi(x1, x0);
|
||||
x1 = veorq_u64(x1, x2);
|
||||
x1 = veorq_u64(x1, x5);
|
||||
|
||||
x5 = (uint64x2_t) pmull_lo(x1, x0);
|
||||
x1 = (uint64x2_t) pmull_hi(x1, x0);
|
||||
x1 = veorq_u64(x1, x3);
|
||||
x1 = veorq_u64(x1, x5);
|
||||
|
||||
x5 = (uint64x2_t) pmull_lo(x1, x0);
|
||||
x1 = (uint64x2_t) pmull_hi(x1, x0);
|
||||
x1 = veorq_u64(x1, x4);
|
||||
x1 = veorq_u64(x1, x5);
|
||||
|
||||
/*
|
||||
* Single fold blocks of 16, if any.
|
||||
*/
|
||||
while (len >= 16)
|
||||
{
|
||||
x2 = vld1q_u64((const uint64_t *)buf);
|
||||
|
||||
x5 = (uint64x2_t) pmull_lo(x1, x0);
|
||||
x1 = (uint64x2_t) pmull_hi(x1, x0);
|
||||
x1 = veorq_u64(x1, x2);
|
||||
x1 = veorq_u64(x1, x5);
|
||||
|
||||
buf += 16;
|
||||
len -= 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fold 128-bits to 64-bits.
|
||||
*/
|
||||
static uint32_t zalign(16) mask[] = { ~0u, 0u, ~0u, 0u };
|
||||
|
||||
x2 = (uint64x2_t) pmull_01(x1, x0);
|
||||
x1 = (uint64x2_t) vextq_u8(vreinterpretq_u8_u64(x1), vdupq_n_u8(0), 8);
|
||||
x3 = (uint64x2_t) vld1q_u32(mask);
|
||||
x1 = veorq_u64(x1, x2);
|
||||
|
||||
x0 = vld1q_u64(k5k0);
|
||||
|
||||
x2 = (uint64x2_t) pmull_01(x2, x0);
|
||||
x2 = (uint64x2_t) vextq_u8(vreinterpretq_u8_u64(x1), vdupq_n_u8(0), 4);
|
||||
x1 = vandq_u64(x1, x3);
|
||||
x1 = (uint64x2_t) pmull_lo(x1, x0);
|
||||
x1 = veorq_u64(x1, x2);
|
||||
|
||||
/*
|
||||
* Barret reduce to 32-bits.
|
||||
*/
|
||||
x0 = vld1q_u64(poly);
|
||||
|
||||
x2 = vandq_u64(x1, x3);
|
||||
x2 = (uint64x2_t) pmull_01(x2, x0);
|
||||
x2 = vandq_u64(x2, x3);
|
||||
x2 = (uint64x2_t) pmull_lo(x2, x0);
|
||||
x1 = veorq_u64(x1, x2);
|
||||
|
||||
/*
|
||||
* Return the crc32.
|
||||
*/
|
||||
return vgetq_lane_u32(vreinterpretq_u32_u64(x1), 1);
|
||||
}
|
||||
#endif /* aarch64 specific code. */
|
||||
|
||||
#endif
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/* crc32_simd.h
|
||||
*
|
||||
* Copyright 2017 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "zconf.h"
|
||||
#include "zutil.h"
|
||||
#include "deflate.h"
|
||||
|
||||
/*
|
||||
* crc32_sse42_simd_(): compute the crc32 of the buffer, where the buffer
|
||||
* length must be at least 64, and a multiple of 16.
|
||||
*/
|
||||
uint32_t ZLIB_INTERNAL crc32_sse42_simd_(const unsigned char* buf,
|
||||
z_size_t len,
|
||||
uint32_t crc);
|
||||
|
||||
uint32_t ZLIB_INTERNAL crc32_avx512_simd_(const unsigned char* buf,
|
||||
z_size_t len,
|
||||
uint32_t crc);
|
||||
|
||||
/*
|
||||
* crc32_sse42_simd_ buffer size constraints: see the use in zlib/crc32.c
|
||||
* for computing the crc32 of an arbitrary length buffer.
|
||||
*/
|
||||
#define Z_CRC32_SSE42_MINIMUM_LENGTH 64
|
||||
#define Z_CRC32_SSE42_CHUNKSIZE_MASK 15
|
||||
#define Z_CRC32_AVX512_MINIMUM_LENGTH 256
|
||||
#define Z_CRC32_AVX512_CHUNKSIZE_MASK 63
|
||||
|
||||
/*
|
||||
* CRC32 checksums using ARMv8-a crypto instructions.
|
||||
*/
|
||||
uint32_t ZLIB_INTERNAL armv8_crc32_little(const unsigned char* buf,
|
||||
z_size_t len,
|
||||
uint32_t crc);
|
||||
|
||||
/* aarch64 specific code. */
|
||||
#if defined(__aarch64__)
|
||||
|
||||
/* 128 is the sweet spot at the time of coding (late 2020). */
|
||||
#define Z_CRC32_PMULL_MINIMUM_LENGTH 128
|
||||
#define Z_CRC32_PMULL_CHUNKSIZE_MASK 15
|
||||
|
||||
/*
|
||||
* CRC32 checksums using ARMv8-a PMULL instructions, where the buffer
|
||||
* length must be at least 64, and a multiple of 16.
|
||||
*/
|
||||
uint32_t ZLIB_INTERNAL armv8_crc32_pmull_little(const unsigned char* buf,
|
||||
z_size_t len,
|
||||
uint32_t crc);
|
||||
|
||||
#endif
|
||||
+513
@@ -0,0 +1,513 @@
|
||||
/*
|
||||
* Compute the CRC32 using a parallelized folding approach with the PCLMULQDQ
|
||||
* instruction.
|
||||
*
|
||||
* A white paper describing this algorithm can be found at:
|
||||
* http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
|
||||
*
|
||||
* Copyright (C) 2013 Intel Corporation. All rights reserved.
|
||||
* Authors:
|
||||
* Wajdi Feghali <wajdi.k.feghali@intel.com>
|
||||
* Jim Guilford <james.guilford@intel.com>
|
||||
* Vinodh Gopal <vinodh.gopal@intel.com>
|
||||
* Erdinc Ozturk <erdinc.ozturk@intel.com>
|
||||
* Jim Kukunas <james.t.kukunas@linux.intel.com>
|
||||
*
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
#include "deflate.h"
|
||||
|
||||
#ifdef CRC32_SIMD_SSE42_PCLMUL
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <emmintrin.h>
|
||||
#include <immintrin.h>
|
||||
#include <wmmintrin.h>
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define TARGET_SSE42_PCLMUL __attribute__((__target__("sse4.2,pclmul")))
|
||||
#else
|
||||
#define TARGET_SSE42_PCLMUL
|
||||
#endif
|
||||
|
||||
#define CRC_LOAD(s) \
|
||||
do { \
|
||||
__m128i xmm_crc0 = _mm_loadu_si128((__m128i *)s->crc0 + 0);\
|
||||
__m128i xmm_crc1 = _mm_loadu_si128((__m128i *)s->crc0 + 1);\
|
||||
__m128i xmm_crc2 = _mm_loadu_si128((__m128i *)s->crc0 + 2);\
|
||||
__m128i xmm_crc3 = _mm_loadu_si128((__m128i *)s->crc0 + 3);\
|
||||
__m128i xmm_crc_part = _mm_loadu_si128((__m128i *)s->crc0 + 4);
|
||||
|
||||
#define CRC_SAVE(s) \
|
||||
_mm_storeu_si128((__m128i *)s->crc0 + 0, xmm_crc0);\
|
||||
_mm_storeu_si128((__m128i *)s->crc0 + 1, xmm_crc1);\
|
||||
_mm_storeu_si128((__m128i *)s->crc0 + 2, xmm_crc2);\
|
||||
_mm_storeu_si128((__m128i *)s->crc0 + 3, xmm_crc3);\
|
||||
_mm_storeu_si128((__m128i *)s->crc0 + 4, xmm_crc_part);\
|
||||
} while (0);
|
||||
|
||||
TARGET_SSE42_PCLMUL
|
||||
ZLIB_INTERNAL void crc_fold_init(deflate_state *const s)
|
||||
{
|
||||
CRC_LOAD(s)
|
||||
|
||||
xmm_crc0 = _mm_cvtsi32_si128(0x9db42487);
|
||||
xmm_crc1 = _mm_setzero_si128();
|
||||
xmm_crc2 = _mm_setzero_si128();
|
||||
xmm_crc3 = _mm_setzero_si128();
|
||||
|
||||
CRC_SAVE(s)
|
||||
|
||||
s->strm->adler = 0;
|
||||
}
|
||||
|
||||
TARGET_SSE42_PCLMUL
|
||||
local void fold_1(deflate_state *const s,
|
||||
__m128i *xmm_crc0, __m128i *xmm_crc1,
|
||||
__m128i *xmm_crc2, __m128i *xmm_crc3)
|
||||
{
|
||||
const __m128i xmm_fold4 = _mm_set_epi32(
|
||||
0x00000001, 0x54442bd4,
|
||||
0x00000001, 0xc6e41596);
|
||||
|
||||
__m128i x_tmp3;
|
||||
__m128 ps_crc0, ps_crc3, ps_res;
|
||||
|
||||
x_tmp3 = *xmm_crc3;
|
||||
|
||||
*xmm_crc3 = *xmm_crc0;
|
||||
*xmm_crc0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01);
|
||||
*xmm_crc3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x10);
|
||||
ps_crc0 = _mm_castsi128_ps(*xmm_crc0);
|
||||
ps_crc3 = _mm_castsi128_ps(*xmm_crc3);
|
||||
ps_res = _mm_xor_ps(ps_crc0, ps_crc3);
|
||||
|
||||
*xmm_crc0 = *xmm_crc1;
|
||||
*xmm_crc1 = *xmm_crc2;
|
||||
*xmm_crc2 = x_tmp3;
|
||||
*xmm_crc3 = _mm_castps_si128(ps_res);
|
||||
}
|
||||
|
||||
TARGET_SSE42_PCLMUL
|
||||
local void fold_2(deflate_state *const s,
|
||||
__m128i *xmm_crc0, __m128i *xmm_crc1,
|
||||
__m128i *xmm_crc2, __m128i *xmm_crc3)
|
||||
{
|
||||
const __m128i xmm_fold4 = _mm_set_epi32(
|
||||
0x00000001, 0x54442bd4,
|
||||
0x00000001, 0xc6e41596);
|
||||
|
||||
__m128i x_tmp3, x_tmp2;
|
||||
__m128 ps_crc0, ps_crc1, ps_crc2, ps_crc3, ps_res31, ps_res20;
|
||||
|
||||
x_tmp3 = *xmm_crc3;
|
||||
x_tmp2 = *xmm_crc2;
|
||||
|
||||
*xmm_crc3 = *xmm_crc1;
|
||||
*xmm_crc1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x01);
|
||||
*xmm_crc3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x10);
|
||||
ps_crc3 = _mm_castsi128_ps(*xmm_crc3);
|
||||
ps_crc1 = _mm_castsi128_ps(*xmm_crc1);
|
||||
ps_res31= _mm_xor_ps(ps_crc3, ps_crc1);
|
||||
|
||||
*xmm_crc2 = *xmm_crc0;
|
||||
*xmm_crc0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01);
|
||||
*xmm_crc2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x10);
|
||||
ps_crc0 = _mm_castsi128_ps(*xmm_crc0);
|
||||
ps_crc2 = _mm_castsi128_ps(*xmm_crc2);
|
||||
ps_res20= _mm_xor_ps(ps_crc0, ps_crc2);
|
||||
|
||||
*xmm_crc0 = x_tmp2;
|
||||
*xmm_crc1 = x_tmp3;
|
||||
*xmm_crc2 = _mm_castps_si128(ps_res20);
|
||||
*xmm_crc3 = _mm_castps_si128(ps_res31);
|
||||
}
|
||||
|
||||
TARGET_SSE42_PCLMUL
|
||||
local void fold_3(deflate_state *const s,
|
||||
__m128i *xmm_crc0, __m128i *xmm_crc1,
|
||||
__m128i *xmm_crc2, __m128i *xmm_crc3)
|
||||
{
|
||||
const __m128i xmm_fold4 = _mm_set_epi32(
|
||||
0x00000001, 0x54442bd4,
|
||||
0x00000001, 0xc6e41596);
|
||||
|
||||
__m128i x_tmp3;
|
||||
__m128 ps_crc0, ps_crc1, ps_crc2, ps_crc3, ps_res32, ps_res21, ps_res10;
|
||||
|
||||
x_tmp3 = *xmm_crc3;
|
||||
|
||||
*xmm_crc3 = *xmm_crc2;
|
||||
*xmm_crc2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x01);
|
||||
*xmm_crc3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x10);
|
||||
ps_crc2 = _mm_castsi128_ps(*xmm_crc2);
|
||||
ps_crc3 = _mm_castsi128_ps(*xmm_crc3);
|
||||
ps_res32 = _mm_xor_ps(ps_crc2, ps_crc3);
|
||||
|
||||
*xmm_crc2 = *xmm_crc1;
|
||||
*xmm_crc1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x01);
|
||||
*xmm_crc2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x10);
|
||||
ps_crc1 = _mm_castsi128_ps(*xmm_crc1);
|
||||
ps_crc2 = _mm_castsi128_ps(*xmm_crc2);
|
||||
ps_res21= _mm_xor_ps(ps_crc1, ps_crc2);
|
||||
|
||||
*xmm_crc1 = *xmm_crc0;
|
||||
*xmm_crc0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01);
|
||||
*xmm_crc1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x10);
|
||||
ps_crc0 = _mm_castsi128_ps(*xmm_crc0);
|
||||
ps_crc1 = _mm_castsi128_ps(*xmm_crc1);
|
||||
ps_res10= _mm_xor_ps(ps_crc0, ps_crc1);
|
||||
|
||||
*xmm_crc0 = x_tmp3;
|
||||
*xmm_crc1 = _mm_castps_si128(ps_res10);
|
||||
*xmm_crc2 = _mm_castps_si128(ps_res21);
|
||||
*xmm_crc3 = _mm_castps_si128(ps_res32);
|
||||
}
|
||||
|
||||
TARGET_SSE42_PCLMUL
|
||||
local void fold_4(deflate_state *const s,
|
||||
__m128i *xmm_crc0, __m128i *xmm_crc1,
|
||||
__m128i *xmm_crc2, __m128i *xmm_crc3)
|
||||
{
|
||||
const __m128i xmm_fold4 = _mm_set_epi32(
|
||||
0x00000001, 0x54442bd4,
|
||||
0x00000001, 0xc6e41596);
|
||||
|
||||
__m128i x_tmp0, x_tmp1, x_tmp2, x_tmp3;
|
||||
__m128 ps_crc0, ps_crc1, ps_crc2, ps_crc3;
|
||||
__m128 ps_t0, ps_t1, ps_t2, ps_t3;
|
||||
__m128 ps_res0, ps_res1, ps_res2, ps_res3;
|
||||
|
||||
x_tmp0 = *xmm_crc0;
|
||||
x_tmp1 = *xmm_crc1;
|
||||
x_tmp2 = *xmm_crc2;
|
||||
x_tmp3 = *xmm_crc3;
|
||||
|
||||
*xmm_crc0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01);
|
||||
x_tmp0 = _mm_clmulepi64_si128(x_tmp0, xmm_fold4, 0x10);
|
||||
ps_crc0 = _mm_castsi128_ps(*xmm_crc0);
|
||||
ps_t0 = _mm_castsi128_ps(x_tmp0);
|
||||
ps_res0 = _mm_xor_ps(ps_crc0, ps_t0);
|
||||
|
||||
*xmm_crc1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x01);
|
||||
x_tmp1 = _mm_clmulepi64_si128(x_tmp1, xmm_fold4, 0x10);
|
||||
ps_crc1 = _mm_castsi128_ps(*xmm_crc1);
|
||||
ps_t1 = _mm_castsi128_ps(x_tmp1);
|
||||
ps_res1 = _mm_xor_ps(ps_crc1, ps_t1);
|
||||
|
||||
*xmm_crc2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x01);
|
||||
x_tmp2 = _mm_clmulepi64_si128(x_tmp2, xmm_fold4, 0x10);
|
||||
ps_crc2 = _mm_castsi128_ps(*xmm_crc2);
|
||||
ps_t2 = _mm_castsi128_ps(x_tmp2);
|
||||
ps_res2 = _mm_xor_ps(ps_crc2, ps_t2);
|
||||
|
||||
*xmm_crc3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x01);
|
||||
x_tmp3 = _mm_clmulepi64_si128(x_tmp3, xmm_fold4, 0x10);
|
||||
ps_crc3 = _mm_castsi128_ps(*xmm_crc3);
|
||||
ps_t3 = _mm_castsi128_ps(x_tmp3);
|
||||
ps_res3 = _mm_xor_ps(ps_crc3, ps_t3);
|
||||
|
||||
*xmm_crc0 = _mm_castps_si128(ps_res0);
|
||||
*xmm_crc1 = _mm_castps_si128(ps_res1);
|
||||
*xmm_crc2 = _mm_castps_si128(ps_res2);
|
||||
*xmm_crc3 = _mm_castps_si128(ps_res3);
|
||||
}
|
||||
|
||||
local const unsigned zalign(32) pshufb_shf_table[60] = {
|
||||
0x84838281,0x88878685,0x8c8b8a89,0x008f8e8d, /* shl 15 (16 - 1)/shr1 */
|
||||
0x85848382,0x89888786,0x8d8c8b8a,0x01008f8e, /* shl 14 (16 - 3)/shr2 */
|
||||
0x86858483,0x8a898887,0x8e8d8c8b,0x0201008f, /* shl 13 (16 - 4)/shr3 */
|
||||
0x87868584,0x8b8a8988,0x8f8e8d8c,0x03020100, /* shl 12 (16 - 4)/shr4 */
|
||||
0x88878685,0x8c8b8a89,0x008f8e8d,0x04030201, /* shl 11 (16 - 5)/shr5 */
|
||||
0x89888786,0x8d8c8b8a,0x01008f8e,0x05040302, /* shl 10 (16 - 6)/shr6 */
|
||||
0x8a898887,0x8e8d8c8b,0x0201008f,0x06050403, /* shl 9 (16 - 7)/shr7 */
|
||||
0x8b8a8988,0x8f8e8d8c,0x03020100,0x07060504, /* shl 8 (16 - 8)/shr8 */
|
||||
0x8c8b8a89,0x008f8e8d,0x04030201,0x08070605, /* shl 7 (16 - 9)/shr9 */
|
||||
0x8d8c8b8a,0x01008f8e,0x05040302,0x09080706, /* shl 6 (16 -10)/shr10*/
|
||||
0x8e8d8c8b,0x0201008f,0x06050403,0x0a090807, /* shl 5 (16 -11)/shr11*/
|
||||
0x8f8e8d8c,0x03020100,0x07060504,0x0b0a0908, /* shl 4 (16 -12)/shr12*/
|
||||
0x008f8e8d,0x04030201,0x08070605,0x0c0b0a09, /* shl 3 (16 -13)/shr13*/
|
||||
0x01008f8e,0x05040302,0x09080706,0x0d0c0b0a, /* shl 2 (16 -14)/shr14*/
|
||||
0x0201008f,0x06050403,0x0a090807,0x0e0d0c0b /* shl 1 (16 -15)/shr15*/
|
||||
};
|
||||
|
||||
TARGET_SSE42_PCLMUL
|
||||
local void partial_fold(deflate_state *const s, const size_t len,
|
||||
__m128i *xmm_crc0, __m128i *xmm_crc1,
|
||||
__m128i *xmm_crc2, __m128i *xmm_crc3,
|
||||
__m128i *xmm_crc_part)
|
||||
{
|
||||
|
||||
const __m128i xmm_fold4 = _mm_set_epi32(
|
||||
0x00000001, 0x54442bd4,
|
||||
0x00000001, 0xc6e41596);
|
||||
const __m128i xmm_mask3 = _mm_set1_epi32(0x80808080);
|
||||
|
||||
__m128i xmm_shl, xmm_shr, xmm_tmp1, xmm_tmp2, xmm_tmp3;
|
||||
__m128i xmm_a0_0, xmm_a0_1;
|
||||
__m128 ps_crc3, psa0_0, psa0_1, ps_res;
|
||||
|
||||
xmm_shl = _mm_load_si128((__m128i *)pshufb_shf_table + (len - 1));
|
||||
xmm_shr = xmm_shl;
|
||||
xmm_shr = _mm_xor_si128(xmm_shr, xmm_mask3);
|
||||
|
||||
xmm_a0_0 = _mm_shuffle_epi8(*xmm_crc0, xmm_shl);
|
||||
|
||||
*xmm_crc0 = _mm_shuffle_epi8(*xmm_crc0, xmm_shr);
|
||||
xmm_tmp1 = _mm_shuffle_epi8(*xmm_crc1, xmm_shl);
|
||||
*xmm_crc0 = _mm_or_si128(*xmm_crc0, xmm_tmp1);
|
||||
|
||||
*xmm_crc1 = _mm_shuffle_epi8(*xmm_crc1, xmm_shr);
|
||||
xmm_tmp2 = _mm_shuffle_epi8(*xmm_crc2, xmm_shl);
|
||||
*xmm_crc1 = _mm_or_si128(*xmm_crc1, xmm_tmp2);
|
||||
|
||||
*xmm_crc2 = _mm_shuffle_epi8(*xmm_crc2, xmm_shr);
|
||||
xmm_tmp3 = _mm_shuffle_epi8(*xmm_crc3, xmm_shl);
|
||||
*xmm_crc2 = _mm_or_si128(*xmm_crc2, xmm_tmp3);
|
||||
|
||||
*xmm_crc3 = _mm_shuffle_epi8(*xmm_crc3, xmm_shr);
|
||||
*xmm_crc_part = _mm_shuffle_epi8(*xmm_crc_part, xmm_shl);
|
||||
*xmm_crc3 = _mm_or_si128(*xmm_crc3, *xmm_crc_part);
|
||||
|
||||
xmm_a0_1 = _mm_clmulepi64_si128(xmm_a0_0, xmm_fold4, 0x10);
|
||||
xmm_a0_0 = _mm_clmulepi64_si128(xmm_a0_0, xmm_fold4, 0x01);
|
||||
|
||||
ps_crc3 = _mm_castsi128_ps(*xmm_crc3);
|
||||
psa0_0 = _mm_castsi128_ps(xmm_a0_0);
|
||||
psa0_1 = _mm_castsi128_ps(xmm_a0_1);
|
||||
|
||||
ps_res = _mm_xor_ps(ps_crc3, psa0_0);
|
||||
ps_res = _mm_xor_ps(ps_res, psa0_1);
|
||||
|
||||
*xmm_crc3 = _mm_castps_si128(ps_res);
|
||||
}
|
||||
|
||||
TARGET_SSE42_PCLMUL
|
||||
ZLIB_INTERNAL void crc_fold_copy(deflate_state *const s,
|
||||
unsigned char *dst, const unsigned char *src, long len)
|
||||
{
|
||||
unsigned long algn_diff;
|
||||
__m128i xmm_t0, xmm_t1, xmm_t2, xmm_t3;
|
||||
|
||||
CRC_LOAD(s)
|
||||
|
||||
if (len < 16) {
|
||||
if (len == 0)
|
||||
return;
|
||||
goto partial;
|
||||
}
|
||||
|
||||
algn_diff = (0 - (uintptr_t)src) & 0xF;
|
||||
if (algn_diff) {
|
||||
xmm_crc_part = _mm_loadu_si128((__m128i *)src);
|
||||
_mm_storeu_si128((__m128i *)dst, xmm_crc_part);
|
||||
|
||||
dst += algn_diff;
|
||||
src += algn_diff;
|
||||
len -= algn_diff;
|
||||
|
||||
partial_fold(s, algn_diff, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3,
|
||||
&xmm_crc_part);
|
||||
}
|
||||
|
||||
while ((len -= 64) >= 0) {
|
||||
xmm_t0 = _mm_load_si128((__m128i *)src);
|
||||
xmm_t1 = _mm_load_si128((__m128i *)src + 1);
|
||||
xmm_t2 = _mm_load_si128((__m128i *)src + 2);
|
||||
xmm_t3 = _mm_load_si128((__m128i *)src + 3);
|
||||
|
||||
fold_4(s, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3);
|
||||
|
||||
_mm_storeu_si128((__m128i *)dst, xmm_t0);
|
||||
_mm_storeu_si128((__m128i *)dst + 1, xmm_t1);
|
||||
_mm_storeu_si128((__m128i *)dst + 2, xmm_t2);
|
||||
_mm_storeu_si128((__m128i *)dst + 3, xmm_t3);
|
||||
|
||||
xmm_crc0 = _mm_xor_si128(xmm_crc0, xmm_t0);
|
||||
xmm_crc1 = _mm_xor_si128(xmm_crc1, xmm_t1);
|
||||
xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_t2);
|
||||
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t3);
|
||||
|
||||
src += 64;
|
||||
dst += 64;
|
||||
}
|
||||
|
||||
/*
|
||||
* len = num bytes left - 64
|
||||
*/
|
||||
if (len + 16 >= 0) {
|
||||
len += 16;
|
||||
|
||||
xmm_t0 = _mm_load_si128((__m128i *)src);
|
||||
xmm_t1 = _mm_load_si128((__m128i *)src + 1);
|
||||
xmm_t2 = _mm_load_si128((__m128i *)src + 2);
|
||||
|
||||
fold_3(s, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3);
|
||||
|
||||
_mm_storeu_si128((__m128i *)dst, xmm_t0);
|
||||
_mm_storeu_si128((__m128i *)dst + 1, xmm_t1);
|
||||
_mm_storeu_si128((__m128i *)dst + 2, xmm_t2);
|
||||
|
||||
xmm_crc1 = _mm_xor_si128(xmm_crc1, xmm_t0);
|
||||
xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_t1);
|
||||
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t2);
|
||||
|
||||
if (len == 0)
|
||||
goto done;
|
||||
|
||||
dst += 48;
|
||||
src += 48;
|
||||
} else if (len + 32 >= 0) {
|
||||
len += 32;
|
||||
|
||||
xmm_t0 = _mm_load_si128((__m128i *)src);
|
||||
xmm_t1 = _mm_load_si128((__m128i *)src + 1);
|
||||
|
||||
fold_2(s, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3);
|
||||
|
||||
_mm_storeu_si128((__m128i *)dst, xmm_t0);
|
||||
_mm_storeu_si128((__m128i *)dst + 1, xmm_t1);
|
||||
|
||||
xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_t0);
|
||||
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t1);
|
||||
|
||||
if (len == 0)
|
||||
goto done;
|
||||
|
||||
dst += 32;
|
||||
src += 32;
|
||||
} else if (len + 48 >= 0) {
|
||||
len += 48;
|
||||
|
||||
xmm_t0 = _mm_load_si128((__m128i *)src);
|
||||
|
||||
fold_1(s, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3);
|
||||
|
||||
_mm_storeu_si128((__m128i *)dst, xmm_t0);
|
||||
|
||||
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t0);
|
||||
|
||||
if (len == 0)
|
||||
goto done;
|
||||
|
||||
dst += 16;
|
||||
src += 16;
|
||||
} else {
|
||||
len += 64;
|
||||
if (len == 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
partial:
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
/* VS does not permit the use of _mm_set_epi64x in 32-bit builds */
|
||||
{
|
||||
int32_t parts[4] = {0, 0, 0, 0};
|
||||
memcpy(&parts, src, len);
|
||||
xmm_crc_part = _mm_set_epi32(parts[3], parts[2], parts[1], parts[0]);
|
||||
}
|
||||
#else
|
||||
{
|
||||
int64_t parts[2] = {0, 0};
|
||||
memcpy(&parts, src, len);
|
||||
xmm_crc_part = _mm_set_epi64x(parts[1], parts[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
zmemcpy(dst, src, len); /* TODO: Possibly generate more efficient code. */
|
||||
partial_fold(s, len, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3,
|
||||
&xmm_crc_part);
|
||||
done:
|
||||
CRC_SAVE(s)
|
||||
}
|
||||
|
||||
local const unsigned zalign(16) crc_k[] = {
|
||||
0xccaa009e, 0x00000000, /* rk1 */
|
||||
0x751997d0, 0x00000001, /* rk2 */
|
||||
0xccaa009e, 0x00000000, /* rk5 */
|
||||
0x63cd6124, 0x00000001, /* rk6 */
|
||||
0xf7011640, 0x00000001, /* rk7 */
|
||||
0xdb710640, 0x00000001 /* rk8 */
|
||||
};
|
||||
|
||||
local const unsigned zalign(16) crc_mask[4] = {
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000
|
||||
};
|
||||
|
||||
local const unsigned zalign(16) crc_mask2[4] = {
|
||||
0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
|
||||
};
|
||||
|
||||
TARGET_SSE42_PCLMUL
|
||||
unsigned ZLIB_INTERNAL crc_fold_512to32(deflate_state *const s)
|
||||
{
|
||||
const __m128i xmm_mask = _mm_load_si128((__m128i *)crc_mask);
|
||||
const __m128i xmm_mask2 = _mm_load_si128((__m128i *)crc_mask2);
|
||||
|
||||
unsigned crc;
|
||||
__m128i x_tmp0, x_tmp1, x_tmp2, crc_fold;
|
||||
|
||||
__m128i xmm_crc0 = _mm_loadu_si128((__m128i *)s->crc0 + 0);
|
||||
__m128i xmm_crc1 = _mm_loadu_si128((__m128i *)s->crc0 + 1);
|
||||
__m128i xmm_crc2 = _mm_loadu_si128((__m128i *)s->crc0 + 2);
|
||||
__m128i xmm_crc3 = _mm_loadu_si128((__m128i *)s->crc0 + 3);
|
||||
|
||||
/*
|
||||
* k1
|
||||
*/
|
||||
crc_fold = _mm_load_si128((__m128i *)crc_k);
|
||||
|
||||
x_tmp0 = _mm_clmulepi64_si128(xmm_crc0, crc_fold, 0x10);
|
||||
xmm_crc0 = _mm_clmulepi64_si128(xmm_crc0, crc_fold, 0x01);
|
||||
xmm_crc1 = _mm_xor_si128(xmm_crc1, x_tmp0);
|
||||
xmm_crc1 = _mm_xor_si128(xmm_crc1, xmm_crc0);
|
||||
|
||||
x_tmp1 = _mm_clmulepi64_si128(xmm_crc1, crc_fold, 0x10);
|
||||
xmm_crc1 = _mm_clmulepi64_si128(xmm_crc1, crc_fold, 0x01);
|
||||
xmm_crc2 = _mm_xor_si128(xmm_crc2, x_tmp1);
|
||||
xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_crc1);
|
||||
|
||||
x_tmp2 = _mm_clmulepi64_si128(xmm_crc2, crc_fold, 0x10);
|
||||
xmm_crc2 = _mm_clmulepi64_si128(xmm_crc2, crc_fold, 0x01);
|
||||
xmm_crc3 = _mm_xor_si128(xmm_crc3, x_tmp2);
|
||||
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2);
|
||||
|
||||
/*
|
||||
* k5
|
||||
*/
|
||||
crc_fold = _mm_load_si128((__m128i *)crc_k + 1);
|
||||
|
||||
xmm_crc0 = xmm_crc3;
|
||||
xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0);
|
||||
xmm_crc0 = _mm_srli_si128(xmm_crc0, 8);
|
||||
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc0);
|
||||
|
||||
xmm_crc0 = xmm_crc3;
|
||||
xmm_crc3 = _mm_slli_si128(xmm_crc3, 4);
|
||||
xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0x10);
|
||||
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc0);
|
||||
xmm_crc3 = _mm_and_si128(xmm_crc3, xmm_mask2);
|
||||
|
||||
/*
|
||||
* k7
|
||||
*/
|
||||
xmm_crc1 = xmm_crc3;
|
||||
xmm_crc2 = xmm_crc3;
|
||||
crc_fold = _mm_load_si128((__m128i *)crc_k + 2);
|
||||
|
||||
xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0);
|
||||
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2);
|
||||
xmm_crc3 = _mm_and_si128(xmm_crc3, xmm_mask);
|
||||
|
||||
xmm_crc2 = xmm_crc3;
|
||||
xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0x10);
|
||||
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2);
|
||||
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc1);
|
||||
|
||||
crc = _mm_extract_epi32(xmm_crc3, 2);
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
#endif /* CRC32_SIMD_SSE42_PCLMUL */
|
||||
+344
-134
@@ -1,5 +1,5 @@
|
||||
/* deflate.c -- compress data using the deflation algorithm
|
||||
* Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler
|
||||
* Copyright (C) 1995-2026 Jean-loup Gailly and Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
* REFERENCES
|
||||
*
|
||||
* Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
|
||||
* Available in http://tools.ietf.org/html/rfc1951
|
||||
* Available at https://datatracker.ietf.org/doc/html/rfc1951
|
||||
*
|
||||
* A description of the Rabin and Karp algorithm is given in the book
|
||||
* "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
|
||||
@@ -48,11 +48,30 @@
|
||||
*/
|
||||
|
||||
/* @(#) $Id$ */
|
||||
|
||||
#include <assert.h>
|
||||
#include "deflate.h"
|
||||
|
||||
#include "cpu_features.h"
|
||||
|
||||
#if defined(DEFLATE_SLIDE_HASH_SSE2) || defined(DEFLATE_SLIDE_HASH_NEON)
|
||||
#include "slide_hash_simd.h"
|
||||
#endif
|
||||
|
||||
#include "compare256.h"
|
||||
|
||||
#if defined(QAT_COMPRESSION_ENABLED)
|
||||
#include "contrib/qat/deflate_qat.h"
|
||||
#endif
|
||||
|
||||
#include "contrib/optimizations/insert_string.h"
|
||||
|
||||
#ifdef FASTEST
|
||||
/* See http://crbug.com/1113596 */
|
||||
#error "FASTEST is not supported in Chromium's zlib."
|
||||
#endif
|
||||
|
||||
const char deflate_copyright[] =
|
||||
" deflate 1.3.1 Copyright 1995-2024 Jean-loup Gailly and Mark Adler ";
|
||||
" deflate 1.3.2.1 Copyright 1995-2026 Jean-loup Gailly and Mark Adler ";
|
||||
/*
|
||||
If you use the zlib library in a product, an acknowledgment is welcome
|
||||
in the documentation of your product. If for some reason you cannot
|
||||
@@ -78,6 +97,11 @@ local block_state deflate_slow(deflate_state *s, int flush);
|
||||
local block_state deflate_rle(deflate_state *s, int flush);
|
||||
local block_state deflate_huff(deflate_state *s, int flush);
|
||||
|
||||
/* From crc32.c */
|
||||
extern void ZLIB_INTERNAL crc_reset(deflate_state *const s);
|
||||
extern void ZLIB_INTERNAL crc_finalize(deflate_state *const s);
|
||||
extern void ZLIB_INTERNAL copy_with_crc(z_streamp strm, Bytef *dst, long size);
|
||||
|
||||
/* ===========================================================================
|
||||
* Local data
|
||||
*/
|
||||
@@ -132,46 +156,17 @@ local const config configuration_table[10] = {
|
||||
/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */
|
||||
#define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0))
|
||||
|
||||
/* ===========================================================================
|
||||
* Update a hash value with the given input byte
|
||||
* IN assertion: all calls to UPDATE_HASH are made with consecutive input
|
||||
* characters, so that a running hash key can be computed from the previous
|
||||
* key instead of complete recalculation each time.
|
||||
*/
|
||||
#define UPDATE_HASH(s,h,c) (h = (((h) << s->hash_shift) ^ (c)) & s->hash_mask)
|
||||
|
||||
|
||||
/* ===========================================================================
|
||||
* Insert string str in the dictionary and set match_head to the previous head
|
||||
* of the hash chain (the most recent string with same hash key). Return
|
||||
* the previous length of the hash chain.
|
||||
* If this file is compiled with -DFASTEST, the compression level is forced
|
||||
* to 1, and no hash chains are maintained.
|
||||
* IN assertion: all calls to INSERT_STRING are made with consecutive input
|
||||
* characters and the first MIN_MATCH bytes of str are valid (except for
|
||||
* the last MIN_MATCH-1 bytes of the input file).
|
||||
*/
|
||||
#ifdef FASTEST
|
||||
#define INSERT_STRING(s, str, match_head) \
|
||||
(UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
|
||||
match_head = s->head[s->ins_h], \
|
||||
s->head[s->ins_h] = (Pos)(str))
|
||||
#else
|
||||
#define INSERT_STRING(s, str, match_head) \
|
||||
(UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
|
||||
match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
|
||||
s->head[s->ins_h] = (Pos)(str))
|
||||
#endif
|
||||
|
||||
/* ===========================================================================
|
||||
* Initialize the hash table (avoiding 64K overflow for 16 bit systems).
|
||||
* prev[] will be initialized on the fly.
|
||||
* TODO(cavalcantii): optimization opportunity, check comments on:
|
||||
* https://chromium-review.googlesource.com/c/chromium/src/+/3561506/
|
||||
*/
|
||||
#define CLEAR_HASH(s) \
|
||||
do { \
|
||||
s->head[s->hash_size - 1] = NIL; \
|
||||
zmemzero((Bytef *)s->head, \
|
||||
(unsigned)(s->hash_size - 1)*sizeof(*s->head)); \
|
||||
zmemzero(s->head, (unsigned)(s->hash_size - 1)*sizeof(*s->head)); \
|
||||
s->slid = 0; \
|
||||
} while (0)
|
||||
|
||||
/* ===========================================================================
|
||||
@@ -185,6 +180,12 @@ local const config configuration_table[10] = {
|
||||
# endif
|
||||
#endif
|
||||
local void slide_hash(deflate_state *s) {
|
||||
#if defined(DEFLATE_SLIDE_HASH_SSE2) || defined(DEFLATE_SLIDE_HASH_NEON)
|
||||
slide_hash_simd(s->head, s->prev, s->w_size, s->hash_size);
|
||||
s->slid = 1;
|
||||
return;
|
||||
#endif
|
||||
|
||||
unsigned n, m;
|
||||
Posf *p;
|
||||
uInt wsize = s->w_size;
|
||||
@@ -195,8 +196,8 @@ local void slide_hash(deflate_state *s) {
|
||||
m = *--p;
|
||||
*p = (Pos)(m >= wsize ? m - wsize : NIL);
|
||||
} while (--n);
|
||||
n = wsize;
|
||||
#ifndef FASTEST
|
||||
n = wsize;
|
||||
p = &s->prev[n];
|
||||
do {
|
||||
m = *--p;
|
||||
@@ -206,6 +207,7 @@ local void slide_hash(deflate_state *s) {
|
||||
*/
|
||||
} while (--n);
|
||||
#endif
|
||||
s->slid = 1;
|
||||
}
|
||||
|
||||
/* ===========================================================================
|
||||
@@ -223,15 +225,19 @@ local unsigned read_buf(z_streamp strm, Bytef *buf, unsigned size) {
|
||||
|
||||
strm->avail_in -= len;
|
||||
|
||||
zmemcpy(buf, strm->next_in, len);
|
||||
if (strm->state->wrap == 1) {
|
||||
strm->adler = adler32(strm->adler, buf, len);
|
||||
}
|
||||
/* TODO(cavalcantii): verify if we can remove 'copy_with_crc', it is legacy
|
||||
* of the Intel optimizations dating back to 2015.
|
||||
*/
|
||||
#ifdef GZIP
|
||||
else if (strm->state->wrap == 2) {
|
||||
strm->adler = crc32(strm->adler, buf, len);
|
||||
}
|
||||
if (strm->state->wrap == 2)
|
||||
copy_with_crc(strm, buf, len);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
zmemcpy(buf, strm->next_in, len);
|
||||
if (strm->state->wrap == 1)
|
||||
strm->adler = adler32(strm->adler, buf, len);
|
||||
}
|
||||
strm->next_in += len;
|
||||
strm->total_in += len;
|
||||
|
||||
@@ -259,7 +265,14 @@ local void fill_window(deflate_state *s) {
|
||||
more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
|
||||
|
||||
/* Deal with !@#$% 64K limit: */
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127)
|
||||
#endif
|
||||
if (sizeof(int) <= 2) {
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
|
||||
more = wsize;
|
||||
|
||||
@@ -303,6 +316,20 @@ local void fill_window(deflate_state *s) {
|
||||
n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
|
||||
s->lookahead += n;
|
||||
|
||||
/* Initialize the hash value now that we have some input: */
|
||||
if (s->chromium_zlib_hash) {
|
||||
/* chromium hash reads 4 bytes */
|
||||
if (s->lookahead + s->insert > MIN_MATCH) {
|
||||
uInt str = s->strstart - s->insert;
|
||||
while (s->insert) {
|
||||
insert_string(s, str);
|
||||
str++;
|
||||
s->insert--;
|
||||
if (s->lookahead + s->insert <= MIN_MATCH)
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
/* Initialize the hash value now that we have some input: */
|
||||
if (s->lookahead + s->insert >= MIN_MATCH) {
|
||||
uInt str = s->strstart - s->insert;
|
||||
@@ -375,6 +402,8 @@ int ZEXPORT deflateInit_(z_streamp strm, int level, const char *version,
|
||||
/* To do: ignore strm->next_in if we use it as window */
|
||||
}
|
||||
|
||||
#define WINDOW_PADDING 8
|
||||
|
||||
/* ========================================================================= */
|
||||
int ZEXPORT deflateInit2_(z_streamp strm, int level, int method,
|
||||
int windowBits, int memLevel, int strategy,
|
||||
@@ -383,6 +412,15 @@ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method,
|
||||
int wrap = 1;
|
||||
static const char my_version[] = ZLIB_VERSION;
|
||||
|
||||
// Needed to activate optimized insert_string() that helps compression
|
||||
// for all wrapper formats (e.g. RAW, ZLIB, GZIP).
|
||||
// Feature detection is not triggered while using RAW mode (i.e. we never
|
||||
// call crc32() with a NULL buffer).
|
||||
#if defined(CRC32_ARMV8_CRC32) || defined(CRC32_SIMD_SSE42_PCLMUL) \
|
||||
|| defined(RISCV_RVV)
|
||||
cpu_check_features();
|
||||
#endif
|
||||
|
||||
if (version == Z_NULL || version[0] != my_version[0] ||
|
||||
stream_size != sizeof(z_stream)) {
|
||||
return Z_VERSION_ERROR;
|
||||
@@ -431,6 +469,7 @@ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method,
|
||||
if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */
|
||||
s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
|
||||
if (s == Z_NULL) return Z_MEM_ERROR;
|
||||
zmemzero(s, sizeof(deflate_state));
|
||||
strm->state = (struct internal_state FAR *)s;
|
||||
s->strm = strm;
|
||||
s->status = INIT_STATE; /* to pass state test in deflateReset() */
|
||||
@@ -441,12 +480,23 @@ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method,
|
||||
s->w_size = 1 << s->w_bits;
|
||||
s->w_mask = s->w_size - 1;
|
||||
|
||||
s->hash_bits = (uInt)memLevel + 7;
|
||||
s->chromium_zlib_hash = 1;
|
||||
#if defined(USE_ZLIB_RABIN_KARP_ROLLING_HASH)
|
||||
s->chromium_zlib_hash = 0;
|
||||
#endif
|
||||
|
||||
s->hash_bits = memLevel + 7;
|
||||
if (s->chromium_zlib_hash && s->hash_bits < 15) {
|
||||
s->hash_bits = 15;
|
||||
}
|
||||
|
||||
s->hash_size = 1 << s->hash_bits;
|
||||
s->hash_mask = s->hash_size - 1;
|
||||
s->hash_shift = ((s->hash_bits + MIN_MATCH-1) / MIN_MATCH);
|
||||
|
||||
s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
|
||||
s->window = (Bytef *) ZALLOC(strm,
|
||||
s->w_size + WINDOW_PADDING,
|
||||
2*sizeof(Byte));
|
||||
s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
|
||||
s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
|
||||
|
||||
@@ -492,8 +542,11 @@ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method,
|
||||
* the compressed data for a dynamic block also cannot overwrite the
|
||||
* symbols from which it is being constructed.
|
||||
*/
|
||||
|
||||
s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, LIT_BUFS);
|
||||
#ifdef LIT_MEM
|
||||
s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 5);
|
||||
#else
|
||||
s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 4);
|
||||
#endif
|
||||
s->pending_buf_size = (ulg)s->lit_bufsize * 4;
|
||||
|
||||
if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
|
||||
@@ -503,6 +556,13 @@ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method,
|
||||
deflateEnd (strm);
|
||||
return Z_MEM_ERROR;
|
||||
}
|
||||
/* Avoid use of unitialized values in the window, see crbug.com/1137613 and
|
||||
* crbug.com/1144420 */
|
||||
zmemzero(s->window, (s->w_size + WINDOW_PADDING) * (2 * sizeof(Byte)));
|
||||
/* Avoid use of uninitialized value, see:
|
||||
* https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11360
|
||||
*/
|
||||
zmemzero(s->prev, s->w_size * sizeof(Pos));
|
||||
#ifdef LIT_MEM
|
||||
s->d_buf = (ushf *)(s->pending_buf + (s->lit_bufsize << 1));
|
||||
s->l_buf = s->pending_buf + (s->lit_bufsize << 2);
|
||||
@@ -520,6 +580,13 @@ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method,
|
||||
s->strategy = strategy;
|
||||
s->method = (Byte)method;
|
||||
|
||||
#if defined(QAT_COMPRESSION_ENABLED)
|
||||
s->qat_s = NULL;
|
||||
if (s->level && qat_deflate_init() == Z_OK) {
|
||||
s->qat_s = qat_deflate_state_init(s->level, s->wrap);
|
||||
}
|
||||
#endif
|
||||
|
||||
return deflateReset(strm);
|
||||
}
|
||||
|
||||
@@ -589,11 +656,7 @@ int ZEXPORT deflateSetDictionary(z_streamp strm, const Bytef *dictionary,
|
||||
str = s->strstart;
|
||||
n = s->lookahead - (MIN_MATCH-1);
|
||||
do {
|
||||
UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
|
||||
#ifndef FASTEST
|
||||
s->prev[str & s->w_mask] = s->head[s->ins_h];
|
||||
#endif
|
||||
s->head[s->ins_h] = (Pos)str;
|
||||
insert_string(s, str);
|
||||
str++;
|
||||
} while (--n);
|
||||
s->strstart = str;
|
||||
@@ -712,10 +775,23 @@ int ZEXPORT deflateSetHeader(z_streamp strm, gz_headerp head) {
|
||||
/* ========================================================================= */
|
||||
int ZEXPORT deflatePending(z_streamp strm, unsigned *pending, int *bits) {
|
||||
if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
|
||||
if (pending != Z_NULL)
|
||||
*pending = strm->state->pending;
|
||||
if (bits != Z_NULL)
|
||||
*bits = strm->state->bi_valid;
|
||||
if (pending != Z_NULL) {
|
||||
*pending = (unsigned)strm->state->pending;
|
||||
if (*pending != strm->state->pending) {
|
||||
*pending = (unsigned)-1;
|
||||
return Z_BUF_ERROR;
|
||||
}
|
||||
}
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
int ZEXPORT deflateUsed(z_streamp strm, int *bits) {
|
||||
if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
|
||||
if (bits != Z_NULL)
|
||||
*bits = strm->state->bi_used;
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
@@ -739,7 +815,11 @@ int ZEXPORT deflatePrime(z_streamp strm, int bits, int value) {
|
||||
put = Buf_size - s->bi_valid;
|
||||
if (put > bits)
|
||||
put = bits;
|
||||
#if defined(DEFLATE_CHUNK_WRITE_64LE)
|
||||
s->bi_buf |= (uint64_t)((value & ((1ULL << put) - 1)) << s->bi_valid);
|
||||
#else
|
||||
s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid);
|
||||
#endif /* DEFLATE_CHUNK_WRITE_64LE */
|
||||
s->bi_valid += put;
|
||||
_tr_flush_bits(s);
|
||||
value >>= put;
|
||||
@@ -831,28 +911,34 @@ int ZEXPORT deflateTune(z_streamp strm, int good_length, int max_lazy,
|
||||
*
|
||||
* Shifts are used to approximate divisions, for speed.
|
||||
*/
|
||||
uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen) {
|
||||
z_size_t ZEXPORT deflateBound_z(z_streamp strm, z_size_t sourceLen) {
|
||||
deflate_state *s;
|
||||
uLong fixedlen, storelen, wraplen;
|
||||
z_size_t fixedlen, storelen, wraplen, bound;
|
||||
|
||||
/* upper bound for fixed blocks with 9-bit literals and length 255
|
||||
(memLevel == 2, which is the lowest that may not use stored blocks) --
|
||||
~13% overhead plus a small constant */
|
||||
fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) +
|
||||
(sourceLen >> 9) + 4;
|
||||
if (fixedlen < sourceLen)
|
||||
fixedlen = (z_size_t)-1;
|
||||
|
||||
/* upper bound for stored blocks with length 127 (memLevel == 1) --
|
||||
~4% overhead plus a small constant */
|
||||
storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) +
|
||||
(sourceLen >> 11) + 7;
|
||||
if (storelen < sourceLen)
|
||||
storelen = (z_size_t)-1;
|
||||
|
||||
/* if can't get parameters, return larger bound plus a zlib wrapper */
|
||||
if (deflateStateCheck(strm))
|
||||
return (fixedlen > storelen ? fixedlen : storelen) + 6;
|
||||
/* if can't get parameters, return larger bound plus a wrapper */
|
||||
if (deflateStateCheck(strm)) {
|
||||
bound = fixedlen > storelen ? fixedlen : storelen;
|
||||
return bound + 18 < bound ? (z_size_t)-1 : bound + 18;
|
||||
}
|
||||
|
||||
/* compute wrapper length */
|
||||
s = strm->state;
|
||||
switch (s->wrap) {
|
||||
switch (s->wrap < 0 ? -s->wrap : s->wrap) {
|
||||
case 0: /* raw deflate */
|
||||
wraplen = 0;
|
||||
break;
|
||||
@@ -882,18 +968,33 @@ uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen) {
|
||||
break;
|
||||
#endif
|
||||
default: /* for compiler happiness */
|
||||
wraplen = 6;
|
||||
wraplen = 18;
|
||||
}
|
||||
|
||||
/* With Chromium's hashing, s->hash_bits may not correspond to the
|
||||
memLevel, making the computations below incorrect. Return the
|
||||
conservative bound. */
|
||||
if (s->chromium_zlib_hash) {
|
||||
bound = fixedlen > storelen ? fixedlen : storelen;
|
||||
return bound + wraplen < bound ? (z_size_t)-1 : bound + wraplen;
|
||||
}
|
||||
|
||||
/* if not default parameters, return one of the conservative bounds */
|
||||
if (s->w_bits != 15 || s->hash_bits != 8 + 7)
|
||||
return (s->w_bits <= s->hash_bits && s->level ? fixedlen : storelen) +
|
||||
wraplen;
|
||||
if (s->w_bits != 15 || s->hash_bits != 8 + 7) {
|
||||
bound = s->w_bits <= s->hash_bits && s->level ? fixedlen :
|
||||
storelen;
|
||||
return bound + wraplen < bound ? (z_size_t)-1 : bound + wraplen;
|
||||
}
|
||||
|
||||
/* default settings: return tight bound for that case -- ~0.03% overhead
|
||||
plus a small constant */
|
||||
return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
|
||||
(sourceLen >> 25) + 13 - 6 + wraplen;
|
||||
bound = sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
|
||||
(sourceLen >> 25) + 13 - 6 + wraplen;
|
||||
return bound < sourceLen ? (z_size_t)-1 : bound;
|
||||
}
|
||||
uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen) {
|
||||
z_size_t bound = deflateBound_z(strm, sourceLen);
|
||||
return (uLong)bound != bound ? (uLong)-1 : (uLong)bound;
|
||||
}
|
||||
|
||||
/* =========================================================================
|
||||
@@ -916,9 +1017,15 @@ local void flush_pending(z_streamp strm) {
|
||||
unsigned len;
|
||||
deflate_state *s = strm->state;
|
||||
|
||||
#if defined(QAT_COMPRESSION_ENABLED)
|
||||
if (s->qat_s) {
|
||||
qat_flush_pending(s);
|
||||
}
|
||||
#endif
|
||||
|
||||
_tr_flush_bits(s);
|
||||
len = s->pending;
|
||||
if (len > strm->avail_out) len = strm->avail_out;
|
||||
len = s->pending > strm->avail_out ? strm->avail_out :
|
||||
(unsigned)s->pending;
|
||||
if (len == 0) return;
|
||||
|
||||
zmemcpy(strm->next_out, s->pending_out, len);
|
||||
@@ -938,8 +1045,8 @@ local void flush_pending(z_streamp strm) {
|
||||
#define HCRC_UPDATE(beg) \
|
||||
do { \
|
||||
if (s->gzhead->hcrc && s->pending > (beg)) \
|
||||
strm->adler = crc32(strm->adler, s->pending_buf + (beg), \
|
||||
s->pending - (beg)); \
|
||||
strm->adler = crc32_z(strm->adler, s->pending_buf + (beg), \
|
||||
s->pending - (beg)); \
|
||||
} while (0)
|
||||
|
||||
/* ========================================================================= */
|
||||
@@ -1030,7 +1137,7 @@ int ZEXPORT deflate(z_streamp strm, int flush) {
|
||||
#ifdef GZIP
|
||||
if (s->status == GZIP_STATE) {
|
||||
/* gzip header */
|
||||
strm->adler = crc32(0L, Z_NULL, 0);
|
||||
crc_reset(s);
|
||||
put_byte(s, 31);
|
||||
put_byte(s, 139);
|
||||
put_byte(s, 8);
|
||||
@@ -1073,8 +1180,8 @@ int ZEXPORT deflate(z_streamp strm, int flush) {
|
||||
put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
|
||||
}
|
||||
if (s->gzhead->hcrc)
|
||||
strm->adler = crc32(strm->adler, s->pending_buf,
|
||||
s->pending);
|
||||
strm->adler = crc32_z(strm->adler, s->pending_buf,
|
||||
s->pending);
|
||||
s->gzindex = 0;
|
||||
s->status = EXTRA_STATE;
|
||||
}
|
||||
@@ -1082,9 +1189,9 @@ int ZEXPORT deflate(z_streamp strm, int flush) {
|
||||
if (s->status == EXTRA_STATE) {
|
||||
if (s->gzhead->extra != Z_NULL) {
|
||||
ulg beg = s->pending; /* start of bytes to update crc */
|
||||
uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex;
|
||||
ulg left = (s->gzhead->extra_len & 0xffff) - s->gzindex;
|
||||
while (s->pending + left > s->pending_buf_size) {
|
||||
uInt copy = s->pending_buf_size - s->pending;
|
||||
ulg copy = s->pending_buf_size - s->pending;
|
||||
zmemcpy(s->pending_buf + s->pending,
|
||||
s->gzhead->extra + s->gzindex, copy);
|
||||
s->pending = s->pending_buf_size;
|
||||
@@ -1231,6 +1338,7 @@ int ZEXPORT deflate(z_streamp strm, int flush) {
|
||||
/* Write the trailer */
|
||||
#ifdef GZIP
|
||||
if (s->wrap == 2) {
|
||||
crc_finalize(s);
|
||||
put_byte(s, (Byte)(strm->adler & 0xff));
|
||||
put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
|
||||
put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
|
||||
@@ -1268,6 +1376,12 @@ int ZEXPORT deflateEnd(z_streamp strm) {
|
||||
TRY_FREE(strm, strm->state->prev);
|
||||
TRY_FREE(strm, strm->state->window);
|
||||
|
||||
#if defined(QAT_COMPRESSION_ENABLED)
|
||||
if (strm->state->qat_s) {
|
||||
qat_deflate_state_free(strm->state);
|
||||
}
|
||||
#endif
|
||||
|
||||
ZFREE(strm, strm->state);
|
||||
strm->state = Z_NULL;
|
||||
|
||||
@@ -1295,18 +1409,25 @@ int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) {
|
||||
|
||||
ss = source->state;
|
||||
|
||||
zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
|
||||
zmemcpy(dest, source, sizeof(z_stream));
|
||||
|
||||
ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
|
||||
if (ds == Z_NULL) return Z_MEM_ERROR;
|
||||
zmemzero(ds, sizeof(deflate_state));
|
||||
dest->state = (struct internal_state FAR *) ds;
|
||||
zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state));
|
||||
zmemcpy(ds, ss, sizeof(deflate_state));
|
||||
ds->strm = dest;
|
||||
|
||||
ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
|
||||
ds->window = (Bytef *) ZALLOC(dest,
|
||||
ds->w_size + WINDOW_PADDING,
|
||||
2*sizeof(Byte));
|
||||
ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
|
||||
ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
|
||||
ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, LIT_BUFS);
|
||||
#ifdef LIT_MEM
|
||||
ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 5);
|
||||
#else
|
||||
ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 4);
|
||||
#endif
|
||||
|
||||
if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
|
||||
ds->pending_buf == Z_NULL) {
|
||||
@@ -1314,23 +1435,36 @@ int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) {
|
||||
return Z_MEM_ERROR;
|
||||
}
|
||||
/* following zmemcpy do not work for 16-bit MSDOS */
|
||||
zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
|
||||
zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos));
|
||||
zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos));
|
||||
zmemcpy(ds->pending_buf, ss->pending_buf, ds->lit_bufsize * LIT_BUFS);
|
||||
zmemcpy(ds->window, ss->window, ss->high_water);
|
||||
zmemcpy(ds->prev, ss->prev,
|
||||
(ss->slid || ss->strstart - ss->insert > ds->w_size ? ds->w_size :
|
||||
ss->strstart - ss->insert) * sizeof(Pos));
|
||||
zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
|
||||
|
||||
ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
|
||||
zmemcpy(ds->pending_out, ss->pending_out, ss->pending);
|
||||
#ifdef LIT_MEM
|
||||
ds->d_buf = (ushf *)(ds->pending_buf + (ds->lit_bufsize << 1));
|
||||
ds->l_buf = ds->pending_buf + (ds->lit_bufsize << 2);
|
||||
zmemcpy(ds->d_buf, ss->d_buf, ss->sym_next * sizeof(ush));
|
||||
zmemcpy(ds->l_buf, ss->l_buf, ss->sym_next);
|
||||
#else
|
||||
ds->sym_buf = ds->pending_buf + ds->lit_bufsize;
|
||||
zmemcpy(ds->sym_buf, ss->sym_buf, ss->sym_next);
|
||||
#endif
|
||||
|
||||
ds->l_desc.dyn_tree = ds->dyn_ltree;
|
||||
ds->d_desc.dyn_tree = ds->dyn_dtree;
|
||||
ds->bl_desc.dyn_tree = ds->bl_tree;
|
||||
|
||||
#if defined(QAT_COMPRESSION_ENABLED)
|
||||
if(ss->qat_s) {
|
||||
ds->qat_s = qat_deflate_copy(ss);
|
||||
if (!ds->qat_s)
|
||||
return Z_MEM_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
return Z_OK;
|
||||
#endif /* MAXSEG_64K */
|
||||
}
|
||||
@@ -1347,9 +1481,9 @@ int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) {
|
||||
*/
|
||||
local uInt longest_match(deflate_state *s, IPos cur_match) {
|
||||
unsigned chain_length = s->max_chain_length;/* max hash chain length */
|
||||
register Bytef *scan = s->window + s->strstart; /* current string */
|
||||
register Bytef *match; /* matched string */
|
||||
register int len; /* length of current match */
|
||||
Bytef *scan = s->window + s->strstart; /* current string */
|
||||
Bytef *match; /* matched string */
|
||||
int len; /* length of current match */
|
||||
int best_len = (int)s->prev_length; /* best match length so far */
|
||||
int nice_match = s->nice_match; /* stop if match long enough */
|
||||
IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
|
||||
@@ -1360,17 +1494,23 @@ local uInt longest_match(deflate_state *s, IPos cur_match) {
|
||||
Posf *prev = s->prev;
|
||||
uInt wmask = s->w_mask;
|
||||
|
||||
#ifdef UNALIGNED_OK
|
||||
#if defined(DEFLATE_COMPARE256_64LE)
|
||||
/* Quickly reject non-matches with the 2-byte prefilter
|
||||
* (scan_start/scan_end); candidates that pass are extended 8 bytes at a
|
||||
* time with compare256(). */
|
||||
uInt scan_start = read16(scan);
|
||||
uInt scan_end = read16(scan + best_len - 1);
|
||||
#elif defined(UNALIGNED_OK)
|
||||
/* Compare two bytes at a time. Note: this is not always beneficial.
|
||||
* Try with and without -DUNALIGNED_OK to check.
|
||||
*/
|
||||
register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
|
||||
register ush scan_start = *(ushf*)scan;
|
||||
register ush scan_end = *(ushf*)(scan + best_len - 1);
|
||||
Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
|
||||
ush scan_start = *(ushf*)scan;
|
||||
ush scan_end = *(ushf*)(scan + best_len - 1);
|
||||
#else
|
||||
register Bytef *strend = s->window + s->strstart + MAX_MATCH;
|
||||
register Byte scan_end1 = scan[best_len - 1];
|
||||
register Byte scan_end = scan[best_len];
|
||||
Bytef *strend = s->window + s->strstart + MAX_MATCH;
|
||||
Byte scan_end1 = scan[best_len - 1];
|
||||
Byte scan_end = scan[best_len];
|
||||
#endif
|
||||
|
||||
/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
|
||||
@@ -1402,7 +1542,13 @@ local uInt longest_match(deflate_state *s, IPos cur_match) {
|
||||
* However the length of the match is limited to the lookahead, so
|
||||
* the output of deflate is not affected by the uninitialized values.
|
||||
*/
|
||||
#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
|
||||
#if defined(DEFLATE_COMPARE256_64LE)
|
||||
if (read16(match + best_len - 1) != scan_end ||
|
||||
read16(match) != scan_start) continue;
|
||||
/* scan_start matched, so bytes 0..1 are equal; compare the remaining
|
||||
* up to 256 bytes so the length can still reach MAX_MATCH (258). */
|
||||
len = 2 + compare256(scan + 2, match + 2);
|
||||
#elif (defined(UNALIGNED_OK) && MAX_MATCH == 258)
|
||||
/* This code assumes sizeof(unsigned short) == 2. Do not use
|
||||
* UNALIGNED_OK if your compiler uses a different size.
|
||||
*/
|
||||
@@ -1418,7 +1564,16 @@ local uInt longest_match(deflate_state *s, IPos cur_match) {
|
||||
* necessary to put more guard bytes at the end of the window, or
|
||||
* to check more often for insufficient lookahead.
|
||||
*/
|
||||
Assert(scan[2] == match[2], "scan[2]?");
|
||||
if (!s->chromium_zlib_hash) {
|
||||
Assert(scan[2] == match[2], "scan[2]?");
|
||||
} else {
|
||||
/* When using CRC hashing, scan[2] and match[2] may mismatch, but in
|
||||
* that case at least one of the other hashed bytes will mismatch
|
||||
* also. Bytes 0 and 1 were already checked above, and we know there
|
||||
* are at least four bytes to check otherwise the mismatch would have
|
||||
* been found by the scan_end comparison above, so: */
|
||||
Assert(scan[2] == match[2] || scan[3] != match[3], "scan[2]??");
|
||||
}
|
||||
scan++, match++;
|
||||
do {
|
||||
} while (*(ushf*)(scan += 2) == *(ushf*)(match += 2) &&
|
||||
@@ -1429,7 +1584,7 @@ local uInt longest_match(deflate_state *s, IPos cur_match) {
|
||||
/* The funny "do {}" generates better code on most compilers */
|
||||
|
||||
/* Here, scan <= window + strstart + 257 */
|
||||
Assert(scan <= s->window + (unsigned)(s->window_size - 1),
|
||||
Assert(scan <= s->window+(unsigned)(s->window_size - 1),
|
||||
"wild scan");
|
||||
if (*scan == *match) scan++;
|
||||
|
||||
@@ -1438,10 +1593,10 @@ local uInt longest_match(deflate_state *s, IPos cur_match) {
|
||||
|
||||
#else /* UNALIGNED_OK */
|
||||
|
||||
if (match[best_len] != scan_end ||
|
||||
if (match[best_len] != scan_end ||
|
||||
match[best_len - 1] != scan_end1 ||
|
||||
*match != *scan ||
|
||||
*++match != scan[1]) continue;
|
||||
*match != *scan ||
|
||||
*++match != scan[1]) continue;
|
||||
|
||||
/* The check at best_len - 1 can be removed because it will be made
|
||||
* again later. (This heuristic is not always a win.)
|
||||
@@ -1450,7 +1605,16 @@ local uInt longest_match(deflate_state *s, IPos cur_match) {
|
||||
* the hash keys are equal and that HASH_BITS >= 8.
|
||||
*/
|
||||
scan += 2, match++;
|
||||
Assert(*scan == *match, "match[2]?");
|
||||
if (!s->chromium_zlib_hash) {
|
||||
Assert(*scan == *match, "match[2]?");
|
||||
} else {
|
||||
/* When using CRC hashing, scan[2] and match[2] may mismatch, but in
|
||||
* that case at least one of the other hashed bytes will mismatch
|
||||
* also. Bytes 0 and 1 were already checked above, and we know there
|
||||
* are at least four bytes to check otherwise the mismatch would have
|
||||
* been found by the scan_end comparison above, so: */
|
||||
Assert(*scan == *match || scan[1] != match[1], "match[2]??");
|
||||
}
|
||||
|
||||
/* We check for insufficient lookahead only every 8th comparison;
|
||||
* the 256th check will be made at strstart + 258.
|
||||
@@ -1474,7 +1638,9 @@ local uInt longest_match(deflate_state *s, IPos cur_match) {
|
||||
s->match_start = cur_match;
|
||||
best_len = len;
|
||||
if (len >= nice_match) break;
|
||||
#ifdef UNALIGNED_OK
|
||||
#if defined(DEFLATE_COMPARE256_64LE)
|
||||
scan_end = read16(scan + best_len - 1);
|
||||
#elif defined(UNALIGNED_OK)
|
||||
scan_end = *(ushf*)(scan + best_len - 1);
|
||||
#else
|
||||
scan_end1 = scan[best_len - 1];
|
||||
@@ -1494,10 +1660,10 @@ local uInt longest_match(deflate_state *s, IPos cur_match) {
|
||||
* Optimized version for FASTEST only
|
||||
*/
|
||||
local uInt longest_match(deflate_state *s, IPos cur_match) {
|
||||
register Bytef *scan = s->window + s->strstart; /* current string */
|
||||
register Bytef *match; /* matched string */
|
||||
register int len; /* length of current match */
|
||||
register Bytef *strend = s->window + s->strstart + MAX_MATCH;
|
||||
Bytef *scan = s->window + s->strstart; /* current string */
|
||||
Bytef *match; /* matched string */
|
||||
int len; /* length of current match */
|
||||
Bytef *strend = s->window + s->strstart + MAX_MATCH;
|
||||
|
||||
/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
|
||||
* It is easy to get rid of this optimization if necessary.
|
||||
@@ -1557,7 +1723,7 @@ local uInt longest_match(deflate_state *s, IPos cur_match) {
|
||||
local void check_match(deflate_state *s, IPos start, IPos match, int length) {
|
||||
/* check that the match is indeed a match */
|
||||
Bytef *back = s->window + (int)match, *here = s->window + start;
|
||||
IPos len = length;
|
||||
IPos len = (IPos)length;
|
||||
if (match == (IPos)-1) {
|
||||
/* match starts one byte before the current window -- just compare the
|
||||
subsequent length-1 bytes */
|
||||
@@ -1629,13 +1795,14 @@ local block_state deflate_stored(deflate_state *s, int flush) {
|
||||
* this is 32K. This can be as small as 507 bytes for memLevel == 1. For
|
||||
* large input and output buffers, the stored block size will be larger.
|
||||
*/
|
||||
unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size);
|
||||
unsigned min_block = (unsigned)(MIN(s->pending_buf_size - 5, s->w_size));
|
||||
|
||||
/* Copy as many min_block or larger stored blocks directly to next_out as
|
||||
* possible. If flushing, copy the remaining available input to next_out as
|
||||
* stored blocks, if there is enough space.
|
||||
*/
|
||||
unsigned len, left, have, last = 0;
|
||||
int last = 0;
|
||||
unsigned len, left, have;
|
||||
unsigned used = s->strm->avail_in;
|
||||
do {
|
||||
/* Set len to the maximum size block that we can copy directly with the
|
||||
@@ -1643,12 +1810,12 @@ local block_state deflate_stored(deflate_state *s, int flush) {
|
||||
* would be copied from what's left in the window.
|
||||
*/
|
||||
len = MAX_STORED; /* maximum deflate stored block length */
|
||||
have = (s->bi_valid + 42) >> 3; /* number of header bytes */
|
||||
have = ((unsigned)s->bi_valid + 42) >> 3; /* bytes in header */
|
||||
if (s->strm->avail_out < have) /* need room for header */
|
||||
break;
|
||||
/* maximum stored block length that will fit in avail_out: */
|
||||
have = s->strm->avail_out - have;
|
||||
left = s->strstart - s->block_start; /* bytes left in window */
|
||||
left = (unsigned)(s->strstart - s->block_start); /* window bytes */
|
||||
if (len > (ulg)left + s->strm->avail_in)
|
||||
len = left + s->strm->avail_in; /* limit len to the input */
|
||||
if (len > have)
|
||||
@@ -1671,10 +1838,10 @@ local block_state deflate_stored(deflate_state *s, int flush) {
|
||||
_tr_stored_block(s, (char *)0, 0L, last);
|
||||
|
||||
/* Replace the lengths in the dummy stored block with len. */
|
||||
s->pending_buf[s->pending - 4] = len;
|
||||
s->pending_buf[s->pending - 3] = len >> 8;
|
||||
s->pending_buf[s->pending - 2] = ~len;
|
||||
s->pending_buf[s->pending - 1] = ~len >> 8;
|
||||
s->pending_buf[s->pending - 4] = (Bytef)len;
|
||||
s->pending_buf[s->pending - 3] = (Bytef)(len >> 8);
|
||||
s->pending_buf[s->pending - 2] = (Bytef)~len;
|
||||
s->pending_buf[s->pending - 1] = (Bytef)(~len >> 8);
|
||||
|
||||
/* Write the stored block header bytes. */
|
||||
flush_pending(s->strm);
|
||||
@@ -1745,8 +1912,10 @@ local block_state deflate_stored(deflate_state *s, int flush) {
|
||||
s->high_water = s->strstart;
|
||||
|
||||
/* If the last block was written to next_out, then done. */
|
||||
if (last)
|
||||
if (last) {
|
||||
s->bi_used = 8;
|
||||
return finish_done;
|
||||
}
|
||||
|
||||
/* If flushing and all input has been consumed, then done. */
|
||||
if (flush != Z_NO_FLUSH && flush != Z_FINISH &&
|
||||
@@ -1754,7 +1923,7 @@ local block_state deflate_stored(deflate_state *s, int flush) {
|
||||
return block_done;
|
||||
|
||||
/* Fill the window with any remaining input. */
|
||||
have = s->window_size - s->strstart;
|
||||
have = (unsigned)(s->window_size - s->strstart);
|
||||
if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) {
|
||||
/* Slide the window down. */
|
||||
s->block_start -= s->w_size;
|
||||
@@ -1781,11 +1950,11 @@ local block_state deflate_stored(deflate_state *s, int flush) {
|
||||
* have enough input for a worthy block, or if flushing and there is enough
|
||||
* room for the remaining input as a stored block in the pending buffer.
|
||||
*/
|
||||
have = (s->bi_valid + 42) >> 3; /* number of header bytes */
|
||||
have = ((unsigned)s->bi_valid + 42) >> 3; /* bytes in header */
|
||||
/* maximum stored block length that will fit in pending: */
|
||||
have = MIN(s->pending_buf_size - have, MAX_STORED);
|
||||
have = (unsigned)MIN(s->pending_buf_size - have, MAX_STORED);
|
||||
min_block = MIN(have, s->w_size);
|
||||
left = s->strstart - s->block_start;
|
||||
left = (unsigned)(s->strstart - s->block_start);
|
||||
if (left >= min_block ||
|
||||
((left || flush == Z_FINISH) && flush != Z_NO_FLUSH &&
|
||||
s->strm->avail_in == 0 && left <= have)) {
|
||||
@@ -1798,6 +1967,8 @@ local block_state deflate_stored(deflate_state *s, int flush) {
|
||||
}
|
||||
|
||||
/* We've done all we can with the available input and output. */
|
||||
if (last)
|
||||
s->bi_used = 8;
|
||||
return last ? finish_started : need_more;
|
||||
}
|
||||
|
||||
@@ -1812,6 +1983,24 @@ local block_state deflate_fast(deflate_state *s, int flush) {
|
||||
IPos hash_head; /* head of the hash chain */
|
||||
int bflush; /* set if current block must be flushed */
|
||||
|
||||
#if defined(QAT_COMPRESSION_ENABLED)
|
||||
if (s->qat_s) {
|
||||
qat_block_state qat_block = qat_deflate_step(s, flush);
|
||||
switch (qat_block) {
|
||||
case qat_block_need_more:
|
||||
return need_more;
|
||||
case qat_block_done:
|
||||
return block_done;
|
||||
case qat_block_finish_started:
|
||||
return finish_started;
|
||||
case qat_block_finish_done:
|
||||
return finish_done;
|
||||
case qat_failure:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
/* Make sure that we always have enough lookahead, except
|
||||
* at the end of the input file. We need MAX_MATCH bytes
|
||||
@@ -1831,7 +2020,7 @@ local block_state deflate_fast(deflate_state *s, int flush) {
|
||||
*/
|
||||
hash_head = NIL;
|
||||
if (s->lookahead >= MIN_MATCH) {
|
||||
INSERT_STRING(s, s->strstart, hash_head);
|
||||
hash_head = insert_string(s, s->strstart);
|
||||
}
|
||||
|
||||
/* Find the longest match, discarding those <= prev_length.
|
||||
@@ -1846,7 +2035,7 @@ local block_state deflate_fast(deflate_state *s, int flush) {
|
||||
/* longest_match() sets match_start */
|
||||
}
|
||||
if (s->match_length >= MIN_MATCH) {
|
||||
check_match(s, s->strstart, s->match_start, s->match_length);
|
||||
check_match(s, s->strstart, s->match_start, (int)s->match_length);
|
||||
|
||||
_tr_tally_dist(s, s->strstart - s->match_start,
|
||||
s->match_length - MIN_MATCH, bflush);
|
||||
@@ -1862,7 +2051,7 @@ local block_state deflate_fast(deflate_state *s, int flush) {
|
||||
s->match_length--; /* string at strstart already in table */
|
||||
do {
|
||||
s->strstart++;
|
||||
INSERT_STRING(s, s->strstart, hash_head);
|
||||
hash_head = insert_string(s, s->strstart);
|
||||
/* strstart never exceeds WSIZE-MAX_MATCH, so there are
|
||||
* always MIN_MATCH bytes ahead.
|
||||
*/
|
||||
@@ -1873,14 +2062,17 @@ local block_state deflate_fast(deflate_state *s, int flush) {
|
||||
{
|
||||
s->strstart += s->match_length;
|
||||
s->match_length = 0;
|
||||
s->ins_h = s->window[s->strstart];
|
||||
UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]);
|
||||
|
||||
if (!s->chromium_zlib_hash) {
|
||||
s->ins_h = s->window[s->strstart];
|
||||
UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]);
|
||||
#if MIN_MATCH != 3
|
||||
Call UPDATE_HASH() MIN_MATCH-3 more times
|
||||
Call UPDATE_HASH() MIN_MATCH-3 more times
|
||||
#endif
|
||||
/* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
|
||||
* matter since it will be recomputed at next deflate call.
|
||||
*/
|
||||
/* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
|
||||
* matter since it will be recomputed at next deflate call.
|
||||
*/
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* No match, output a literal byte */
|
||||
@@ -1911,6 +2103,24 @@ local block_state deflate_slow(deflate_state *s, int flush) {
|
||||
IPos hash_head; /* head of hash chain */
|
||||
int bflush; /* set if current block must be flushed */
|
||||
|
||||
#if defined(QAT_COMPRESSION_ENABLED)
|
||||
if (s->qat_s) {
|
||||
qat_block_state qat_block = qat_deflate_step(s, flush);
|
||||
switch (qat_block) {
|
||||
case qat_block_need_more:
|
||||
return need_more;
|
||||
case qat_block_done:
|
||||
return block_done;
|
||||
case qat_block_finish_started:
|
||||
return finish_started;
|
||||
case qat_block_finish_done:
|
||||
return finish_done;
|
||||
case qat_failure:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Process the input block. */
|
||||
for (;;) {
|
||||
/* Make sure that we always have enough lookahead, except
|
||||
@@ -1931,7 +2141,7 @@ local block_state deflate_slow(deflate_state *s, int flush) {
|
||||
*/
|
||||
hash_head = NIL;
|
||||
if (s->lookahead >= MIN_MATCH) {
|
||||
INSERT_STRING(s, s->strstart, hash_head);
|
||||
hash_head = insert_string(s, s->strstart);
|
||||
}
|
||||
|
||||
/* Find the longest match, discarding those <= prev_length.
|
||||
@@ -1968,7 +2178,7 @@ local block_state deflate_slow(deflate_state *s, int flush) {
|
||||
uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
|
||||
/* Do not insert strings in hash table beyond this. */
|
||||
|
||||
check_match(s, s->strstart - 1, s->prev_match, s->prev_length);
|
||||
check_match(s, s->strstart - 1, s->prev_match, (int)s->prev_length);
|
||||
|
||||
_tr_tally_dist(s, s->strstart - 1 - s->prev_match,
|
||||
s->prev_length - MIN_MATCH, bflush);
|
||||
@@ -1982,7 +2192,7 @@ local block_state deflate_slow(deflate_state *s, int flush) {
|
||||
s->prev_length -= 2;
|
||||
do {
|
||||
if (++s->strstart <= max_insert) {
|
||||
INSERT_STRING(s, s->strstart, hash_head);
|
||||
hash_head = insert_string(s, s->strstart);
|
||||
}
|
||||
} while (--s->prev_length != 0);
|
||||
s->match_available = 0;
|
||||
@@ -2076,7 +2286,7 @@ local block_state deflate_rle(deflate_state *s, int flush) {
|
||||
|
||||
/* Emit match if have run of MIN_MATCH or longer, else emit literal */
|
||||
if (s->match_length >= MIN_MATCH) {
|
||||
check_match(s, s->strstart, s->strstart - 1, s->match_length);
|
||||
check_match(s, s->strstart, s->strstart - 1, (int)s->match_length);
|
||||
|
||||
_tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);
|
||||
|
||||
|
||||
+42
-6
@@ -1,5 +1,5 @@
|
||||
/* deflate.h -- internal compression state
|
||||
* Copyright (C) 1995-2024 Jean-loup Gailly
|
||||
* Copyright (C) 1995-2026 Jean-loup Gailly
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
#ifndef DEFLATE_H
|
||||
#define DEFLATE_H
|
||||
|
||||
#if defined(DEFLATE_CHUNK_WRITE_64LE)
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "zutil.h"
|
||||
|
||||
/* define NO_GZIP when compiling if you want to disable gzip header and
|
||||
@@ -25,7 +29,7 @@
|
||||
|
||||
/* define LIT_MEM to slightly increase the speed of deflate (order 1% to 2%) at
|
||||
the cost of a larger memory footprint */
|
||||
/* #define LIT_MEM */
|
||||
#define LIT_MEM
|
||||
|
||||
/* ===========================================================================
|
||||
* Internal compression state.
|
||||
@@ -52,7 +56,11 @@
|
||||
#define MAX_BITS 15
|
||||
/* All codes must not exceed MAX_BITS bits */
|
||||
|
||||
#if defined(DEFLATE_CHUNK_WRITE_64LE)
|
||||
#define Buf_size 64
|
||||
#else
|
||||
#define Buf_size 16
|
||||
#endif
|
||||
/* size of bit buffer in bi_buf */
|
||||
|
||||
#define INIT_STATE 42 /* zlib header -> BUSY_STATE */
|
||||
@@ -113,8 +121,8 @@ typedef struct internal_state {
|
||||
ulg gzindex; /* where in extra, name, or comment */
|
||||
Byte method; /* can only be DEFLATED */
|
||||
int last_flush; /* value of flush param for previous deflate call */
|
||||
|
||||
/* used by deflate.c: */
|
||||
unsigned crc0[4 * 5];
|
||||
/* used by deflate.c: */
|
||||
|
||||
uInt w_size; /* LZ77 window size (32K by default) */
|
||||
uInt w_bits; /* log2(w_size) (8..16) */
|
||||
@@ -222,11 +230,9 @@ typedef struct internal_state {
|
||||
*/
|
||||
|
||||
#ifdef LIT_MEM
|
||||
# define LIT_BUFS 5
|
||||
ushf *d_buf; /* buffer for distances */
|
||||
uchf *l_buf; /* buffer for literals/lengths */
|
||||
#else
|
||||
# define LIT_BUFS 4
|
||||
uchf *sym_buf; /* buffer for distances and literals/lengths */
|
||||
#endif
|
||||
|
||||
@@ -263,7 +269,11 @@ typedef struct internal_state {
|
||||
ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
|
||||
#endif
|
||||
|
||||
#if defined(DEFLATE_CHUNK_WRITE_64LE)
|
||||
uint64_t bi_buf;
|
||||
#else
|
||||
ush bi_buf;
|
||||
#endif
|
||||
/* Output buffer. bits are inserted starting at the bottom (least
|
||||
* significant bits).
|
||||
*/
|
||||
@@ -271,6 +281,9 @@ typedef struct internal_state {
|
||||
/* Number of valid bits in bi_buf. All bits above the last valid bit
|
||||
* are always zero.
|
||||
*/
|
||||
int bi_used;
|
||||
/* Last number of used bits when going to a byte boundary.
|
||||
*/
|
||||
|
||||
ulg high_water;
|
||||
/* High water mark offset in window for initialized bytes -- bytes above
|
||||
@@ -279,6 +292,21 @@ typedef struct internal_state {
|
||||
* updated to the new high water mark.
|
||||
*/
|
||||
|
||||
uInt chromium_zlib_hash;
|
||||
/* 0 if Rabin-Karp rolling hash is enabled, non-zero if chromium zlib
|
||||
* hash is enabled.
|
||||
*/
|
||||
|
||||
#if defined(QAT_COMPRESSION_ENABLED)
|
||||
/* Pointer to a struct that contains the current state of the QAT
|
||||
* stream.
|
||||
*/
|
||||
struct qat_deflate *qat_s;
|
||||
#endif
|
||||
|
||||
int slid;
|
||||
/* True if the hash table has been slid since it was cleared. */
|
||||
|
||||
} FAR deflate_state;
|
||||
|
||||
/* Output a byte on the stream.
|
||||
@@ -374,4 +402,12 @@ void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf,
|
||||
flush = _tr_tally(s, distance, length)
|
||||
#endif
|
||||
|
||||
/* Functions that are SIMD optimised on x86 */
|
||||
void ZLIB_INTERNAL crc_fold_init(deflate_state* const s);
|
||||
void ZLIB_INTERNAL crc_fold_copy(deflate_state* const s,
|
||||
unsigned char* dst,
|
||||
const unsigned char* src,
|
||||
long len);
|
||||
unsigned ZLIB_INTERNAL crc_fold_512to32(deflate_state* const s);
|
||||
|
||||
#endif /* DEFLATE_H */
|
||||
|
||||
+38
-31
@@ -1,5 +1,5 @@
|
||||
/* gzguts.h -- zlib internal header definitions for gz* operations
|
||||
* Copyright (C) 2004-2024 Mark Adler
|
||||
* Copyright (C) 2004-2026 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@@ -17,6 +17,18 @@
|
||||
# define ZLIB_INTERNAL
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# ifndef _CRT_SECURE_NO_WARNINGS
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
# endif
|
||||
# ifndef _CRT_NONSTDC_NO_DEPRECATE
|
||||
# define _CRT_NONSTDC_NO_DEPRECATE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "zlib.h"
|
||||
#ifdef STDC
|
||||
@@ -25,8 +37,8 @@
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#ifndef _POSIX_SOURCE
|
||||
# define _POSIX_SOURCE
|
||||
#ifndef _POSIX_C_SOURCE
|
||||
# define _POSIX_C_SOURCE 200112L
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
|
||||
@@ -36,19 +48,13 @@
|
||||
|
||||
#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32)
|
||||
# include <io.h>
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(_WIN32) && !defined(WIDECHAR)
|
||||
# define WIDECHAR
|
||||
#endif
|
||||
|
||||
#ifdef WINAPI_FAMILY
|
||||
# define open _open
|
||||
# define read _read
|
||||
# define write _write
|
||||
# define close _close
|
||||
#endif
|
||||
|
||||
#ifdef NO_DEFLATE /* for compatibility with old definition */
|
||||
# define NO_GZCOMPRESS
|
||||
#endif
|
||||
@@ -72,33 +78,28 @@
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_VSNPRINTF
|
||||
# ifdef MSDOS
|
||||
# if !defined(NO_vsnprintf) && \
|
||||
(defined(MSDOS) || defined(__TURBOC__) || defined(__SASC) || \
|
||||
defined(VMS) || defined(__OS400) || defined(__MVS__))
|
||||
/* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
|
||||
but for now we just assume it doesn't. */
|
||||
# define NO_vsnprintf
|
||||
# endif
|
||||
# ifdef __TURBOC__
|
||||
# define NO_vsnprintf
|
||||
# endif
|
||||
# ifdef WIN32
|
||||
/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
|
||||
# if !defined(vsnprintf) && !defined(NO_vsnprintf)
|
||||
# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )
|
||||
# define vsnprintf _vsnprintf
|
||||
# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )
|
||||
# ifndef vsnprintf
|
||||
# define vsnprintf _vsnprintf
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
# ifdef __SASC
|
||||
# define NO_vsnprintf
|
||||
# endif
|
||||
# ifdef VMS
|
||||
# define NO_vsnprintf
|
||||
# endif
|
||||
# ifdef __OS400__
|
||||
# define NO_vsnprintf
|
||||
# endif
|
||||
# ifdef __MVS__
|
||||
# define NO_vsnprintf
|
||||
# elif !defined(__STDC_VERSION__) || __STDC_VERSION__-0 < 199901L
|
||||
/* Otherwise if C89/90, assume no C99 snprintf() or vsnprintf() */
|
||||
# ifndef NO_snprintf
|
||||
# define NO_snprintf
|
||||
# endif
|
||||
# ifndef NO_vsnprintf
|
||||
# define NO_vsnprintf
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -135,6 +136,11 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* some environments don't define EWOULDBLOCK */
|
||||
#ifndef EWOULDBLOCK
|
||||
# define EWOULDBLOCK EAGAIN
|
||||
#endif
|
||||
|
||||
/* provide prototypes for these when building zlib without LFS */
|
||||
#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
|
||||
ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *);
|
||||
@@ -182,7 +188,9 @@ typedef struct {
|
||||
unsigned char *out; /* output buffer (double-sized when reading) */
|
||||
int direct; /* 0 if processing gzip, 1 if transparent */
|
||||
/* just for reading */
|
||||
int junk; /* -1 = start, 1 = junk candidate, 0 = in gzip */
|
||||
int how; /* 0: get header, 1: copy, 2: decompress */
|
||||
int again; /* true if EAGAIN or EWOULDBLOCK on last i/o */
|
||||
z_off64_t start; /* where the gzip data started, for rewinding */
|
||||
int eof; /* true if end of input file reached */
|
||||
int past; /* true if read requested past end */
|
||||
@@ -192,7 +200,6 @@ typedef struct {
|
||||
int reset; /* true if a reset is pending after a Z_FINISH */
|
||||
/* seek request */
|
||||
z_off64_t skip; /* amount to skip (already rewound if backwards) */
|
||||
int seek; /* true if seek request pending */
|
||||
/* error information */
|
||||
int err; /* error code */
|
||||
char *msg; /* error message */
|
||||
|
||||
Vendored
+68
-38
@@ -1,18 +1,21 @@
|
||||
/* gzlib.c -- zlib functions common to reading and writing gzip files
|
||||
* Copyright (C) 2004-2024 Mark Adler
|
||||
* Copyright (C) 2004-2026 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
#include "gzguts.h"
|
||||
|
||||
#if defined(_WIN32) && !defined(__BORLANDC__)
|
||||
#if defined(__DJGPP__)
|
||||
# define LSEEK llseek
|
||||
#elif defined(_WIN32) && !defined(__BORLANDC__) && !defined(UNDER_CE)
|
||||
# define LSEEK _lseeki64
|
||||
#else
|
||||
#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
|
||||
# define OPEN open
|
||||
#elif defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
|
||||
# define LSEEK lseek64
|
||||
# define OPEN open64
|
||||
#else
|
||||
# define LSEEK lseek
|
||||
#endif
|
||||
# define OPEN open
|
||||
#endif
|
||||
|
||||
#if defined UNDER_CE
|
||||
@@ -52,7 +55,7 @@ char ZLIB_INTERNAL *gz_strwinerror(DWORD error) {
|
||||
msgbuf[chars] = 0;
|
||||
}
|
||||
|
||||
wcstombs(buf, msgbuf, chars + 1);
|
||||
wcstombs(buf, msgbuf, chars + 1); /* assumes buf is big enough */
|
||||
LocalFree(msgbuf);
|
||||
}
|
||||
else {
|
||||
@@ -72,10 +75,12 @@ local void gz_reset(gz_statep state) {
|
||||
state->eof = 0; /* not at end of file */
|
||||
state->past = 0; /* have not read past end yet */
|
||||
state->how = LOOK; /* look for gzip header */
|
||||
state->junk = -1; /* mark first member */
|
||||
}
|
||||
else /* for writing ... */
|
||||
state->reset = 0; /* no deflateReset pending */
|
||||
state->seek = 0; /* no seek request pending */
|
||||
state->again = 0; /* no stalled i/o yet */
|
||||
state->skip = 0; /* no seek request pending */
|
||||
gz_error(state, Z_OK, NULL); /* clear error */
|
||||
state->x.pos = 0; /* no uncompressed data yet */
|
||||
state->strm.avail_in = 0; /* no input data yet */
|
||||
@@ -85,16 +90,13 @@ local void gz_reset(gz_statep state) {
|
||||
local gzFile gz_open(const void *path, int fd, const char *mode) {
|
||||
gz_statep state;
|
||||
z_size_t len;
|
||||
int oflag;
|
||||
#ifdef O_CLOEXEC
|
||||
int cloexec = 0;
|
||||
#endif
|
||||
int oflag = 0;
|
||||
#ifdef O_EXCL
|
||||
int exclusive = 0;
|
||||
#endif
|
||||
|
||||
/* check input */
|
||||
if (path == NULL)
|
||||
if (path == NULL || mode == NULL)
|
||||
return NULL;
|
||||
|
||||
/* allocate gzFile structure to return */
|
||||
@@ -103,6 +105,7 @@ local gzFile gz_open(const void *path, int fd, const char *mode) {
|
||||
return NULL;
|
||||
state->size = 0; /* no buffers allocated yet */
|
||||
state->want = GZBUFSIZE; /* requested buffer size */
|
||||
state->err = Z_OK; /* no error yet */
|
||||
state->msg = NULL; /* no error message yet */
|
||||
|
||||
/* interpret mode */
|
||||
@@ -133,7 +136,7 @@ local gzFile gz_open(const void *path, int fd, const char *mode) {
|
||||
break;
|
||||
#ifdef O_CLOEXEC
|
||||
case 'e':
|
||||
cloexec = 1;
|
||||
oflag |= O_CLOEXEC;
|
||||
break;
|
||||
#endif
|
||||
#ifdef O_EXCL
|
||||
@@ -153,6 +156,14 @@ local gzFile gz_open(const void *path, int fd, const char *mode) {
|
||||
case 'F':
|
||||
state->strategy = Z_FIXED;
|
||||
break;
|
||||
case 'G':
|
||||
state->direct = -1;
|
||||
break;
|
||||
#ifdef O_NONBLOCK
|
||||
case 'N':
|
||||
oflag |= O_NONBLOCK;
|
||||
break;
|
||||
#endif
|
||||
case 'T':
|
||||
state->direct = 1;
|
||||
break;
|
||||
@@ -168,22 +179,30 @@ local gzFile gz_open(const void *path, int fd, const char *mode) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* can't force transparent read */
|
||||
/* direct is 0, 1 if "T", or -1 if "G" (last "G" or "T" wins) */
|
||||
if (state->mode == GZ_READ) {
|
||||
if (state->direct) {
|
||||
if (state->direct == 1) {
|
||||
/* can't force a transparent read */
|
||||
free(state);
|
||||
return NULL;
|
||||
}
|
||||
state->direct = 1; /* for empty file */
|
||||
if (state->direct == 0)
|
||||
/* default when reading is auto-detect of gzip vs. transparent --
|
||||
start with a transparent assumption in case of an empty file */
|
||||
state->direct = 1;
|
||||
}
|
||||
else if (state->direct == -1) {
|
||||
/* "G" has no meaning when writing -- disallow it */
|
||||
free(state);
|
||||
return NULL;
|
||||
}
|
||||
/* if reading, direct == 1 for auto-detect, -1 for gzip only; if writing or
|
||||
appending, direct == 0 for gzip, 1 for transparent (copy in to out) */
|
||||
|
||||
/* save the path name for error messages */
|
||||
#ifdef WIDECHAR
|
||||
if (fd == -2) {
|
||||
if (fd == -2)
|
||||
len = wcstombs(NULL, path, 0);
|
||||
if (len == (z_size_t)-1)
|
||||
len = 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
len = strlen((const char *)path);
|
||||
@@ -193,29 +212,29 @@ local gzFile gz_open(const void *path, int fd, const char *mode) {
|
||||
return NULL;
|
||||
}
|
||||
#ifdef WIDECHAR
|
||||
if (fd == -2)
|
||||
if (fd == -2) {
|
||||
if (len)
|
||||
wcstombs(state->path, path, len + 1);
|
||||
else
|
||||
*(state->path) = 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
|
||||
(void)snprintf(state->path, len + 1, "%s", (const char *)path);
|
||||
#else
|
||||
strcpy(state->path, path);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* compute the flags for open() */
|
||||
oflag =
|
||||
oflag |=
|
||||
#ifdef O_LARGEFILE
|
||||
O_LARGEFILE |
|
||||
#endif
|
||||
#ifdef O_BINARY
|
||||
O_BINARY |
|
||||
#endif
|
||||
#ifdef O_CLOEXEC
|
||||
(cloexec ? O_CLOEXEC : 0) |
|
||||
#endif
|
||||
(state->mode == GZ_READ ?
|
||||
O_RDONLY :
|
||||
@@ -228,11 +247,23 @@ local gzFile gz_open(const void *path, int fd, const char *mode) {
|
||||
O_APPEND)));
|
||||
|
||||
/* open the file with the appropriate flags (or just use fd) */
|
||||
state->fd = fd > -1 ? fd : (
|
||||
if (fd == -1)
|
||||
state->fd = OPEN((const char *)path, oflag, 0666);
|
||||
#ifdef WIDECHAR
|
||||
fd == -2 ? _wopen(path, oflag, 0666) :
|
||||
else if (fd == -2)
|
||||
state->fd = _wopen(path, oflag, _S_IREAD | _S_IWRITE);
|
||||
#endif
|
||||
open((const char *)path, oflag, 0666));
|
||||
else {
|
||||
#ifdef O_NONBLOCK
|
||||
if (oflag & O_NONBLOCK)
|
||||
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
|
||||
#endif
|
||||
#ifdef O_CLOEXEC
|
||||
if (oflag & O_CLOEXEC)
|
||||
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | O_CLOEXEC);
|
||||
#endif
|
||||
state->fd = fd;
|
||||
}
|
||||
if (state->fd == -1) {
|
||||
free(state->path);
|
||||
free(state);
|
||||
@@ -359,9 +390,10 @@ z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
|
||||
/* normalize offset to a SEEK_CUR specification */
|
||||
if (whence == SEEK_SET)
|
||||
offset -= state->x.pos;
|
||||
else if (state->seek)
|
||||
offset += state->skip;
|
||||
state->seek = 0;
|
||||
else {
|
||||
offset += state->past ? 0 : state->skip;
|
||||
state->skip = 0;
|
||||
}
|
||||
|
||||
/* if within raw area while reading, just go there */
|
||||
if (state->mode == GZ_READ && state->how == COPY &&
|
||||
@@ -372,7 +404,7 @@ z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
|
||||
state->x.have = 0;
|
||||
state->eof = 0;
|
||||
state->past = 0;
|
||||
state->seek = 0;
|
||||
state->skip = 0;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
state->strm.avail_in = 0;
|
||||
state->x.pos += offset;
|
||||
@@ -401,10 +433,7 @@ z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
|
||||
}
|
||||
|
||||
/* request skip (if not zero) */
|
||||
if (offset) {
|
||||
state->seek = 1;
|
||||
state->skip = offset;
|
||||
}
|
||||
state->skip = offset;
|
||||
return state->x.pos + offset;
|
||||
}
|
||||
|
||||
@@ -428,7 +457,7 @@ z_off64_t ZEXPORT gztell64(gzFile file) {
|
||||
return -1;
|
||||
|
||||
/* return position */
|
||||
return state->x.pos + (state->seek ? state->skip : 0);
|
||||
return state->x.pos + (state->past ? 0 : state->skip);
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
@@ -535,7 +564,7 @@ void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
|
||||
}
|
||||
|
||||
/* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
|
||||
if (err != Z_OK && err != Z_BUF_ERROR)
|
||||
if (err != Z_OK && err != Z_BUF_ERROR && !state->again)
|
||||
state->x.have = 0;
|
||||
|
||||
/* set error code, and if no message, then done */
|
||||
@@ -572,6 +601,7 @@ unsigned ZLIB_INTERNAL gz_intmax(void) {
|
||||
return INT_MAX;
|
||||
#else
|
||||
unsigned p = 1, q;
|
||||
|
||||
do {
|
||||
q = p;
|
||||
p <<= 1;
|
||||
|
||||
+194
-124
@@ -1,5 +1,5 @@
|
||||
/* gzread.c -- zlib functions for reading gzip files
|
||||
* Copyright (C) 2004-2017 Mark Adler
|
||||
* Copyright (C) 2004-2026 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@@ -8,23 +8,36 @@
|
||||
/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from
|
||||
state->fd, and update state->eof, state->err, and state->msg as appropriate.
|
||||
This function needs to loop on read(), since read() is not guaranteed to
|
||||
read the number of bytes requested, depending on the type of descriptor. */
|
||||
read the number of bytes requested, depending on the type of descriptor. It
|
||||
also needs to loop to manage the fact that read() returns an int. If the
|
||||
descriptor is non-blocking and read() returns with no data in order to avoid
|
||||
blocking, then gz_load() will return 0 if some data has been read, or -1 if
|
||||
no data has been read. Either way, state->again is set true to indicate a
|
||||
non-blocking event. If errno is non-zero on return, then there was an error
|
||||
signaled from read(). *have is set to the number of bytes read. */
|
||||
local int gz_load(gz_statep state, unsigned char *buf, unsigned len,
|
||||
unsigned *have) {
|
||||
int ret;
|
||||
unsigned get, max = ((unsigned)-1 >> 2) + 1;
|
||||
|
||||
state->again = 0;
|
||||
errno = 0;
|
||||
*have = 0;
|
||||
do {
|
||||
get = len - *have;
|
||||
if (get > max)
|
||||
get = max;
|
||||
ret = read(state->fd, buf + *have, get);
|
||||
ret = (int)read(state->fd, buf + *have, get);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
*have += (unsigned)ret;
|
||||
} while (*have < len);
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
state->again = 1;
|
||||
if (*have != 0)
|
||||
return 0;
|
||||
}
|
||||
gz_error(state, Z_ERRNO, zstrerror());
|
||||
return -1;
|
||||
}
|
||||
@@ -50,10 +63,14 @@ local int gz_avail(gz_statep state) {
|
||||
if (strm->avail_in) { /* copy what's there to the start */
|
||||
unsigned char *p = state->in;
|
||||
unsigned const char *q = strm->next_in;
|
||||
unsigned n = strm->avail_in;
|
||||
do {
|
||||
*p++ = *q++;
|
||||
} while (--n);
|
||||
|
||||
if (q != p) {
|
||||
unsigned n = strm->avail_in;
|
||||
|
||||
do {
|
||||
*p++ = *q++;
|
||||
} while (--n);
|
||||
}
|
||||
}
|
||||
if (gz_load(state, state->in + strm->avail_in,
|
||||
state->size - strm->avail_in, &got) == -1)
|
||||
@@ -104,39 +121,44 @@ local int gz_look(gz_statep state) {
|
||||
}
|
||||
}
|
||||
|
||||
/* get at least the magic bytes in the input buffer */
|
||||
if (strm->avail_in < 2) {
|
||||
if (gz_avail(state) == -1)
|
||||
return -1;
|
||||
if (strm->avail_in == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* look for gzip magic bytes -- if there, do gzip decoding (note: there is
|
||||
a logical dilemma here when considering the case of a partially written
|
||||
gzip file, to wit, if a single 31 byte is written, then we cannot tell
|
||||
whether this is a single-byte file, or just a partially written gzip
|
||||
file -- for here we assume that if a gzip file is being written, then
|
||||
the header will be written in a single operation, so that reading a
|
||||
single byte is sufficient indication that it is not a gzip file) */
|
||||
if (strm->avail_in > 1 &&
|
||||
strm->next_in[0] == 31 && strm->next_in[1] == 139) {
|
||||
/* if transparent reading is disabled, which would only be at the start, or
|
||||
if we're looking for a gzip member after the first one, which is not at
|
||||
the start, then proceed directly to look for a gzip member next */
|
||||
if (state->direct == -1 || state->junk == 0) {
|
||||
inflateReset(strm);
|
||||
state->how = GZIP;
|
||||
state->junk = state->junk != -1;
|
||||
state->direct = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* no gzip header -- if we were decoding gzip before, then this is trailing
|
||||
garbage. Ignore the trailing garbage and finish. */
|
||||
if (state->direct == 0) {
|
||||
strm->avail_in = 0;
|
||||
state->eof = 1;
|
||||
state->x.have = 0;
|
||||
/* otherwise we're at the start with auto-detect -- we check to see if the
|
||||
first four bytes could be gzip header in order to decide whether or not
|
||||
this will be a transparent read */
|
||||
|
||||
/* load any header bytes into the input buffer -- if the input is empty,
|
||||
then it's not an error as this is a transparent read of zero bytes */
|
||||
if (gz_avail(state) == -1)
|
||||
return -1;
|
||||
if (strm->avail_in == 0 || (state->again && strm->avail_in < 4))
|
||||
/* if non-blocking input stalled before getting four bytes, then
|
||||
return and wait until a later call has accumulated enough */
|
||||
return 0;
|
||||
|
||||
/* see if this is (likely) gzip input -- if the first four bytes are
|
||||
consistent with a gzip header, then go look for the first gzip member,
|
||||
otherwise proceed to copy the input transparently */
|
||||
if (strm->avail_in > 3 &&
|
||||
strm->next_in[0] == 31 && strm->next_in[1] == 139 &&
|
||||
strm->next_in[2] == 8 && strm->next_in[3] < 32) {
|
||||
inflateReset(strm);
|
||||
state->how = GZIP;
|
||||
state->junk = 1;
|
||||
state->direct = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* doing raw i/o, copy any leftover input to output -- this assumes that
|
||||
/* doing raw i/o: copy any leftover input to output -- this assumes that
|
||||
the output buffer is larger than the input buffer, which also assures
|
||||
space for gzungetc() */
|
||||
state->x.next = state->out;
|
||||
@@ -144,15 +166,17 @@ local int gz_look(gz_statep state) {
|
||||
state->x.have = strm->avail_in;
|
||||
strm->avail_in = 0;
|
||||
state->how = COPY;
|
||||
state->direct = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Decompress from input to the provided next_out and avail_out in the state.
|
||||
On return, state->x.have and state->x.next point to the just decompressed
|
||||
data. If the gzip stream completes, state->how is reset to LOOK to look for
|
||||
the next gzip stream or raw data, once state->x.have is depleted. Returns 0
|
||||
on success, -1 on failure. */
|
||||
data. If the gzip stream completes, state->how is reset to LOOK to look for
|
||||
the next gzip stream or raw data, once state->x.have is depleted. Returns 0
|
||||
on success, -1 on failure. If EOF is reached when looking for more input to
|
||||
complete the gzip member, then an unexpected end of file error is raised.
|
||||
If there is no more input, but state->again is true, then EOF has not been
|
||||
reached, and no error is raised. */
|
||||
local int gz_decomp(gz_statep state) {
|
||||
int ret = Z_OK;
|
||||
unsigned had;
|
||||
@@ -162,28 +186,41 @@ local int gz_decomp(gz_statep state) {
|
||||
had = strm->avail_out;
|
||||
do {
|
||||
/* get more input for inflate() */
|
||||
if (strm->avail_in == 0 && gz_avail(state) == -1)
|
||||
return -1;
|
||||
if (strm->avail_in == 0 && gz_avail(state) == -1) {
|
||||
ret = state->err;
|
||||
break;
|
||||
}
|
||||
if (strm->avail_in == 0) {
|
||||
gz_error(state, Z_BUF_ERROR, "unexpected end of file");
|
||||
if (!state->again)
|
||||
gz_error(state, Z_BUF_ERROR, "unexpected end of file");
|
||||
break;
|
||||
}
|
||||
|
||||
/* decompress and handle errors */
|
||||
ret = inflate(strm, Z_NO_FLUSH);
|
||||
if (strm->avail_out < had)
|
||||
/* any decompressed data marks this as a real gzip stream */
|
||||
state->junk = 0;
|
||||
if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
|
||||
gz_error(state, Z_STREAM_ERROR,
|
||||
"internal error: inflate stream corrupt");
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
if (ret == Z_MEM_ERROR) {
|
||||
gz_error(state, Z_MEM_ERROR, "out of memory");
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
if (ret == Z_DATA_ERROR) { /* deflate stream invalid */
|
||||
if (state->junk == 1) { /* trailing garbage is ok */
|
||||
strm->avail_in = 0;
|
||||
state->eof = 1;
|
||||
state->how = LOOK;
|
||||
ret = Z_OK;
|
||||
break;
|
||||
}
|
||||
gz_error(state, Z_DATA_ERROR,
|
||||
strm->msg == NULL ? "compressed data error" : strm->msg);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
} while (strm->avail_out && ret != Z_STREAM_END);
|
||||
|
||||
@@ -192,11 +229,14 @@ local int gz_decomp(gz_statep state) {
|
||||
state->x.next = strm->next_out - state->x.have;
|
||||
|
||||
/* if the gzip stream completed successfully, look for another */
|
||||
if (ret == Z_STREAM_END)
|
||||
if (ret == Z_STREAM_END) {
|
||||
state->junk = 0;
|
||||
state->how = LOOK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* good decompression */
|
||||
return 0;
|
||||
/* return decompression status */
|
||||
return ret != Z_OK ? -1 : 0;
|
||||
}
|
||||
|
||||
/* Fetch data and put it in the output buffer. Assumes state->x.have is 0.
|
||||
@@ -227,25 +267,31 @@ local int gz_fetch(gz_statep state) {
|
||||
strm->next_out = state->out;
|
||||
if (gz_decomp(state) == -1)
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
gz_error(state, Z_STREAM_ERROR, "state corrupt");
|
||||
return -1;
|
||||
}
|
||||
} while (state->x.have == 0 && (!state->eof || strm->avail_in));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */
|
||||
local int gz_skip(gz_statep state, z_off64_t len) {
|
||||
/* Skip state->skip (> 0) uncompressed bytes of output. Return -1 on error, 0
|
||||
on success. */
|
||||
local int gz_skip(gz_statep state) {
|
||||
unsigned n;
|
||||
|
||||
/* skip over len bytes or reach end-of-file, whichever comes first */
|
||||
while (len)
|
||||
do {
|
||||
/* skip over whatever is in output buffer */
|
||||
if (state->x.have) {
|
||||
n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?
|
||||
(unsigned)len : state->x.have;
|
||||
n = GT_OFF(state->x.have) ||
|
||||
(z_off64_t)state->x.have > state->skip ?
|
||||
(unsigned)state->skip : state->x.have;
|
||||
state->x.have -= n;
|
||||
state->x.next += n;
|
||||
state->x.pos += n;
|
||||
len -= n;
|
||||
state->skip -= n;
|
||||
}
|
||||
|
||||
/* output buffer empty -- return if we're at the end of the input */
|
||||
@@ -258,30 +304,32 @@ local int gz_skip(gz_statep state, z_off64_t len) {
|
||||
if (gz_fetch(state) == -1)
|
||||
return -1;
|
||||
}
|
||||
} while (state->skip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read len bytes into buf from file, or less than len up to the end of the
|
||||
input. Return the number of bytes read. If zero is returned, either the
|
||||
end of file was reached, or there was an error. state->err must be
|
||||
consulted in that case to determine which. */
|
||||
input. Return the number of bytes read. If zero is returned, either the end
|
||||
of file was reached, or there was an error. state->err must be consulted in
|
||||
that case to determine which. If there was an error, but some uncompressed
|
||||
bytes were read before the error, then that count is returned. The error is
|
||||
still recorded, and so is deferred until the next call. */
|
||||
local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) {
|
||||
z_size_t got;
|
||||
unsigned n;
|
||||
int err;
|
||||
|
||||
/* if len is zero, avoid unnecessary operations */
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
/* process a skip request */
|
||||
if (state->seek) {
|
||||
state->seek = 0;
|
||||
if (gz_skip(state, state->skip) == -1)
|
||||
return 0;
|
||||
}
|
||||
if (state->skip && gz_skip(state) == -1)
|
||||
return 0;
|
||||
|
||||
/* get len bytes to buf, or less than len if at the end */
|
||||
got = 0;
|
||||
err = 0;
|
||||
do {
|
||||
/* set n to the maximum amount of len that fits in an unsigned int */
|
||||
n = (unsigned)-1;
|
||||
@@ -295,37 +343,36 @@ local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) {
|
||||
memcpy(buf, state->x.next, n);
|
||||
state->x.next += n;
|
||||
state->x.have -= n;
|
||||
if (state->err != Z_OK)
|
||||
/* caught deferred error from gz_fetch() */
|
||||
err = -1;
|
||||
}
|
||||
|
||||
/* output buffer empty -- return if we're at the end of the input */
|
||||
else if (state->eof && state->strm.avail_in == 0) {
|
||||
state->past = 1; /* tried to read past end */
|
||||
else if (state->eof && state->strm.avail_in == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* need output data -- for small len or new stream load up our output
|
||||
buffer */
|
||||
buffer, so that gzgetc() can be fast */
|
||||
else if (state->how == LOOK || n < (state->size << 1)) {
|
||||
/* get more output, looking for header if required */
|
||||
if (gz_fetch(state) == -1)
|
||||
return 0;
|
||||
if (gz_fetch(state) == -1 && state->x.have == 0)
|
||||
/* if state->x.have != 0, error will be caught after copy */
|
||||
err = -1;
|
||||
continue; /* no progress yet -- go back to copy above */
|
||||
/* the copy above assures that we will leave with space in the
|
||||
output buffer, allowing at least one gzungetc() to succeed */
|
||||
}
|
||||
|
||||
/* large len -- read directly into user buffer */
|
||||
else if (state->how == COPY) { /* read directly */
|
||||
if (gz_load(state, (unsigned char *)buf, n, &n) == -1)
|
||||
return 0;
|
||||
}
|
||||
else if (state->how == COPY) /* read directly */
|
||||
err = gz_load(state, (unsigned char *)buf, n, &n);
|
||||
|
||||
/* large len -- decompress directly into user buffer */
|
||||
else { /* state->how == GZIP */
|
||||
state->strm.avail_out = n;
|
||||
state->strm.next_out = (unsigned char *)buf;
|
||||
if (gz_decomp(state) == -1)
|
||||
return 0;
|
||||
err = gz_decomp(state);
|
||||
n = state->x.have;
|
||||
state->x.have = 0;
|
||||
}
|
||||
@@ -335,7 +382,11 @@ local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) {
|
||||
buf = (char *)buf + n;
|
||||
got += n;
|
||||
state->x.pos += n;
|
||||
} while (len);
|
||||
} while (len && !err);
|
||||
|
||||
/* note read past eof */
|
||||
if (len && state->eof)
|
||||
state->past = 1;
|
||||
|
||||
/* return number of bytes read into user buffer */
|
||||
return got;
|
||||
@@ -345,16 +396,18 @@ local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) {
|
||||
int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) {
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure */
|
||||
/* get internal structure and check that it's for reading */
|
||||
if (file == NULL)
|
||||
return -1;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're reading and that there's no (serious) error */
|
||||
if (state->mode != GZ_READ ||
|
||||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
|
||||
if (state->mode != GZ_READ)
|
||||
return -1;
|
||||
|
||||
/* check that there was no (serious) error */
|
||||
if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
|
||||
return -1;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* since an int is returned, make sure len fits in one, otherwise return
|
||||
with an error (this avoids a flaw in the interface) */
|
||||
if ((int)len < 0) {
|
||||
@@ -366,28 +419,40 @@ int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) {
|
||||
len = (unsigned)gz_read(state, buf, len);
|
||||
|
||||
/* check for an error */
|
||||
if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR)
|
||||
return -1;
|
||||
if (len == 0) {
|
||||
if (state->err != Z_OK && state->err != Z_BUF_ERROR)
|
||||
return -1;
|
||||
if (state->again) {
|
||||
/* non-blocking input stalled after some input was read, but no
|
||||
uncompressed bytes were produced -- let the application know
|
||||
this isn't EOF */
|
||||
gz_error(state, Z_ERRNO, zstrerror());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* return the number of bytes read (this is assured to fit in an int) */
|
||||
/* return the number of bytes read */
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file) {
|
||||
z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems,
|
||||
gzFile file) {
|
||||
z_size_t len;
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure */
|
||||
/* get internal structure and check that it's for reading */
|
||||
if (file == NULL)
|
||||
return 0;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're reading and that there's no (serious) error */
|
||||
if (state->mode != GZ_READ ||
|
||||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
|
||||
if (state->mode != GZ_READ)
|
||||
return 0;
|
||||
|
||||
/* check that there was no (serious) error */
|
||||
if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
|
||||
return 0;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* compute bytes to read -- error on overflow */
|
||||
len = nitems * size;
|
||||
if (size && len / size != nitems) {
|
||||
@@ -404,21 +469,27 @@ z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file)
|
||||
# undef z_gzgetc
|
||||
#else
|
||||
# undef gzgetc
|
||||
# ifdef Z_CR_PREFIX_SET
|
||||
# define gzgetc Cr_z_gzgetc
|
||||
# endif
|
||||
#endif
|
||||
|
||||
int ZEXPORT gzgetc(gzFile file) {
|
||||
unsigned char buf[1];
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure */
|
||||
/* get internal structure and check that it's for reading */
|
||||
if (file == NULL)
|
||||
return -1;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're reading and that there's no (serious) error */
|
||||
if (state->mode != GZ_READ ||
|
||||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
|
||||
if (state->mode != GZ_READ)
|
||||
return -1;
|
||||
|
||||
/* check that there was no (serious) error */
|
||||
if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
|
||||
return -1;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* try output buffer (no need to check for skip request) */
|
||||
if (state->x.have) {
|
||||
state->x.have--;
|
||||
@@ -438,26 +509,25 @@ int ZEXPORT gzgetc_(gzFile file) {
|
||||
int ZEXPORT gzungetc(int c, gzFile file) {
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure */
|
||||
/* get internal structure and check that it's for reading */
|
||||
if (file == NULL)
|
||||
return -1;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* in case this was just opened, set up the input buffer */
|
||||
if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
|
||||
(void)gz_look(state);
|
||||
|
||||
/* check that we're reading and that there's no (serious) error */
|
||||
if (state->mode != GZ_READ ||
|
||||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
|
||||
if (state->mode != GZ_READ)
|
||||
return -1;
|
||||
|
||||
/* in case this was just opened, set up the input buffer */
|
||||
if (state->how == LOOK && state->x.have == 0)
|
||||
(void)gz_look(state);
|
||||
|
||||
/* check that there was no (serious) error */
|
||||
if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
|
||||
return -1;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* process a skip request */
|
||||
if (state->seek) {
|
||||
state->seek = 0;
|
||||
if (gz_skip(state, state->skip) == -1)
|
||||
return -1;
|
||||
}
|
||||
if (state->skip && gz_skip(state) == -1)
|
||||
return -1;
|
||||
|
||||
/* can't push EOF */
|
||||
if (c < 0)
|
||||
@@ -483,6 +553,7 @@ int ZEXPORT gzungetc(int c, gzFile file) {
|
||||
if (state->x.next == state->out) {
|
||||
unsigned char *src = state->out + state->x.have;
|
||||
unsigned char *dest = state->out + (state->size << 1);
|
||||
|
||||
while (src > state->out)
|
||||
*--dest = *--src;
|
||||
state->x.next = dest;
|
||||
@@ -502,32 +573,31 @@ char * ZEXPORT gzgets(gzFile file, char *buf, int len) {
|
||||
unsigned char *eol;
|
||||
gz_statep state;
|
||||
|
||||
/* check parameters and get internal structure */
|
||||
/* check parameters, get internal structure, and check that it's for
|
||||
reading */
|
||||
if (file == NULL || buf == NULL || len < 1)
|
||||
return NULL;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're reading and that there's no (serious) error */
|
||||
if (state->mode != GZ_READ ||
|
||||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
|
||||
if (state->mode != GZ_READ)
|
||||
return NULL;
|
||||
|
||||
/* process a skip request */
|
||||
if (state->seek) {
|
||||
state->seek = 0;
|
||||
if (gz_skip(state, state->skip) == -1)
|
||||
return NULL;
|
||||
}
|
||||
/* check that there was no (serious) error */
|
||||
if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
|
||||
return NULL;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* copy output bytes up to new line or len - 1, whichever comes first --
|
||||
append a terminating zero to the string (we don't check for a zero in
|
||||
the contents, let the user worry about that) */
|
||||
/* process a skip request */
|
||||
if (state->skip && gz_skip(state) == -1)
|
||||
return NULL;
|
||||
|
||||
/* copy output up to a new line, len-1 bytes, or there is no more output,
|
||||
whichever comes first */
|
||||
str = buf;
|
||||
left = (unsigned)len - 1;
|
||||
if (left) do {
|
||||
/* assure that something is in the output buffer */
|
||||
if (state->x.have == 0 && gz_fetch(state) == -1)
|
||||
return NULL; /* error */
|
||||
break; /* error */
|
||||
if (state->x.have == 0) { /* end of file */
|
||||
state->past = 1; /* read past end */
|
||||
break; /* return what we have */
|
||||
@@ -548,7 +618,9 @@ char * ZEXPORT gzgets(gzFile file, char *buf, int len) {
|
||||
buf += n;
|
||||
} while (left && eol == NULL);
|
||||
|
||||
/* return terminated string, or if nothing, end of file */
|
||||
/* append a terminating zero to the string (we don't check for a zero in
|
||||
the contents, let the user worry about that) -- return the terminated
|
||||
string, or if nothing was read, NULL */
|
||||
if (buf == str)
|
||||
return NULL;
|
||||
buf[0] = 0;
|
||||
@@ -570,7 +642,7 @@ int ZEXPORT gzdirect(gzFile file) {
|
||||
(void)gz_look(state);
|
||||
|
||||
/* return 1 if transparent, 0 if processing a gzip stream */
|
||||
return state->direct;
|
||||
return state->direct == 1;
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
@@ -578,12 +650,10 @@ int ZEXPORT gzclose_r(gzFile file) {
|
||||
int ret, err;
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure */
|
||||
/* get internal structure and check that it's for reading */
|
||||
if (file == NULL)
|
||||
return Z_STREAM_ERROR;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're reading */
|
||||
if (state->mode != GZ_READ)
|
||||
return Z_STREAM_ERROR;
|
||||
|
||||
|
||||
+168
-99
@@ -1,5 +1,5 @@
|
||||
/* gzwrite.c -- zlib functions for writing gzip files
|
||||
* Copyright (C) 2004-2019 Mark Adler
|
||||
* Copyright (C) 2004-2026 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@@ -74,9 +74,13 @@ local int gz_comp(gz_statep state, int flush) {
|
||||
/* write directly if requested */
|
||||
if (state->direct) {
|
||||
while (strm->avail_in) {
|
||||
errno = 0;
|
||||
state->again = 0;
|
||||
put = strm->avail_in > max ? max : strm->avail_in;
|
||||
writ = write(state->fd, strm->next_in, put);
|
||||
writ = (int)write(state->fd, strm->next_in, put);
|
||||
if (writ < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
state->again = 1;
|
||||
gz_error(state, Z_ERRNO, zstrerror());
|
||||
return -1;
|
||||
}
|
||||
@@ -88,8 +92,9 @@ local int gz_comp(gz_statep state, int flush) {
|
||||
|
||||
/* check for a pending reset */
|
||||
if (state->reset) {
|
||||
/* don't start a new gzip member unless there is data to write */
|
||||
if (strm->avail_in == 0)
|
||||
/* don't start a new gzip member unless there is data to write and
|
||||
we're not flushing */
|
||||
if (strm->avail_in == 0 && flush == Z_NO_FLUSH)
|
||||
return 0;
|
||||
deflateReset(strm);
|
||||
state->reset = 0;
|
||||
@@ -103,10 +108,14 @@ local int gz_comp(gz_statep state, int flush) {
|
||||
if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
|
||||
(flush != Z_FINISH || ret == Z_STREAM_END))) {
|
||||
while (strm->next_out > state->x.next) {
|
||||
errno = 0;
|
||||
state->again = 0;
|
||||
put = strm->next_out - state->x.next > (int)max ? max :
|
||||
(unsigned)(strm->next_out - state->x.next);
|
||||
writ = write(state->fd, state->x.next, put);
|
||||
writ = (int)write(state->fd, state->x.next, put);
|
||||
if (writ < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
state->again = 1;
|
||||
gz_error(state, Z_ERRNO, zstrerror());
|
||||
return -1;
|
||||
}
|
||||
@@ -138,10 +147,12 @@ local int gz_comp(gz_statep state, int flush) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compress len zeros to output. Return -1 on a write error or memory
|
||||
allocation failure by gz_comp(), or 0 on success. */
|
||||
local int gz_zero(gz_statep state, z_off64_t len) {
|
||||
int first;
|
||||
/* Compress state->skip (> 0) zeros to output. Return -1 on a write error or
|
||||
memory allocation failure by gz_comp(), or 0 on success. state->skip is
|
||||
updated with the number of successfully written zeros, in case there is a
|
||||
stall on a non-blocking write destination. */
|
||||
local int gz_zero(gz_statep state) {
|
||||
int first, ret;
|
||||
unsigned n;
|
||||
z_streamp strm = &(state->strm);
|
||||
|
||||
@@ -149,29 +160,34 @@ local int gz_zero(gz_statep state, z_off64_t len) {
|
||||
if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
|
||||
return -1;
|
||||
|
||||
/* compress len zeros (len guaranteed > 0) */
|
||||
/* compress state->skip zeros */
|
||||
first = 1;
|
||||
while (len) {
|
||||
n = GT_OFF(state->size) || (z_off64_t)state->size > len ?
|
||||
(unsigned)len : state->size;
|
||||
do {
|
||||
n = GT_OFF(state->size) || (z_off64_t)state->size > state->skip ?
|
||||
(unsigned)state->skip : state->size;
|
||||
if (first) {
|
||||
memset(state->in, 0, n);
|
||||
first = 0;
|
||||
}
|
||||
strm->avail_in = n;
|
||||
strm->next_in = state->in;
|
||||
ret = gz_comp(state, Z_NO_FLUSH);
|
||||
n -= strm->avail_in;
|
||||
state->x.pos += n;
|
||||
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
||||
state->skip -= n;
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
len -= n;
|
||||
}
|
||||
} while (state->skip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write len bytes from buf to file. Return the number of bytes written. If
|
||||
the returned value is less than len, then there was an error. */
|
||||
the returned value is less than len, then there was an error. If the error
|
||||
was a non-blocking stall, then the number of bytes consumed is returned.
|
||||
For any other error, 0 is returned. */
|
||||
local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
|
||||
z_size_t put = len;
|
||||
int ret;
|
||||
|
||||
/* if len is zero, avoid unnecessary operations */
|
||||
if (len == 0)
|
||||
@@ -182,16 +198,13 @@ local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
|
||||
return 0;
|
||||
|
||||
/* check for seek request */
|
||||
if (state->seek) {
|
||||
state->seek = 0;
|
||||
if (gz_zero(state, state->skip) == -1)
|
||||
return 0;
|
||||
}
|
||||
if (state->skip && gz_zero(state) == -1)
|
||||
return 0;
|
||||
|
||||
/* for small len, copy to input buffer, otherwise compress directly */
|
||||
if (len < state->size) {
|
||||
/* copy to input buffer, compress when full */
|
||||
do {
|
||||
for (;;) {
|
||||
unsigned have, copy;
|
||||
|
||||
if (state->strm.avail_in == 0)
|
||||
@@ -206,9 +219,11 @@ local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
|
||||
state->x.pos += copy;
|
||||
buf = (const char *)buf + copy;
|
||||
len -= copy;
|
||||
if (len && gz_comp(state, Z_NO_FLUSH) == -1)
|
||||
return 0;
|
||||
} while (len);
|
||||
if (len == 0)
|
||||
break;
|
||||
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
||||
return state->again ? put - len : 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* consume whatever's left in the input buffer */
|
||||
@@ -219,13 +234,16 @@ local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
|
||||
state->strm.next_in = (z_const Bytef *)buf;
|
||||
do {
|
||||
unsigned n = (unsigned)-1;
|
||||
|
||||
if (n > len)
|
||||
n = (unsigned)len;
|
||||
state->strm.avail_in = n;
|
||||
ret = gz_comp(state, Z_NO_FLUSH);
|
||||
n -= state->strm.avail_in;
|
||||
state->x.pos += n;
|
||||
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
||||
return 0;
|
||||
len -= n;
|
||||
if (ret == -1)
|
||||
return state->again ? put - len : 0;
|
||||
} while (len);
|
||||
}
|
||||
|
||||
@@ -242,9 +260,10 @@ int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) {
|
||||
return 0;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're writing and that there's no error */
|
||||
if (state->mode != GZ_WRITE || state->err != Z_OK)
|
||||
/* check that we're writing and that there's no (serious) error */
|
||||
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
|
||||
return 0;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* since an int is returned, make sure len fits in one, otherwise return
|
||||
with an error (this avoids a flaw in the interface) */
|
||||
@@ -268,9 +287,10 @@ z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems,
|
||||
return 0;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're writing and that there's no error */
|
||||
if (state->mode != GZ_WRITE || state->err != Z_OK)
|
||||
/* check that we're writing and that there's no (serious) error */
|
||||
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
|
||||
return 0;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* compute bytes to read -- error on overflow */
|
||||
len = nitems * size;
|
||||
@@ -296,16 +316,14 @@ int ZEXPORT gzputc(gzFile file, int c) {
|
||||
state = (gz_statep)file;
|
||||
strm = &(state->strm);
|
||||
|
||||
/* check that we're writing and that there's no error */
|
||||
if (state->mode != GZ_WRITE || state->err != Z_OK)
|
||||
/* check that we're writing and that there's no (serious) error */
|
||||
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
|
||||
return -1;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* check for seek request */
|
||||
if (state->seek) {
|
||||
state->seek = 0;
|
||||
if (gz_zero(state, state->skip) == -1)
|
||||
return -1;
|
||||
}
|
||||
if (state->skip && gz_zero(state) == -1)
|
||||
return -1;
|
||||
|
||||
/* try writing to input buffer for speed (state->size == 0 if buffer not
|
||||
initialized) */
|
||||
@@ -338,9 +356,10 @@ int ZEXPORT gzputs(gzFile file, const char *s) {
|
||||
return -1;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're writing and that there's no error */
|
||||
if (state->mode != GZ_WRITE || state->err != Z_OK)
|
||||
/* check that we're writing and that there's no (serious) error */
|
||||
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
|
||||
return -1;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* write string */
|
||||
len = strlen(s);
|
||||
@@ -349,16 +368,47 @@ int ZEXPORT gzputs(gzFile file, const char *s) {
|
||||
return -1;
|
||||
}
|
||||
put = gz_write(state, s, len);
|
||||
return put < len ? -1 : (int)len;
|
||||
return len && put == 0 ? -1 : (int)put;
|
||||
}
|
||||
|
||||
#if (((!defined(STDC) && !defined(Z_HAVE_STDARG_H)) || !defined(NO_vsnprintf)) && \
|
||||
(defined(STDC) || defined(Z_HAVE_STDARG_H) || !defined(NO_snprintf))) || \
|
||||
defined(ZLIB_INSECURE)
|
||||
/* If the second half of the input buffer is occupied, write out the contents.
|
||||
If there is any input remaining due to a non-blocking stall on write, move
|
||||
it to the start of the buffer. Return true if this did not open up the
|
||||
second half of the buffer. state->err should be checked after this to
|
||||
handle a gz_comp() error. */
|
||||
local int gz_vacate(gz_statep state) {
|
||||
z_streamp strm;
|
||||
|
||||
strm = &(state->strm);
|
||||
if (strm->next_in + strm->avail_in <= state->in + state->size)
|
||||
return 0;
|
||||
(void)gz_comp(state, Z_NO_FLUSH);
|
||||
if (strm->avail_in == 0) {
|
||||
strm->next_in = state->in;
|
||||
return 0;
|
||||
}
|
||||
memmove(state->in, strm->next_in, strm->avail_in);
|
||||
strm->next_in = state->in;
|
||||
return strm->avail_in > state->size;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||
#include <stdarg.h>
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
|
||||
int len;
|
||||
unsigned left;
|
||||
#if defined(NO_vsnprintf) && !defined(ZLIB_INSECURE)
|
||||
#warning "vsnprintf() not available -- gzprintf() stub returns Z_STREAM_ERROR"
|
||||
#warning "you can recompile with ZLIB_INSECURE defined to use vsprintf()"
|
||||
/* prevent use of insecure vsprintf(), unless purposefully requested */
|
||||
(void)file, (void)format, (void)va;
|
||||
return Z_STREAM_ERROR;
|
||||
#else
|
||||
int len, ret;
|
||||
char *next;
|
||||
gz_statep state;
|
||||
z_streamp strm;
|
||||
@@ -369,24 +419,34 @@ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
|
||||
state = (gz_statep)file;
|
||||
strm = &(state->strm);
|
||||
|
||||
/* check that we're writing and that there's no error */
|
||||
if (state->mode != GZ_WRITE || state->err != Z_OK)
|
||||
/* check that we're writing and that there's no (serious) error */
|
||||
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
|
||||
return Z_STREAM_ERROR;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* make sure we have some buffer space */
|
||||
if (state->size == 0 && gz_init(state) == -1)
|
||||
return state->err;
|
||||
|
||||
/* check for seek request */
|
||||
if (state->seek) {
|
||||
state->seek = 0;
|
||||
if (gz_zero(state, state->skip) == -1)
|
||||
return state->err;
|
||||
}
|
||||
if (state->skip && gz_zero(state) == -1)
|
||||
return state->err;
|
||||
|
||||
/* do the printf() into the input buffer, put length in len -- the input
|
||||
buffer is double-sized just for this function, so there is guaranteed to
|
||||
be state->size bytes available after the current contents */
|
||||
buffer is double-sized just for this function, so there should be
|
||||
state->size bytes available after the current contents */
|
||||
ret = gz_vacate(state);
|
||||
if (state->err) {
|
||||
if (ret && state->again) {
|
||||
/* There was a non-blocking stall on write, resulting in the part
|
||||
of the second half of the output buffer being occupied. Return
|
||||
a Z_BUF_ERROR to let the application know that this gzprintf()
|
||||
needs to be retried. */
|
||||
gz_error(state, Z_BUF_ERROR, "stalled write on gzprintf");
|
||||
}
|
||||
if (!state->again)
|
||||
return state->err;
|
||||
}
|
||||
if (strm->avail_in == 0)
|
||||
strm->next_in = state->in;
|
||||
next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in);
|
||||
@@ -412,19 +472,16 @@ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
|
||||
if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0)
|
||||
return 0;
|
||||
|
||||
/* update buffer and position, compress first half if past that */
|
||||
/* update buffer and position */
|
||||
strm->avail_in += (unsigned)len;
|
||||
state->x.pos += len;
|
||||
if (strm->avail_in >= state->size) {
|
||||
left = strm->avail_in - state->size;
|
||||
strm->avail_in = state->size;
|
||||
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
||||
return state->err;
|
||||
memmove(state->in, state->in + state->size, left);
|
||||
strm->next_in = state->in;
|
||||
strm->avail_in = left;
|
||||
}
|
||||
|
||||
/* write out buffer if more than half is occupied */
|
||||
ret = gz_vacate(state);
|
||||
if (state->err && !state->again)
|
||||
return state->err;
|
||||
return len;
|
||||
#endif
|
||||
}
|
||||
|
||||
int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) {
|
||||
@@ -444,6 +501,17 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,
|
||||
int a4, int a5, int a6, int a7, int a8, int a9, int a10,
|
||||
int a11, int a12, int a13, int a14, int a15, int a16,
|
||||
int a17, int a18, int a19, int a20) {
|
||||
#if defined(NO_snprintf) && !defined(ZLIB_INSECURE)
|
||||
#warning "snprintf() not available -- gzprintf() stub returns Z_STREAM_ERROR"
|
||||
#warning "you can recompile with ZLIB_INSECURE defined to use sprintf()"
|
||||
/* prevent use of insecure sprintf(), unless purposefully requested */
|
||||
(void)file, (void)format, (void)a1, (void)a2, (void)a3, (void)a4, (void)a5,
|
||||
(void)a6, (void)a7, (void)a8, (void)a9, (void)a10, (void)a11, (void)a12,
|
||||
(void)a13, (void)a14, (void)a15, (void)a16, (void)a17, (void)a18,
|
||||
(void)a19, (void)a20;
|
||||
return Z_STREAM_ERROR;
|
||||
#else
|
||||
int ret;
|
||||
unsigned len, left;
|
||||
char *next;
|
||||
gz_statep state;
|
||||
@@ -459,24 +527,34 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,
|
||||
if (sizeof(int) != sizeof(void *))
|
||||
return Z_STREAM_ERROR;
|
||||
|
||||
/* check that we're writing and that there's no error */
|
||||
if (state->mode != GZ_WRITE || state->err != Z_OK)
|
||||
/* check that we're writing and that there's no (serious) error */
|
||||
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
|
||||
return Z_STREAM_ERROR;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* make sure we have some buffer space */
|
||||
if (state->size == 0 && gz_init(state) == -1)
|
||||
return state->error;
|
||||
return state->err;
|
||||
|
||||
/* check for seek request */
|
||||
if (state->seek) {
|
||||
state->seek = 0;
|
||||
if (gz_zero(state, state->skip) == -1)
|
||||
return state->error;
|
||||
}
|
||||
if (state->skip && gz_zero(state) == -1)
|
||||
return state->err;
|
||||
|
||||
/* do the printf() into the input buffer, put length in len -- the input
|
||||
buffer is double-sized just for this function, so there is guaranteed to
|
||||
be state->size bytes available after the current contents */
|
||||
ret = gz_vacate(state);
|
||||
if (state->err) {
|
||||
if (ret && state->again) {
|
||||
/* There was a non-blocking stall on write, resulting in the part
|
||||
of the second half of the output buffer being occupied. Return
|
||||
a Z_BUF_ERROR to let the application know that this gzprintf()
|
||||
needs to be retried. */
|
||||
gz_error(state, Z_BUF_ERROR, "stalled write on gzprintf");
|
||||
}
|
||||
if (!state->again)
|
||||
return state->err;
|
||||
}
|
||||
if (strm->avail_in == 0)
|
||||
strm->next_in = state->in;
|
||||
next = (char *)(strm->next_in + strm->avail_in);
|
||||
@@ -510,16 +588,13 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,
|
||||
/* update buffer and position, compress first half if past that */
|
||||
strm->avail_in += len;
|
||||
state->x.pos += len;
|
||||
if (strm->avail_in >= state->size) {
|
||||
left = strm->avail_in - state->size;
|
||||
strm->avail_in = state->size;
|
||||
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
||||
return state->err;
|
||||
memmove(state->in, state->in + state->size, left);
|
||||
strm->next_in = state->in;
|
||||
strm->avail_in = left;
|
||||
}
|
||||
|
||||
/* write out buffer if more than half is occupied */
|
||||
ret = gz_vacate(state);
|
||||
if (state->err && !state->again)
|
||||
return state->err;
|
||||
return (int)len;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -533,20 +608,18 @@ int ZEXPORT gzflush(gzFile file, int flush) {
|
||||
return Z_STREAM_ERROR;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're writing and that there's no error */
|
||||
if (state->mode != GZ_WRITE || state->err != Z_OK)
|
||||
/* check that we're writing and that there's no (serious) error */
|
||||
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
|
||||
return Z_STREAM_ERROR;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* check flush parameter */
|
||||
if (flush < 0 || flush > Z_FINISH)
|
||||
return Z_STREAM_ERROR;
|
||||
|
||||
/* check for seek request */
|
||||
if (state->seek) {
|
||||
state->seek = 0;
|
||||
if (gz_zero(state, state->skip) == -1)
|
||||
return state->err;
|
||||
}
|
||||
if (state->skip && gz_zero(state) == -1)
|
||||
return state->err;
|
||||
|
||||
/* compress remaining data with requested flush */
|
||||
(void)gz_comp(state, flush);
|
||||
@@ -564,20 +637,19 @@ int ZEXPORT gzsetparams(gzFile file, int level, int strategy) {
|
||||
state = (gz_statep)file;
|
||||
strm = &(state->strm);
|
||||
|
||||
/* check that we're writing and that there's no error */
|
||||
if (state->mode != GZ_WRITE || state->err != Z_OK || state->direct)
|
||||
/* check that we're compressing and that there's no (serious) error */
|
||||
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again) ||
|
||||
state->direct)
|
||||
return Z_STREAM_ERROR;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* if no change is requested, then do nothing */
|
||||
if (level == state->level && strategy == state->strategy)
|
||||
return Z_OK;
|
||||
|
||||
/* check for seek request */
|
||||
if (state->seek) {
|
||||
state->seek = 0;
|
||||
if (gz_zero(state, state->skip) == -1)
|
||||
return state->err;
|
||||
}
|
||||
if (state->skip && gz_zero(state) == -1)
|
||||
return state->err;
|
||||
|
||||
/* change compression parameters for subsequent input */
|
||||
if (state->size) {
|
||||
@@ -606,11 +678,8 @@ int ZEXPORT gzclose_w(gzFile file) {
|
||||
return Z_STREAM_ERROR;
|
||||
|
||||
/* check for seek request */
|
||||
if (state->seek) {
|
||||
state->seek = 0;
|
||||
if (gz_zero(state, state->skip) == -1)
|
||||
ret = state->err;
|
||||
}
|
||||
if (state->skip && gz_zero(state) == -1)
|
||||
ret = state->err;
|
||||
|
||||
/* flush, free memory, and close file */
|
||||
if (gz_comp(state, Z_FINISH) == -1)
|
||||
|
||||
+25
-73
@@ -1,5 +1,5 @@
|
||||
/* infback.c -- inflate using a call-back interface
|
||||
* Copyright (C) 1995-2022 Mark Adler
|
||||
* Copyright (C) 1995-2026 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@@ -46,7 +46,7 @@ int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits,
|
||||
#ifdef Z_SOLO
|
||||
return Z_STREAM_ERROR;
|
||||
#else
|
||||
strm->zfree = zcfree;
|
||||
strm->zfree = zcfree;
|
||||
#endif
|
||||
state = (struct inflate_state FAR *)ZALLOC(strm, 1,
|
||||
sizeof(struct inflate_state));
|
||||
@@ -63,57 +63,6 @@ int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits,
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Return state with length and distance decoding tables and index sizes set to
|
||||
fixed code decoding. Normally this returns fixed tables from inffixed.h.
|
||||
If BUILDFIXED is defined, then instead this routine builds the tables the
|
||||
first time it's called, and returns those tables the first time and
|
||||
thereafter. This reduces the size of the code by about 2K bytes, in
|
||||
exchange for a little execution time. However, BUILDFIXED should not be
|
||||
used for threaded applications, since the rewriting of the tables and virgin
|
||||
may not be thread-safe.
|
||||
*/
|
||||
local void fixedtables(struct inflate_state FAR *state) {
|
||||
#ifdef BUILDFIXED
|
||||
static int virgin = 1;
|
||||
static code *lenfix, *distfix;
|
||||
static code fixed[544];
|
||||
|
||||
/* build fixed huffman tables if first call (may not be thread safe) */
|
||||
if (virgin) {
|
||||
unsigned sym, bits;
|
||||
static code *next;
|
||||
|
||||
/* literal/length table */
|
||||
sym = 0;
|
||||
while (sym < 144) state->lens[sym++] = 8;
|
||||
while (sym < 256) state->lens[sym++] = 9;
|
||||
while (sym < 280) state->lens[sym++] = 7;
|
||||
while (sym < 288) state->lens[sym++] = 8;
|
||||
next = fixed;
|
||||
lenfix = next;
|
||||
bits = 9;
|
||||
inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
|
||||
|
||||
/* distance table */
|
||||
sym = 0;
|
||||
while (sym < 32) state->lens[sym++] = 5;
|
||||
distfix = next;
|
||||
bits = 5;
|
||||
inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
|
||||
|
||||
/* do this just once */
|
||||
virgin = 0;
|
||||
}
|
||||
#else /* !BUILDFIXED */
|
||||
# include "inffixed.h"
|
||||
#endif /* BUILDFIXED */
|
||||
state->lencode = lenfix;
|
||||
state->lenbits = 9;
|
||||
state->distcode = distfix;
|
||||
state->distbits = 5;
|
||||
}
|
||||
|
||||
/* Macros for inflateBack(): */
|
||||
|
||||
/* Load returned state from inflate_fast() */
|
||||
@@ -293,7 +242,7 @@ int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc,
|
||||
state->mode = STORED;
|
||||
break;
|
||||
case 1: /* fixed block */
|
||||
fixedtables(state);
|
||||
inflate_fixed(state);
|
||||
Tracev((stderr, "inflate: fixed codes block%s\n",
|
||||
state->last ? " (last)" : ""));
|
||||
state->mode = LEN; /* decode codes */
|
||||
@@ -303,8 +252,8 @@ int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc,
|
||||
state->last ? " (last)" : ""));
|
||||
state->mode = TABLE;
|
||||
break;
|
||||
case 3:
|
||||
strm->msg = (char *)"invalid block type";
|
||||
default:
|
||||
strm->msg = (z_const char *)"invalid block type";
|
||||
state->mode = BAD;
|
||||
}
|
||||
DROPBITS(2);
|
||||
@@ -315,7 +264,7 @@ int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc,
|
||||
BYTEBITS(); /* go to byte boundary */
|
||||
NEEDBITS(32);
|
||||
if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
|
||||
strm->msg = (char *)"invalid stored block lengths";
|
||||
strm->msg = (z_const char *)"invalid stored block lengths";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -353,7 +302,8 @@ int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc,
|
||||
DROPBITS(4);
|
||||
#ifndef PKZIP_BUG_WORKAROUND
|
||||
if (state->nlen > 286 || state->ndist > 30) {
|
||||
strm->msg = (char *)"too many length or distance symbols";
|
||||
strm->msg = (z_const char *)
|
||||
"too many length or distance symbols";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -375,7 +325,7 @@ int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc,
|
||||
ret = inflate_table(CODES, state->lens, 19, &(state->next),
|
||||
&(state->lenbits), state->work);
|
||||
if (ret) {
|
||||
strm->msg = (char *)"invalid code lengths set";
|
||||
strm->msg = (z_const char *)"invalid code lengths set";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -398,7 +348,8 @@ int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc,
|
||||
NEEDBITS(here.bits + 2);
|
||||
DROPBITS(here.bits);
|
||||
if (state->have == 0) {
|
||||
strm->msg = (char *)"invalid bit length repeat";
|
||||
strm->msg = (z_const char *)
|
||||
"invalid bit length repeat";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -421,7 +372,8 @@ int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc,
|
||||
DROPBITS(7);
|
||||
}
|
||||
if (state->have + copy > state->nlen + state->ndist) {
|
||||
strm->msg = (char *)"invalid bit length repeat";
|
||||
strm->msg = (z_const char *)
|
||||
"invalid bit length repeat";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -435,30 +387,31 @@ int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc,
|
||||
|
||||
/* check for end-of-block code (better have one) */
|
||||
if (state->lens[256] == 0) {
|
||||
strm->msg = (char *)"invalid code -- missing end-of-block";
|
||||
strm->msg = (z_const char *)
|
||||
"invalid code -- missing end-of-block";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
|
||||
/* build code tables -- note: do not change the lenbits or distbits
|
||||
values here (9 and 6) without reading the comments in inftrees.h
|
||||
values here (10 and 9) without reading the comments in inftrees.h
|
||||
concerning the ENOUGH constants, which depend on those values */
|
||||
state->next = state->codes;
|
||||
state->lencode = (code const FAR *)(state->next);
|
||||
state->lenbits = 9;
|
||||
state->lenbits = 10;
|
||||
ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
|
||||
&(state->lenbits), state->work);
|
||||
if (ret) {
|
||||
strm->msg = (char *)"invalid literal/lengths set";
|
||||
strm->msg = (z_const char *)"invalid literal/lengths set";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
state->distcode = (code const FAR *)(state->next);
|
||||
state->distbits = 6;
|
||||
state->distbits = 9;
|
||||
ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
|
||||
&(state->next), &(state->distbits), state->work);
|
||||
if (ret) {
|
||||
strm->msg = (char *)"invalid distances set";
|
||||
strm->msg = (z_const char *)"invalid distances set";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -468,10 +421,9 @@ int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc,
|
||||
|
||||
case LEN:
|
||||
/* use inflate_fast() if we have enough input and output */
|
||||
if (have >= 6 && left >= 258) {
|
||||
if (have >= INFLATE_FAST_MIN_INPUT &&
|
||||
left >= INFLATE_FAST_MIN_OUTPUT) {
|
||||
RESTORE();
|
||||
if (state->whave < state->wsize)
|
||||
state->whave = state->wsize - left;
|
||||
inflate_fast(strm, state->wsize);
|
||||
LOAD();
|
||||
break;
|
||||
@@ -517,7 +469,7 @@ int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc,
|
||||
|
||||
/* invalid code */
|
||||
if (here.op & 64) {
|
||||
strm->msg = (char *)"invalid literal/length code";
|
||||
strm->msg = (z_const char *)"invalid literal/length code";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -549,7 +501,7 @@ int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc,
|
||||
}
|
||||
DROPBITS(here.bits);
|
||||
if (here.op & 64) {
|
||||
strm->msg = (char *)"invalid distance code";
|
||||
strm->msg = (z_const char *)"invalid distance code";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -564,7 +516,7 @@ int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc,
|
||||
}
|
||||
if (state->offset > state->wsize - (state->whave < state->wsize ?
|
||||
left : 0)) {
|
||||
strm->msg = (char *)"invalid distance too far back";
|
||||
strm->msg = (z_const char *)"invalid distance too far back";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
|
||||
+22
-14
@@ -1,5 +1,5 @@
|
||||
/* inffast.c -- fast decoding
|
||||
* Copyright (C) 1995-2017 Mark Adler
|
||||
* Copyright (C) 1995-2026 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
available, an end-of-block is encountered, or a data error is encountered.
|
||||
When large enough input and output buffers are supplied to inflate(), for
|
||||
example, a 16K input buffer and a 64K output buffer, more than 95% of the
|
||||
inflate execution time is spent in this routine.
|
||||
inflate() execution time is spent in this routine.
|
||||
|
||||
Entry assumptions:
|
||||
|
||||
state->mode == LEN
|
||||
strm->avail_in >= 6
|
||||
strm->avail_out >= 258
|
||||
strm->avail_in >= INFLATE_FAST_MIN_INPUT (6 bytes)
|
||||
strm->avail_out >= INFLATE_FAST_MIN_OUTPUT (258 bytes)
|
||||
start >= strm->avail_out
|
||||
state->bits < 8
|
||||
|
||||
@@ -36,16 +36,20 @@
|
||||
|
||||
Notes:
|
||||
|
||||
INFLATE_FAST_MIN_INPUT: 6 bytes
|
||||
|
||||
- The maximum input bits used by a length/distance pair is 15 bits for the
|
||||
length code, 5 bits for the length extra, 15 bits for the distance code,
|
||||
and 13 bits for the distance extra. This totals 48 bits, or six bytes.
|
||||
Therefore if strm->avail_in >= 6, then there is enough input to avoid
|
||||
checking for available input while decoding.
|
||||
|
||||
INFLATE_FAST_MIN_OUTPUT: 258 bytes
|
||||
|
||||
- The maximum bytes that a single length/distance pair can output is 258
|
||||
bytes, which is the maximum length that can be coded. inflate_fast()
|
||||
requires strm->avail_out >= 258 for each loop to avoid checking for
|
||||
output space.
|
||||
available output space while decoding.
|
||||
*/
|
||||
void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
|
||||
struct inflate_state FAR *state;
|
||||
@@ -77,10 +81,10 @@ void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
|
||||
/* copy state to local variables */
|
||||
state = (struct inflate_state FAR *)strm->state;
|
||||
in = strm->next_in;
|
||||
last = in + (strm->avail_in - 5);
|
||||
last = in + (strm->avail_in - (INFLATE_FAST_MIN_INPUT - 1));
|
||||
out = strm->next_out;
|
||||
beg = out - (start - strm->avail_out);
|
||||
end = out + (strm->avail_out - 257);
|
||||
end = out + (strm->avail_out - (INFLATE_FAST_MIN_OUTPUT - 1));
|
||||
#ifdef INFLATE_STRICT
|
||||
dmax = state->dmax;
|
||||
#endif
|
||||
@@ -155,7 +159,8 @@ void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
|
||||
dist += (unsigned)hold & ((1U << op) - 1);
|
||||
#ifdef INFLATE_STRICT
|
||||
if (dist > dmax) {
|
||||
strm->msg = (char *)"invalid distance too far back";
|
||||
strm->msg = (z_const char *)
|
||||
"invalid distance too far back";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -168,8 +173,8 @@ void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
|
||||
op = dist - op; /* distance back in window */
|
||||
if (op > whave) {
|
||||
if (state->sane) {
|
||||
strm->msg =
|
||||
(char *)"invalid distance too far back";
|
||||
strm->msg = (z_const char *)
|
||||
"invalid distance too far back";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -265,7 +270,7 @@ void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
|
||||
goto dodist;
|
||||
}
|
||||
else {
|
||||
strm->msg = (char *)"invalid distance code";
|
||||
strm->msg = (z_const char *)"invalid distance code";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -280,7 +285,7 @@ void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
strm->msg = (char *)"invalid literal/length code";
|
||||
strm->msg = (z_const char *)"invalid literal/length code";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -295,9 +300,12 @@ void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
|
||||
/* update state and return */
|
||||
strm->next_in = in;
|
||||
strm->next_out = out;
|
||||
strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
|
||||
strm->avail_in = (unsigned)(in < last ?
|
||||
(INFLATE_FAST_MIN_INPUT - 1) + (last - in) :
|
||||
(INFLATE_FAST_MIN_INPUT - 1) - (in - last));
|
||||
strm->avail_out = (unsigned)(out < end ?
|
||||
257 + (end - out) : 257 - (out - end));
|
||||
(INFLATE_FAST_MIN_OUTPUT - 1) + (end - out) :
|
||||
(INFLATE_FAST_MIN_OUTPUT - 1) - (out - end));
|
||||
state->hold = hold;
|
||||
state->bits = bits;
|
||||
return;
|
||||
|
||||
+15
@@ -8,4 +8,19 @@
|
||||
subject to change. Applications should only use zlib.h.
|
||||
*/
|
||||
|
||||
/* INFLATE_FAST_MIN_INPUT: the minimum number of input bytes needed so that
|
||||
we can safely call inflate_fast() with only one up-front bounds check. One
|
||||
length/distance code pair (15 bits for the length code, 5 bits for length
|
||||
extra, 15 bits for the distance code, 13 bits for distance extra) requires
|
||||
reading up to 48 input bits (6 bytes).
|
||||
*/
|
||||
#define INFLATE_FAST_MIN_INPUT 6
|
||||
|
||||
/* INFLATE_FAST_MIN_OUTPUT: the minimum number of output bytes needed so that
|
||||
we can safely call inflate_fast() with only one up-front bounds check. One
|
||||
length/distance code pair can output up to 258 bytes, which is the maximum
|
||||
length that can be coded.
|
||||
*/
|
||||
#define INFLATE_FAST_MIN_OUTPUT 258
|
||||
|
||||
void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start);
|
||||
|
||||
+91
-91
@@ -1,94 +1,94 @@
|
||||
/* inffixed.h -- table for decoding fixed codes
|
||||
* Generated automatically by makefixed().
|
||||
*/
|
||||
/* inffixed.h -- table for decoding fixed codes
|
||||
* Generated automatically by makefixed().
|
||||
*/
|
||||
|
||||
/* WARNING: this file should *not* be used by applications.
|
||||
It is part of the implementation of this library and is
|
||||
subject to change. Applications should only use zlib.h.
|
||||
*/
|
||||
/* WARNING: this file should *not* be used by applications.
|
||||
It is part of the implementation of this library and is
|
||||
subject to change. Applications should only use zlib.h.
|
||||
*/
|
||||
|
||||
static const code lenfix[512] = {
|
||||
{96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
|
||||
{0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
|
||||
{0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
|
||||
{0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
|
||||
{0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
|
||||
{21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
|
||||
{0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
|
||||
{0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
|
||||
{18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
|
||||
{0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
|
||||
{0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
|
||||
{0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
|
||||
{20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
|
||||
{0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
|
||||
{0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
|
||||
{0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
|
||||
{16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
|
||||
{0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
|
||||
{0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
|
||||
{0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
|
||||
{0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
|
||||
{0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
|
||||
{0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
|
||||
{0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
|
||||
{17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
|
||||
{0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
|
||||
{0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
|
||||
{0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
|
||||
{19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
|
||||
{0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
|
||||
{0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
|
||||
{0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
|
||||
{16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
|
||||
{0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
|
||||
{0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
|
||||
{0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
|
||||
{0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
|
||||
{20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
|
||||
{0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
|
||||
{0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
|
||||
{17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
|
||||
{0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
|
||||
{0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
|
||||
{0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
|
||||
{20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
|
||||
{0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
|
||||
{0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
|
||||
{0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
|
||||
{16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
|
||||
{0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
|
||||
{0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
|
||||
{0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
|
||||
{0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
|
||||
{0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
|
||||
{0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
|
||||
{0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
|
||||
{16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
|
||||
{0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
|
||||
{0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
|
||||
{0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
|
||||
{19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
|
||||
{0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
|
||||
{0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
|
||||
{0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
|
||||
{16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
|
||||
{0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
|
||||
{0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
|
||||
{0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
|
||||
{0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
|
||||
{64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
|
||||
{0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
|
||||
{0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
|
||||
{18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
|
||||
{0,9,255}
|
||||
};
|
||||
static const code lenfix[512] = {
|
||||
{96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
|
||||
{0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
|
||||
{0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
|
||||
{0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
|
||||
{0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
|
||||
{21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
|
||||
{0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
|
||||
{0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
|
||||
{18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
|
||||
{0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
|
||||
{0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
|
||||
{0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
|
||||
{20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
|
||||
{0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
|
||||
{0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
|
||||
{0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
|
||||
{16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
|
||||
{0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
|
||||
{0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
|
||||
{0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
|
||||
{0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
|
||||
{0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
|
||||
{0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
|
||||
{0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
|
||||
{17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
|
||||
{0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
|
||||
{0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
|
||||
{0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
|
||||
{19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
|
||||
{0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
|
||||
{0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
|
||||
{0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
|
||||
{16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
|
||||
{0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
|
||||
{0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
|
||||
{0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
|
||||
{0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
|
||||
{20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
|
||||
{0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
|
||||
{0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
|
||||
{17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
|
||||
{0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
|
||||
{0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
|
||||
{0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
|
||||
{20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
|
||||
{0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
|
||||
{0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
|
||||
{0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
|
||||
{16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
|
||||
{0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
|
||||
{0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
|
||||
{0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
|
||||
{0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
|
||||
{0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
|
||||
{0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
|
||||
{0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
|
||||
{16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
|
||||
{0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
|
||||
{0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
|
||||
{0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
|
||||
{19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
|
||||
{0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
|
||||
{0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
|
||||
{0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
|
||||
{16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
|
||||
{0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
|
||||
{0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
|
||||
{0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
|
||||
{0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
|
||||
{64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
|
||||
{0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
|
||||
{0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
|
||||
{18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
|
||||
{0,9,255}
|
||||
};
|
||||
|
||||
static const code distfix[32] = {
|
||||
{16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
|
||||
{21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
|
||||
{18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
|
||||
{19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
|
||||
{16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
|
||||
{22,5,193},{64,5,0}
|
||||
};
|
||||
static const code distfix[32] = {
|
||||
{16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
|
||||
{21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
|
||||
{18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
|
||||
{19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
|
||||
{16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
|
||||
{22,5,193},{64,5,0}
|
||||
};
|
||||
|
||||
+44
-155
@@ -1,5 +1,5 @@
|
||||
/* inflate.c -- zlib decompression
|
||||
* Copyright (C) 1995-2022 Mark Adler
|
||||
* Copyright (C) 1995-2026 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@@ -85,12 +85,6 @@
|
||||
#include "inflate.h"
|
||||
#include "inffast.h"
|
||||
|
||||
#ifdef MAKEFIXED
|
||||
# ifndef BUILDFIXED
|
||||
# define BUILDFIXED
|
||||
# endif
|
||||
#endif
|
||||
|
||||
local int inflateStateCheck(z_streamp strm) {
|
||||
struct inflate_state FAR *state;
|
||||
if (strm == Z_NULL ||
|
||||
@@ -110,6 +104,7 @@ int ZEXPORT inflateResetKeep(z_streamp strm) {
|
||||
state = (struct inflate_state FAR *)strm->state;
|
||||
strm->total_in = strm->total_out = state->total = 0;
|
||||
strm->msg = Z_NULL;
|
||||
strm->data_type = 0;
|
||||
if (state->wrap) /* to support ill-conceived Java test suite */
|
||||
strm->adler = state->wrap & 1;
|
||||
state->mode = HEAD;
|
||||
@@ -202,11 +197,13 @@ int ZEXPORT inflateInit2_(z_streamp strm, int windowBits,
|
||||
state = (struct inflate_state FAR *)
|
||||
ZALLOC(strm, 1, sizeof(struct inflate_state));
|
||||
if (state == Z_NULL) return Z_MEM_ERROR;
|
||||
zmemzero(state, sizeof(struct inflate_state));
|
||||
Tracev((stderr, "inflate: allocated\n"));
|
||||
strm->state = (struct internal_state FAR *)state;
|
||||
state->strm = strm;
|
||||
state->window = Z_NULL;
|
||||
state->mode = HEAD; /* to pass state test in inflateReset2() */
|
||||
state->check = 1L; /* 1L is the result of adler32() zero length data */
|
||||
ret = inflateReset2(strm, windowBits);
|
||||
if (ret != Z_OK) {
|
||||
ZFREE(strm, state);
|
||||
@@ -234,123 +231,11 @@ int ZEXPORT inflatePrime(z_streamp strm, int bits, int value) {
|
||||
}
|
||||
if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR;
|
||||
value &= (1L << bits) - 1;
|
||||
state->hold += (unsigned)value << state->bits;
|
||||
state->hold += (unsigned long)value << state->bits;
|
||||
state->bits += (uInt)bits;
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Return state with length and distance decoding tables and index sizes set to
|
||||
fixed code decoding. Normally this returns fixed tables from inffixed.h.
|
||||
If BUILDFIXED is defined, then instead this routine builds the tables the
|
||||
first time it's called, and returns those tables the first time and
|
||||
thereafter. This reduces the size of the code by about 2K bytes, in
|
||||
exchange for a little execution time. However, BUILDFIXED should not be
|
||||
used for threaded applications, since the rewriting of the tables and virgin
|
||||
may not be thread-safe.
|
||||
*/
|
||||
local void fixedtables(struct inflate_state FAR *state) {
|
||||
#ifdef BUILDFIXED
|
||||
static int virgin = 1;
|
||||
static code *lenfix, *distfix;
|
||||
static code fixed[544];
|
||||
|
||||
/* build fixed huffman tables if first call (may not be thread safe) */
|
||||
if (virgin) {
|
||||
unsigned sym, bits;
|
||||
static code *next;
|
||||
|
||||
/* literal/length table */
|
||||
sym = 0;
|
||||
while (sym < 144) state->lens[sym++] = 8;
|
||||
while (sym < 256) state->lens[sym++] = 9;
|
||||
while (sym < 280) state->lens[sym++] = 7;
|
||||
while (sym < 288) state->lens[sym++] = 8;
|
||||
next = fixed;
|
||||
lenfix = next;
|
||||
bits = 9;
|
||||
inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
|
||||
|
||||
/* distance table */
|
||||
sym = 0;
|
||||
while (sym < 32) state->lens[sym++] = 5;
|
||||
distfix = next;
|
||||
bits = 5;
|
||||
inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
|
||||
|
||||
/* do this just once */
|
||||
virgin = 0;
|
||||
}
|
||||
#else /* !BUILDFIXED */
|
||||
# include "inffixed.h"
|
||||
#endif /* BUILDFIXED */
|
||||
state->lencode = lenfix;
|
||||
state->lenbits = 9;
|
||||
state->distcode = distfix;
|
||||
state->distbits = 5;
|
||||
}
|
||||
|
||||
#ifdef MAKEFIXED
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also
|
||||
defines BUILDFIXED, so the tables are built on the fly. makefixed() writes
|
||||
those tables to stdout, which would be piped to inffixed.h. A small program
|
||||
can simply call makefixed to do this:
|
||||
|
||||
void makefixed(void);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
makefixed();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Then that can be linked with zlib built with MAKEFIXED defined and run:
|
||||
|
||||
a.out > inffixed.h
|
||||
*/
|
||||
void makefixed(void)
|
||||
{
|
||||
unsigned low, size;
|
||||
struct inflate_state state;
|
||||
|
||||
fixedtables(&state);
|
||||
puts(" /* inffixed.h -- table for decoding fixed codes");
|
||||
puts(" * Generated automatically by makefixed().");
|
||||
puts(" */");
|
||||
puts("");
|
||||
puts(" /* WARNING: this file should *not* be used by applications.");
|
||||
puts(" It is part of the implementation of this library and is");
|
||||
puts(" subject to change. Applications should only use zlib.h.");
|
||||
puts(" */");
|
||||
puts("");
|
||||
size = 1U << 9;
|
||||
printf(" static const code lenfix[%u] = {", size);
|
||||
low = 0;
|
||||
for (;;) {
|
||||
if ((low % 7) == 0) printf("\n ");
|
||||
printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op,
|
||||
state.lencode[low].bits, state.lencode[low].val);
|
||||
if (++low == size) break;
|
||||
putchar(',');
|
||||
}
|
||||
puts("\n };");
|
||||
size = 1U << 5;
|
||||
printf("\n static const code distfix[%u] = {", size);
|
||||
low = 0;
|
||||
for (;;) {
|
||||
if ((low % 6) == 0) printf("\n ");
|
||||
printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
|
||||
state.distcode[low].val);
|
||||
if (++low == size) break;
|
||||
putchar(',');
|
||||
}
|
||||
puts("\n };");
|
||||
}
|
||||
#endif /* MAKEFIXED */
|
||||
|
||||
/*
|
||||
Update the window with the last wsize (normally 32K) bytes written before
|
||||
returning. If window does not exist yet, create it. This is only called
|
||||
@@ -642,12 +527,12 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
if (
|
||||
#endif
|
||||
((BITS(8) << 8) + (hold >> 8)) % 31) {
|
||||
strm->msg = (char *)"incorrect header check";
|
||||
strm->msg = (z_const char *)"incorrect header check";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
if (BITS(4) != Z_DEFLATED) {
|
||||
strm->msg = (char *)"unknown compression method";
|
||||
strm->msg = (z_const char *)"unknown compression method";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -656,7 +541,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
if (state->wbits == 0)
|
||||
state->wbits = len;
|
||||
if (len > 15 || len > state->wbits) {
|
||||
strm->msg = (char *)"invalid window size";
|
||||
strm->msg = (z_const char *)"invalid window size";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -672,12 +557,12 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
NEEDBITS(16);
|
||||
state->flags = (int)(hold);
|
||||
if ((state->flags & 0xff) != Z_DEFLATED) {
|
||||
strm->msg = (char *)"unknown compression method";
|
||||
strm->msg = (z_const char *)"unknown compression method";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
if (state->flags & 0xe000) {
|
||||
strm->msg = (char *)"unknown header flags set";
|
||||
strm->msg = (z_const char *)"unknown header flags set";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -793,7 +678,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
if (state->flags & 0x0200) {
|
||||
NEEDBITS(16);
|
||||
if ((state->wrap & 4) && hold != (state->check & 0xffff)) {
|
||||
strm->msg = (char *)"header crc mismatch";
|
||||
strm->msg = (z_const char *)"header crc mismatch";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -840,7 +725,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
state->mode = STORED;
|
||||
break;
|
||||
case 1: /* fixed block */
|
||||
fixedtables(state);
|
||||
inflate_fixed(state);
|
||||
Tracev((stderr, "inflate: fixed codes block%s\n",
|
||||
state->last ? " (last)" : ""));
|
||||
state->mode = LEN_; /* decode codes */
|
||||
@@ -854,8 +739,8 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
state->last ? " (last)" : ""));
|
||||
state->mode = TABLE;
|
||||
break;
|
||||
case 3:
|
||||
strm->msg = (char *)"invalid block type";
|
||||
default:
|
||||
strm->msg = (z_const char *)"invalid block type";
|
||||
state->mode = BAD;
|
||||
}
|
||||
DROPBITS(2);
|
||||
@@ -864,7 +749,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
BYTEBITS(); /* go to byte boundary */
|
||||
NEEDBITS(32);
|
||||
if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
|
||||
strm->msg = (char *)"invalid stored block lengths";
|
||||
strm->msg = (z_const char *)"invalid stored block lengths";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -905,7 +790,8 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
DROPBITS(4);
|
||||
#ifndef PKZIP_BUG_WORKAROUND
|
||||
if (state->nlen > 286 || state->ndist > 30) {
|
||||
strm->msg = (char *)"too many length or distance symbols";
|
||||
strm->msg = (z_const char *)
|
||||
"too many length or distance symbols";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -923,12 +809,12 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
while (state->have < 19)
|
||||
state->lens[order[state->have++]] = 0;
|
||||
state->next = state->codes;
|
||||
state->lencode = (const code FAR *)(state->next);
|
||||
state->lencode = state->distcode = (const code FAR *)(state->next);
|
||||
state->lenbits = 7;
|
||||
ret = inflate_table(CODES, state->lens, 19, &(state->next),
|
||||
&(state->lenbits), state->work);
|
||||
if (ret) {
|
||||
strm->msg = (char *)"invalid code lengths set";
|
||||
strm->msg = (z_const char *)"invalid code lengths set";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -952,7 +838,8 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
NEEDBITS(here.bits + 2);
|
||||
DROPBITS(here.bits);
|
||||
if (state->have == 0) {
|
||||
strm->msg = (char *)"invalid bit length repeat";
|
||||
strm->msg = (z_const char *)
|
||||
"invalid bit length repeat";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -975,7 +862,8 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
DROPBITS(7);
|
||||
}
|
||||
if (state->have + copy > state->nlen + state->ndist) {
|
||||
strm->msg = (char *)"invalid bit length repeat";
|
||||
strm->msg = (z_const char *)
|
||||
"invalid bit length repeat";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -989,30 +877,31 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
|
||||
/* check for end-of-block code (better have one) */
|
||||
if (state->lens[256] == 0) {
|
||||
strm->msg = (char *)"invalid code -- missing end-of-block";
|
||||
strm->msg = (z_const char *)
|
||||
"invalid code -- missing end-of-block";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
|
||||
/* build code tables -- note: do not change the lenbits or distbits
|
||||
values here (9 and 6) without reading the comments in inftrees.h
|
||||
values here (10 and 9) without reading the comments in inftrees.h
|
||||
concerning the ENOUGH constants, which depend on those values */
|
||||
state->next = state->codes;
|
||||
state->lencode = (const code FAR *)(state->next);
|
||||
state->lenbits = 9;
|
||||
state->lenbits = 10;
|
||||
ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
|
||||
&(state->lenbits), state->work);
|
||||
if (ret) {
|
||||
strm->msg = (char *)"invalid literal/lengths set";
|
||||
strm->msg = (z_const char *)"invalid literal/lengths set";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
state->distcode = (const code FAR *)(state->next);
|
||||
state->distbits = 6;
|
||||
state->distbits = 9;
|
||||
ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
|
||||
&(state->next), &(state->distbits), state->work);
|
||||
if (ret) {
|
||||
strm->msg = (char *)"invalid distances set";
|
||||
strm->msg = (z_const char *)"invalid distances set";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -1024,7 +913,8 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
state->mode = LEN;
|
||||
/* fallthrough */
|
||||
case LEN:
|
||||
if (have >= 6 && left >= 258) {
|
||||
if (have >= INFLATE_FAST_MIN_INPUT &&
|
||||
left >= INFLATE_FAST_MIN_OUTPUT) {
|
||||
RESTORE();
|
||||
inflate_fast(strm, out);
|
||||
LOAD();
|
||||
@@ -1066,7 +956,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
break;
|
||||
}
|
||||
if (here.op & 64) {
|
||||
strm->msg = (char *)"invalid literal/length code";
|
||||
strm->msg = (z_const char *)"invalid literal/length code";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -1104,7 +994,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
DROPBITS(here.bits);
|
||||
state->back += here.bits;
|
||||
if (here.op & 64) {
|
||||
strm->msg = (char *)"invalid distance code";
|
||||
strm->msg = (z_const char *)"invalid distance code";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -1121,7 +1011,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
}
|
||||
#ifdef INFLATE_STRICT
|
||||
if (state->offset > state->dmax) {
|
||||
strm->msg = (char *)"invalid distance too far back";
|
||||
strm->msg = (z_const char *)"invalid distance too far back";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -1136,7 +1026,8 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
copy = state->offset - copy;
|
||||
if (copy > state->whave) {
|
||||
if (state->sane) {
|
||||
strm->msg = (char *)"invalid distance too far back";
|
||||
strm->msg = (z_const char *)
|
||||
"invalid distance too far back";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -1195,7 +1086,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
state->flags ? hold :
|
||||
#endif
|
||||
ZSWAP32(hold)) != state->check) {
|
||||
strm->msg = (char *)"incorrect data check";
|
||||
strm->msg = (z_const char *)"incorrect data check";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -1209,7 +1100,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||
if (state->wrap && state->flags) {
|
||||
NEEDBITS(32);
|
||||
if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) {
|
||||
strm->msg = (char *)"incorrect length check";
|
||||
strm->msg = (z_const char *)"incorrect length check";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
}
|
||||
@@ -1440,7 +1331,6 @@ int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) {
|
||||
struct inflate_state FAR *state;
|
||||
struct inflate_state FAR *copy;
|
||||
unsigned char FAR *window;
|
||||
unsigned wsize;
|
||||
|
||||
/* check input */
|
||||
if (inflateStateCheck(source) || dest == Z_NULL)
|
||||
@@ -1451,6 +1341,7 @@ int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) {
|
||||
copy = (struct inflate_state FAR *)
|
||||
ZALLOC(source, 1, sizeof(struct inflate_state));
|
||||
if (copy == Z_NULL) return Z_MEM_ERROR;
|
||||
zmemzero(copy, sizeof(struct inflate_state));
|
||||
window = Z_NULL;
|
||||
if (state->window != Z_NULL) {
|
||||
window = (unsigned char FAR *)
|
||||
@@ -1462,8 +1353,8 @@ int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) {
|
||||
}
|
||||
|
||||
/* copy state */
|
||||
zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
|
||||
zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state));
|
||||
zmemcpy(dest, source, sizeof(z_stream));
|
||||
zmemcpy(copy, state, sizeof(struct inflate_state));
|
||||
copy->strm = dest;
|
||||
if (state->lencode >= state->codes &&
|
||||
state->lencode <= state->codes + ENOUGH - 1) {
|
||||
@@ -1471,10 +1362,8 @@ int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) {
|
||||
copy->distcode = copy->codes + (state->distcode - state->codes);
|
||||
}
|
||||
copy->next = copy->codes + (state->next - state->codes);
|
||||
if (window != Z_NULL) {
|
||||
wsize = 1U << state->wbits;
|
||||
zmemcpy(window, state->window, wsize);
|
||||
}
|
||||
if (window != Z_NULL)
|
||||
zmemcpy(window, state->window, state->whave);
|
||||
copy->window = window;
|
||||
dest->state = (struct internal_state FAR *)copy;
|
||||
return Z_OK;
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ struct inflate_state {
|
||||
unsigned char FAR *window; /* allocated sliding window, if needed */
|
||||
/* bit accumulator */
|
||||
unsigned long hold; /* input bit accumulator */
|
||||
unsigned bits; /* number of bits in "in" */
|
||||
unsigned bits; /* number of bits in hold */
|
||||
/* for string and stored block copying */
|
||||
unsigned length; /* literal or length of data to copy */
|
||||
unsigned offset; /* distance back to copy string from */
|
||||
|
||||
+134
-9
@@ -1,15 +1,29 @@
|
||||
/* inftrees.c -- generate Huffman trees for efficient decoding
|
||||
* Copyright (C) 1995-2024 Mark Adler
|
||||
* Copyright (C) 1995-2026 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
#ifdef MAKEFIXED
|
||||
# ifndef BUILDFIXED
|
||||
# define BUILDFIXED
|
||||
# endif
|
||||
#endif
|
||||
#ifdef BUILDFIXED
|
||||
# define Z_ONCE
|
||||
#endif
|
||||
|
||||
#include "zutil.h"
|
||||
#include "inftrees.h"
|
||||
#include "inflate.h"
|
||||
|
||||
#ifndef NULL
|
||||
# define NULL 0
|
||||
#endif
|
||||
|
||||
#define MAXBITS 15
|
||||
|
||||
const char inflate_copyright[] =
|
||||
" inflate 1.3.1 Copyright 1995-2024 Mark Adler ";
|
||||
" inflate 1.3.2.1 Copyright 1995-2026 Mark Adler ";
|
||||
/*
|
||||
If you use the zlib library in a product, an acknowledgment is welcome
|
||||
in the documentation of your product. If for some reason you cannot
|
||||
@@ -47,9 +61,9 @@ int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
|
||||
unsigned mask; /* mask for low root bits */
|
||||
code here; /* table entry for duplication */
|
||||
code FAR *next; /* next available space in table */
|
||||
const unsigned short FAR *base; /* base value table to use */
|
||||
const unsigned short FAR *extra; /* extra bits table to use */
|
||||
unsigned match; /* use base and extra for symbol >= match */
|
||||
const unsigned short FAR *base = NULL; /* base value table to use */
|
||||
const unsigned short FAR *extra = NULL; /* extra bits table to use */
|
||||
unsigned match = 0; /* use base and extra for symbol >= match */
|
||||
unsigned short count[MAXBITS+1]; /* number of codes of each length */
|
||||
unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
|
||||
static const unsigned short lbase[31] = { /* Length codes 257..285 base */
|
||||
@@ -57,7 +71,7 @@ int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
|
||||
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
|
||||
static const unsigned short lext[31] = { /* Length codes 257..285 extra */
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
|
||||
19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 203, 77};
|
||||
19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 68, 193};
|
||||
static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
|
||||
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
|
||||
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
|
||||
@@ -175,7 +189,6 @@ int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
|
||||
/* set up for code type */
|
||||
switch (type) {
|
||||
case CODES:
|
||||
base = extra = work; /* dummy value--not used */
|
||||
match = 20;
|
||||
break;
|
||||
case LENS:
|
||||
@@ -183,10 +196,9 @@ int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
|
||||
extra = lext;
|
||||
match = 257;
|
||||
break;
|
||||
default: /* DISTS */
|
||||
case DISTS:
|
||||
base = dbase;
|
||||
extra = dext;
|
||||
match = 0;
|
||||
}
|
||||
|
||||
/* initialize state for loop */
|
||||
@@ -297,3 +309,116 @@ int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
|
||||
*bits = root;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef BUILDFIXED
|
||||
/*
|
||||
If this is compiled with BUILDFIXED defined, and if inflate will be used in
|
||||
multiple threads, and if atomics are not available, then inflate() must be
|
||||
called with a fixed block (e.g. 0x03 0x00) to initialize the tables and must
|
||||
return before any other threads are allowed to call inflate.
|
||||
*/
|
||||
|
||||
static code *lenfix, *distfix;
|
||||
static code fixed[544];
|
||||
|
||||
/* State for z_once(). */
|
||||
local z_once_t built = Z_ONCE_INIT;
|
||||
|
||||
local void buildtables(void) {
|
||||
unsigned sym, bits;
|
||||
static code *next;
|
||||
unsigned short lens[288], work[288];
|
||||
|
||||
/* literal/length table */
|
||||
sym = 0;
|
||||
while (sym < 144) lens[sym++] = 8;
|
||||
while (sym < 256) lens[sym++] = 9;
|
||||
while (sym < 280) lens[sym++] = 7;
|
||||
while (sym < 288) lens[sym++] = 8;
|
||||
next = fixed;
|
||||
lenfix = next;
|
||||
bits = 9;
|
||||
inflate_table(LENS, lens, 288, &(next), &(bits), work);
|
||||
|
||||
/* distance table */
|
||||
sym = 0;
|
||||
while (sym < 32) lens[sym++] = 5;
|
||||
distfix = next;
|
||||
bits = 5;
|
||||
inflate_table(DISTS, lens, 32, &(next), &(bits), work);
|
||||
}
|
||||
#else /* !BUILDFIXED */
|
||||
# include "inffixed.h"
|
||||
#endif /* BUILDFIXED */
|
||||
|
||||
/*
|
||||
Return state with length and distance decoding tables and index sizes set to
|
||||
fixed code decoding. Normally this returns fixed tables from inffixed.h.
|
||||
If BUILDFIXED is defined, then instead this routine builds the tables the
|
||||
first time it's called, and returns those tables the first time and
|
||||
thereafter. This reduces the size of the code by about 2K bytes, in
|
||||
exchange for a little execution time. However, BUILDFIXED should not be
|
||||
used for threaded applications if atomics are not available, as it will
|
||||
not be thread-safe.
|
||||
*/
|
||||
void inflate_fixed(struct inflate_state FAR *state) {
|
||||
#ifdef BUILDFIXED
|
||||
z_once(&built, buildtables);
|
||||
#endif /* BUILDFIXED */
|
||||
state->lencode = lenfix;
|
||||
state->lenbits = 9;
|
||||
state->distcode = distfix;
|
||||
state->distbits = 5;
|
||||
}
|
||||
|
||||
#ifdef MAKEFIXED
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
Write out the inffixed.h that will be #include'd above. Defining MAKEFIXED
|
||||
also defines BUILDFIXED, so the tables are built on the fly. main() writes
|
||||
those tables to stdout, which would directed to inffixed.h. Compile this
|
||||
along with zutil.c:
|
||||
|
||||
cc -DMAKEFIXED -o fix inftrees.c zutil.c
|
||||
./fix > inffixed.h
|
||||
*/
|
||||
int main(void) {
|
||||
unsigned low, size;
|
||||
struct inflate_state state;
|
||||
|
||||
inflate_fixed(&state);
|
||||
puts("/* inffixed.h -- table for decoding fixed codes");
|
||||
puts(" * Generated automatically by makefixed().");
|
||||
puts(" */");
|
||||
puts("");
|
||||
puts("/* WARNING: this file should *not* be used by applications.");
|
||||
puts(" It is part of the implementation of this library and is");
|
||||
puts(" subject to change. Applications should only use zlib.h.");
|
||||
puts(" */");
|
||||
puts("");
|
||||
size = 1U << 9;
|
||||
printf("static const code lenfix[%u] = {", size);
|
||||
low = 0;
|
||||
for (;;) {
|
||||
if ((low % 7) == 0) printf("\n ");
|
||||
printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op,
|
||||
state.lencode[low].bits, state.lencode[low].val);
|
||||
if (++low == size) break;
|
||||
putchar(',');
|
||||
}
|
||||
puts("\n};");
|
||||
size = 1U << 5;
|
||||
printf("\nstatic const code distfix[%u] = {", size);
|
||||
low = 0;
|
||||
for (;;) {
|
||||
if ((low % 6) == 0) printf("\n ");
|
||||
printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
|
||||
state.distcode[low].val);
|
||||
if (++low == size) break;
|
||||
putchar(',');
|
||||
}
|
||||
puts("\n};");
|
||||
return 0;
|
||||
}
|
||||
#endif /* MAKEFIXED */
|
||||
|
||||
+8
-6
@@ -1,5 +1,5 @@
|
||||
/* inftrees.h -- header to use inftrees.c
|
||||
* Copyright (C) 1995-2005, 2010 Mark Adler
|
||||
* Copyright (C) 1995-2026 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@@ -36,17 +36,17 @@ typedef struct {
|
||||
*/
|
||||
|
||||
/* Maximum size of the dynamic table. The maximum number of code structures is
|
||||
1444, which is the sum of 852 for literal/length codes and 592 for distance
|
||||
1924, which is the sum of 1332 for literal/length codes and 592 for distance
|
||||
codes. These values were found by exhaustive searches using the program
|
||||
examples/enough.c found in the zlib distribution. The arguments to that
|
||||
program are the number of symbols, the initial root table size, and the
|
||||
maximum bit length of a code. "enough 286 9 15" for literal/length codes
|
||||
returns 852, and "enough 30 6 15" for distance codes returns 592. The
|
||||
initial root table size (9 or 6) is found in the fifth argument of the
|
||||
maximum bit length of a code. "enough 286 10 15" for literal/length codes
|
||||
returns 1332, and "enough 30 9 15" for distance codes returns 592.
|
||||
The initial root table size (10 or 9) is found in the fifth argument of the
|
||||
inflate_table() calls in inflate.c and infback.c. If the root table size is
|
||||
changed, then these maximum sizes would be need to be recalculated and
|
||||
updated. */
|
||||
#define ENOUGH_LENS 852
|
||||
#define ENOUGH_LENS 1332
|
||||
#define ENOUGH_DISTS 592
|
||||
#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)
|
||||
|
||||
@@ -60,3 +60,5 @@ typedef enum {
|
||||
int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
|
||||
unsigned codes, code FAR * FAR *table,
|
||||
unsigned FAR *bits, unsigned short FAR *work);
|
||||
struct inflate_state;
|
||||
void ZLIB_INTERNAL inflate_fixed(struct inflate_state FAR *state);
|
||||
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
/* slide_hash_simd.h
|
||||
*
|
||||
* Copyright 2022 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SLIDE_HASH_SIMD_H
|
||||
#define SLIDE_HASH_SIMD_H
|
||||
|
||||
#include "deflate.h"
|
||||
|
||||
#ifndef INLINE
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define INLINE __inline
|
||||
#else
|
||||
#define INLINE inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CPU_NO_SIMD)
|
||||
|
||||
#error SIMD has been disabled for your build target
|
||||
|
||||
#elif defined(DEFLATE_SLIDE_HASH_SSE2)
|
||||
|
||||
#include <emmintrin.h> /* SSE2 */
|
||||
|
||||
#define Z_SLIDE_INIT_SIMD(wsize) _mm_set1_epi16((ush)(wsize))
|
||||
|
||||
#define Z_SLIDE_HASH_SIMD(table, size, vector_wsize) \
|
||||
for (const Posf* const end = table + size; table != end;) { \
|
||||
__m128i vO = _mm_loadu_si128((__m128i *)(table + 0)); \
|
||||
vO = _mm_subs_epu16(vO, vector_wsize); \
|
||||
_mm_storeu_si128((__m128i *)(table + 0), vO); \
|
||||
table += 8; \
|
||||
}
|
||||
|
||||
typedef __m128i z_vec128i_u16x8_t;
|
||||
|
||||
#elif defined(DEFLATE_SLIDE_HASH_NEON)
|
||||
|
||||
#include <arm_neon.h> /* NEON */
|
||||
|
||||
#define Z_SLIDE_INIT_SIMD(wsize) vdupq_n_u16((ush)(wsize))
|
||||
|
||||
#define Z_SLIDE_HASH_SIMD(table, size, vector_wsize) \
|
||||
for (const Posf* const end = table + size; table != end;) { \
|
||||
uint16x8_t vO = vld1q_u16(table + 0); \
|
||||
uint16x8_t v8 = vld1q_u16(table + 8); \
|
||||
vO = vqsubq_u16(vO, vector_wsize); \
|
||||
v8 = vqsubq_u16(v8, vector_wsize); \
|
||||
vst1q_u16(table + 0, vO); \
|
||||
vst1q_u16(table + 8, v8); \
|
||||
table += 8 + 8; \
|
||||
}
|
||||
|
||||
typedef uint16x8_t z_vec128i_u16x8_t;
|
||||
|
||||
#else
|
||||
|
||||
#error slide_hash_simd is not defined for your build target
|
||||
|
||||
#endif
|
||||
|
||||
/* ===========================================================================
|
||||
* Slide the hash table when sliding the window down (could be avoided with 32
|
||||
* bit values at the expense of memory usage). We slide even when level == 0 to
|
||||
* keep the hash table consistent if we switch back to level > 0 later.
|
||||
*/
|
||||
local INLINE void slide_hash_simd(
|
||||
Posf *head, Posf *prev, const uInt w_size, const uInt hash_size) {
|
||||
/*
|
||||
* The SIMD implementation of the hash table slider assumes:
|
||||
*
|
||||
* 1. hash chain offset is 2 bytes. Should be true as Pos is "ush" type.
|
||||
*/
|
||||
Assert(sizeof(Pos) == 2, "Pos type size error: should be 2 bytes");
|
||||
Assert(sizeof(ush) == 2, "ush type size error: should be 2 bytes");
|
||||
|
||||
Assert(hash_size <= (1 << 16), "Hash table maximum size error");
|
||||
Assert(hash_size >= (1 << 8), "Hash table minimum size error");
|
||||
Assert(w_size == (ush)w_size, "Prev table size error");
|
||||
|
||||
/*
|
||||
* 2. The hash & prev table sizes are a multiple of 32 bytes (256 bits),
|
||||
* since the NEON table slider moves two 128-bit items per loop (loop is
|
||||
* unrolled on NEON for performance, see http://crbug.com/863257).
|
||||
*/
|
||||
Assert(!((hash_size * sizeof(head[0])) & (32 - 1)),
|
||||
"Hash table size error: should be a multiple of 32 bytes");
|
||||
Assert(!((w_size * sizeof(prev[0])) & (32 - 1)),
|
||||
"Prev table size error: should be a multiple of 32 bytes");
|
||||
|
||||
/*
|
||||
* Duplicate (ush)w_size in each uint16_t component of a 128-bit vector.
|
||||
*/
|
||||
const z_vec128i_u16x8_t vec_wsize = Z_SLIDE_INIT_SIMD(w_size);
|
||||
|
||||
/*
|
||||
* Slide {head,prev} hash chain values: subtracts (ush)w_size from every
|
||||
* value with a saturating SIMD subtract, to clamp the result to 0(NIL),
|
||||
* to implement slide_hash() `(m >= wsize ? m - wsize : NIL);` code.
|
||||
*/
|
||||
Z_SLIDE_HASH_SIMD(head, hash_size, vec_wsize);
|
||||
#ifndef FASTEST
|
||||
Z_SLIDE_HASH_SIMD(prev, w_size, vec_wsize);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#undef z_vec128i_u16x8_t
|
||||
#undef Z_SLIDE_HASH_SIMD
|
||||
#undef Z_SLIDE_INIT_SIMD
|
||||
|
||||
#endif /* SLIDE_HASH_SIMD_H */
|
||||
Vendored
+64
-18
@@ -1,5 +1,5 @@
|
||||
/* trees.c -- output deflated data using Huffman coding
|
||||
* Copyright (C) 1995-2024 Jean-loup Gailly
|
||||
* Copyright (C) 1995-2026 Jean-loup Gailly
|
||||
* detect_data_type() function provided freely by Cosmin Truta, 2006
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
@@ -112,7 +112,7 @@ local int base_dist[D_CODES];
|
||||
|
||||
#else
|
||||
# include "trees.h"
|
||||
#endif /* GEN_TREES_H */
|
||||
#endif /* defined(GEN_TREES_H) || !defined(STDC) */
|
||||
|
||||
struct static_tree_desc_s {
|
||||
const ct_data *static_tree; /* static tree or NULL */
|
||||
@@ -141,18 +141,25 @@ local TCONST static_tree_desc static_bl_desc =
|
||||
* Output a short LSB first on the stream.
|
||||
* IN assertion: there is enough room in pendingBuf.
|
||||
*/
|
||||
#if defined(DEFLATE_CHUNK_WRITE_64LE)
|
||||
#define put_short(s, w) { \
|
||||
uint16_t data = (uint16_t)(w); \
|
||||
zmemcpy(&s->pending_buf[s->pending], &data, sizeof(data)); \
|
||||
s->pending += 2; \
|
||||
}
|
||||
#else
|
||||
#define put_short(s, w) { \
|
||||
put_byte(s, (uch)((w) & 0xff)); \
|
||||
put_byte(s, (uch)((ush)(w) >> 8)); \
|
||||
}
|
||||
|
||||
#endif /* DEFLATE_CHUNK_WRITE_64LE */
|
||||
/* ===========================================================================
|
||||
* Reverse the first len bits of a code, using straightforward code (a faster
|
||||
* method would use a table)
|
||||
* IN assertion: 1 <= len <= 15
|
||||
*/
|
||||
local unsigned bi_reverse(unsigned code, int len) {
|
||||
register unsigned res = 0;
|
||||
unsigned res = 0;
|
||||
do {
|
||||
res |= code & 1;
|
||||
code >>= 1, res <<= 1;
|
||||
@@ -164,6 +171,13 @@ local unsigned bi_reverse(unsigned code, int len) {
|
||||
* Flush the bit buffer, keeping at most 7 bits in it.
|
||||
*/
|
||||
local void bi_flush(deflate_state *s) {
|
||||
#if defined(DEFLATE_CHUNK_WRITE_64LE)
|
||||
while (s->bi_valid >= 16) {
|
||||
put_short(s, s->bi_buf);
|
||||
s->bi_buf >>= 16;
|
||||
s->bi_valid -= 16;
|
||||
}
|
||||
#endif /* DEFLATE_CHUNK_WRITE_64LE */
|
||||
if (s->bi_valid == 16) {
|
||||
put_short(s, s->bi_buf);
|
||||
s->bi_buf = 0;
|
||||
@@ -173,21 +187,31 @@ local void bi_flush(deflate_state *s) {
|
||||
s->bi_buf >>= 8;
|
||||
s->bi_valid -= 8;
|
||||
}
|
||||
|
||||
Assert(s->bi_valid >= 0 && s->bi_valid <= 7, "bad bi_flush");
|
||||
}
|
||||
|
||||
/* ===========================================================================
|
||||
* Flush the bit buffer and align the output on a byte boundary
|
||||
*/
|
||||
local void bi_windup(deflate_state *s) {
|
||||
#if defined(DEFLATE_CHUNK_WRITE_64LE)
|
||||
while (s->bi_valid >= 16) {
|
||||
put_short(s, s->bi_buf);
|
||||
s->bi_buf >>= 16;
|
||||
s->bi_valid -= 16;
|
||||
}
|
||||
#endif /* DEFLATE_CHUNK_WRITE_64LE */
|
||||
if (s->bi_valid > 8) {
|
||||
put_short(s, s->bi_buf);
|
||||
} else if (s->bi_valid > 0) {
|
||||
put_byte(s, (Byte)s->bi_buf);
|
||||
}
|
||||
s->bi_used = ((s->bi_valid - 1) & 7) + 1;
|
||||
s->bi_buf = 0;
|
||||
s->bi_valid = 0;
|
||||
#ifdef ZLIB_DEBUG
|
||||
s->bits_sent = (s->bits_sent + 7) & ~7;
|
||||
s->bits_sent = (s->bits_sent + 7) & ~(ulg)7;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -248,7 +272,28 @@ local void gen_trees_header(void);
|
||||
* Send a value on a given number of bits.
|
||||
* IN assertion: length <= 16 and value fits in length bits.
|
||||
*/
|
||||
#if defined(DEFLATE_CHUNK_WRITE_64LE)
|
||||
local void send_bits(deflate_state *s, uint64_t value, int length)
|
||||
{
|
||||
Tracevv((stderr," l %2d v %4llx ", length, (unsigned long long)value));
|
||||
Assert(s->bi_valid >= 0 && s->bi_valid <= 63, "invalid bi_valid");
|
||||
Assert(length > 0 && length <= 15, "invalid length");
|
||||
#ifdef ZLIB_DEBUG
|
||||
s->bits_sent += (ulg)length;
|
||||
#endif
|
||||
|
||||
s->bi_buf |= (value << s->bi_valid);
|
||||
s->bi_valid += length;
|
||||
|
||||
if (s->bi_valid >= Buf_size) {
|
||||
zmemcpy(&s->pending_buf[s->pending], &s->bi_buf, sizeof(s->bi_buf));
|
||||
s->pending += 8;
|
||||
s->bi_valid -= Buf_size;
|
||||
s->bi_buf = value >> (length - s->bi_valid);
|
||||
}
|
||||
Assert(s->bi_valid >= 0 && s->bi_valid <= 63, "invalid bi_valid");
|
||||
}
|
||||
#elif defined(ZLIB_DEBUG)
|
||||
local void send_bits(deflate_state *s, int value, int length) {
|
||||
Tracevv((stderr," l %2d v %4x ", length, value));
|
||||
Assert(length > 0 && length <= 15, "invalid length");
|
||||
@@ -268,8 +313,7 @@ local void send_bits(deflate_state *s, int value, int length) {
|
||||
s->bi_valid += length;
|
||||
}
|
||||
}
|
||||
#else /* !ZLIB_DEBUG */
|
||||
|
||||
#else /* !ZLIB_DEBUG && !DEFLATE_CHUNK_WRITE_64LE */
|
||||
#define send_bits(s, value, length) \
|
||||
{ int len = length;\
|
||||
if (s->bi_valid > (int)Buf_size - len) {\
|
||||
@@ -283,7 +327,7 @@ local void send_bits(deflate_state *s, int value, int length) {
|
||||
s->bi_valid += len;\
|
||||
}\
|
||||
}
|
||||
#endif /* ZLIB_DEBUG */
|
||||
#endif /* DEFLATE_CHUNK_WRITE_64LE */
|
||||
|
||||
|
||||
/* the arguments must not have side effects */
|
||||
@@ -466,6 +510,7 @@ void ZLIB_INTERNAL _tr_init(deflate_state *s) {
|
||||
|
||||
s->bi_buf = 0;
|
||||
s->bi_valid = 0;
|
||||
s->bi_used = 0;
|
||||
#ifdef ZLIB_DEBUG
|
||||
s->compressed_len = 0L;
|
||||
s->bits_sent = 0L;
|
||||
@@ -724,7 +769,7 @@ local void scan_tree(deflate_state *s, ct_data *tree, int max_code) {
|
||||
if (++count < max_count && curlen == nextlen) {
|
||||
continue;
|
||||
} else if (count < min_count) {
|
||||
s->bl_tree[curlen].Freq += count;
|
||||
s->bl_tree[curlen].Freq += (ush)count;
|
||||
} else if (curlen != 0) {
|
||||
if (curlen != prevlen) s->bl_tree[curlen].Freq++;
|
||||
s->bl_tree[REP_3_6].Freq++;
|
||||
@@ -817,7 +862,7 @@ local int build_bl_tree(deflate_state *s) {
|
||||
}
|
||||
/* Update opt_len to include the bit length tree and counts */
|
||||
s->opt_len += 3*((ulg)max_blindex + 1) + 5 + 5 + 4;
|
||||
Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
|
||||
Tracev((stderr, "\ndyn trees: dyn %lu, stat %lu",
|
||||
s->opt_len, s->static_len));
|
||||
|
||||
return max_blindex;
|
||||
@@ -843,13 +888,13 @@ local void send_all_trees(deflate_state *s, int lcodes, int dcodes,
|
||||
Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
|
||||
send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
|
||||
}
|
||||
Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
|
||||
Tracev((stderr, "\nbl tree: sent %lu", s->bits_sent));
|
||||
|
||||
send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1); /* literal tree */
|
||||
Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
|
||||
Tracev((stderr, "\nlit tree: sent %lu", s->bits_sent));
|
||||
|
||||
send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1); /* distance tree */
|
||||
Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
|
||||
Tracev((stderr, "\ndist tree: sent %lu", s->bits_sent));
|
||||
}
|
||||
|
||||
/* ===========================================================================
|
||||
@@ -932,13 +977,14 @@ local void compress_block(deflate_state *s, const ct_data *ltree,
|
||||
extra = extra_dbits[code];
|
||||
if (extra != 0) {
|
||||
dist -= (unsigned)base_dist[code];
|
||||
send_bits(s, dist, extra); /* send the extra distance bits */
|
||||
send_bits(s, (int)dist, extra); /* send the extra bits */
|
||||
}
|
||||
} /* literal or match pair ? */
|
||||
|
||||
/* Check for no overlay of pending_buf on needed symbols */
|
||||
#ifdef LIT_MEM
|
||||
Assert(s->pending < 2 * (s->lit_bufsize + sx), "pendingBuf overflow");
|
||||
Assert(s->pending < (s->lit_bufsize << 1) + (sx << 1),
|
||||
"pendingBuf overflow");
|
||||
#else
|
||||
Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow");
|
||||
#endif
|
||||
@@ -1006,11 +1052,11 @@ void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf,
|
||||
|
||||
/* Construct the literal and distance trees */
|
||||
build_tree(s, (tree_desc *)(&(s->l_desc)));
|
||||
Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
|
||||
Tracev((stderr, "\nlit data: dyn %lu, stat %lu", s->opt_len,
|
||||
s->static_len));
|
||||
|
||||
build_tree(s, (tree_desc *)(&(s->d_desc)));
|
||||
Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
|
||||
Tracev((stderr, "\ndist data: dyn %lu, stat %lu", s->opt_len,
|
||||
s->static_len));
|
||||
/* At this point, opt_len and static_len are the total bit lengths of
|
||||
* the compressed block data, excluding the tree representations.
|
||||
@@ -1083,7 +1129,7 @@ void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf,
|
||||
#endif
|
||||
}
|
||||
Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len >> 3,
|
||||
s->compressed_len - 7*last));
|
||||
s->compressed_len - 7*(ulg)last));
|
||||
}
|
||||
|
||||
/* ===========================================================================
|
||||
|
||||
+39
-23
@@ -1,5 +1,5 @@
|
||||
/* uncompr.c -- decompress a memory buffer
|
||||
* Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler
|
||||
* Copyright (C) 1995-2026 Jean-loup Gailly, Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@@ -23,24 +23,24 @@
|
||||
memory, Z_BUF_ERROR if there was not enough room in the output buffer, or
|
||||
Z_DATA_ERROR if the input data was corrupted, including if the input data is
|
||||
an incomplete zlib stream.
|
||||
|
||||
The _z versions of the functions take size_t length arguments.
|
||||
*/
|
||||
int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, const Bytef *source,
|
||||
uLong *sourceLen) {
|
||||
int ZEXPORT uncompress2_z(Bytef *dest, z_size_t *destLen, const Bytef *source,
|
||||
z_size_t *sourceLen) {
|
||||
z_stream stream;
|
||||
int err;
|
||||
const uInt max = (uInt)-1;
|
||||
uLong len, left;
|
||||
Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */
|
||||
z_size_t len, left;
|
||||
|
||||
if (sourceLen == NULL || (*sourceLen > 0 && source == NULL) ||
|
||||
destLen == NULL || (*destLen > 0 && dest == NULL))
|
||||
return Z_STREAM_ERROR;
|
||||
|
||||
len = *sourceLen;
|
||||
if (*destLen) {
|
||||
left = *destLen;
|
||||
*destLen = 0;
|
||||
}
|
||||
else {
|
||||
left = 1;
|
||||
dest = buf;
|
||||
}
|
||||
left = *destLen;
|
||||
if (left == 0 && dest == Z_NULL)
|
||||
dest = (Bytef *)&stream.reserved; /* next_out cannot be NULL */
|
||||
|
||||
stream.next_in = (z_const Bytef *)source;
|
||||
stream.avail_in = 0;
|
||||
@@ -56,30 +56,46 @@ int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, const Bytef *source,
|
||||
|
||||
do {
|
||||
if (stream.avail_out == 0) {
|
||||
stream.avail_out = left > (uLong)max ? max : (uInt)left;
|
||||
stream.avail_out = left > (z_size_t)max ? max : (uInt)left;
|
||||
left -= stream.avail_out;
|
||||
}
|
||||
if (stream.avail_in == 0) {
|
||||
stream.avail_in = len > (uLong)max ? max : (uInt)len;
|
||||
stream.avail_in = len > (z_size_t)max ? max : (uInt)len;
|
||||
len -= stream.avail_in;
|
||||
}
|
||||
err = inflate(&stream, Z_NO_FLUSH);
|
||||
} while (err == Z_OK);
|
||||
|
||||
*sourceLen -= len + stream.avail_in;
|
||||
if (dest != buf)
|
||||
*destLen = stream.total_out;
|
||||
else if (stream.total_out && err == Z_BUF_ERROR)
|
||||
left = 1;
|
||||
/* Set len and left to the unused input data and unused output space. Set
|
||||
*sourceLen to the amount of input consumed. Set *destLen to the amount
|
||||
of data produced. */
|
||||
len += stream.avail_in;
|
||||
left += stream.avail_out;
|
||||
*sourceLen -= len;
|
||||
*destLen -= left;
|
||||
|
||||
inflateEnd(&stream);
|
||||
return err == Z_STREAM_END ? Z_OK :
|
||||
err == Z_NEED_DICT ? Z_DATA_ERROR :
|
||||
err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR :
|
||||
err == Z_BUF_ERROR && len == 0 ? Z_DATA_ERROR :
|
||||
err;
|
||||
}
|
||||
|
||||
int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, const Bytef *source,
|
||||
uLong *sourceLen) {
|
||||
int ret;
|
||||
z_size_t got = *destLen, used = *sourceLen;
|
||||
ret = uncompress2_z(dest, &got, source, &used);
|
||||
*sourceLen = (uLong)used;
|
||||
*destLen = (uLong)got;
|
||||
return ret;
|
||||
}
|
||||
int ZEXPORT uncompress_z(Bytef *dest, z_size_t *destLen, const Bytef *source,
|
||||
z_size_t sourceLen) {
|
||||
z_size_t used = sourceLen;
|
||||
return uncompress2_z(dest, destLen, source, &used);
|
||||
}
|
||||
int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, const Bytef *source,
|
||||
uLong sourceLen) {
|
||||
return uncompress2(dest, destLen, source, &sourceLen);
|
||||
uLong used = sourceLen;
|
||||
return uncompress2(dest, destLen, source, &used);
|
||||
}
|
||||
|
||||
Vendored
+42
-19
@@ -1,5 +1,5 @@
|
||||
/* zconf.h -- configuration of the zlib compression library
|
||||
* Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler
|
||||
* Copyright (C) 1995-2026 Jean-loup Gailly, Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@@ -8,6 +8,18 @@
|
||||
#ifndef ZCONF_H
|
||||
#define ZCONF_H
|
||||
|
||||
/*
|
||||
* This library is also built as a part of AOSP, which does not need to include
|
||||
* chromeconf.h. This config does not want chromeconf.h, so it can set this
|
||||
* macro to opt out. While this works today, there's no guarantee that building
|
||||
* zlib outside of Chromium keeps working in the future.
|
||||
*/
|
||||
#if !defined(CHROMIUM_ZLIB_NO_CHROMECONF)
|
||||
/* This include does prefixing as below, but with an updated set of names. Also
|
||||
* sets up export macros in component builds. */
|
||||
//#include "chromeconf.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If you *really* need a unique prefix for all types and library functions,
|
||||
* compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
|
||||
@@ -33,7 +45,10 @@
|
||||
# ifndef Z_SOLO
|
||||
# define compress z_compress
|
||||
# define compress2 z_compress2
|
||||
# define compress_z z_compress_z
|
||||
# define compress2_z z_compress2_z
|
||||
# define compressBound z_compressBound
|
||||
# define compressBound_z z_compressBound_z
|
||||
# endif
|
||||
# define crc32 z_crc32
|
||||
# define crc32_combine z_crc32_combine
|
||||
@@ -44,6 +59,7 @@
|
||||
# define crc32_z z_crc32_z
|
||||
# define deflate z_deflate
|
||||
# define deflateBound z_deflateBound
|
||||
# define deflateBound_z z_deflateBound_z
|
||||
# define deflateCopy z_deflateCopy
|
||||
# define deflateEnd z_deflateEnd
|
||||
# define deflateGetDictionary z_deflateGetDictionary
|
||||
@@ -59,6 +75,7 @@
|
||||
# define deflateSetDictionary z_deflateSetDictionary
|
||||
# define deflateSetHeader z_deflateSetHeader
|
||||
# define deflateTune z_deflateTune
|
||||
# define deflateUsed z_deflateUsed
|
||||
# define deflate_copyright z_deflate_copyright
|
||||
# define get_crc_table z_get_crc_table
|
||||
# ifndef Z_SOLO
|
||||
@@ -128,9 +145,12 @@
|
||||
# define inflate_copyright z_inflate_copyright
|
||||
# define inflate_fast z_inflate_fast
|
||||
# define inflate_table z_inflate_table
|
||||
# define inflate_fixed z_inflate_fixed
|
||||
# ifndef Z_SOLO
|
||||
# define uncompress z_uncompress
|
||||
# define uncompress2 z_uncompress2
|
||||
# define uncompress_z z_uncompress_z
|
||||
# define uncompress2_z z_uncompress2_z
|
||||
# endif
|
||||
# define zError z_zError
|
||||
# ifndef Z_SOLO
|
||||
@@ -234,10 +254,12 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(ZLIB_CONST) && !defined(z_const)
|
||||
# define z_const const
|
||||
#else
|
||||
# define z_const
|
||||
#ifndef z_const
|
||||
# ifdef ZLIB_CONST
|
||||
# define z_const const
|
||||
# else
|
||||
# define z_const
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef Z_SOLO
|
||||
@@ -388,6 +410,9 @@
|
||||
#ifndef FAR
|
||||
# define FAR
|
||||
#endif
|
||||
#ifndef far
|
||||
# define far
|
||||
#endif
|
||||
|
||||
#if !defined(__MACTYPES__)
|
||||
typedef unsigned char Byte; /* 8 bits */
|
||||
@@ -433,11 +458,11 @@ typedef uLong FAR uLongf;
|
||||
typedef unsigned long z_crc_t;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */
|
||||
#if !defined(_WIN32)
|
||||
# define Z_HAVE_UNISTD_H
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */
|
||||
#if defined(HAVE_STDARG_H) && HAVE_STDARG_H-0
|
||||
# define Z_HAVE_STDARG_H
|
||||
#endif
|
||||
|
||||
@@ -470,12 +495,8 @@ typedef uLong FAR uLongf;
|
||||
#endif
|
||||
|
||||
#ifndef Z_HAVE_UNISTD_H
|
||||
# ifdef __WATCOMC__
|
||||
# define Z_HAVE_UNISTD_H
|
||||
# endif
|
||||
#endif
|
||||
#ifndef Z_HAVE_UNISTD_H
|
||||
# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32)
|
||||
# if defined(__WATCOMC__) || defined(__GO32__) || \
|
||||
(defined(_LARGEFILE64_SOURCE) && !defined(_WIN32))
|
||||
# define Z_HAVE_UNISTD_H
|
||||
# endif
|
||||
#endif
|
||||
@@ -510,17 +531,19 @@ typedef uLong FAR uLongf;
|
||||
#endif
|
||||
|
||||
#ifndef z_off_t
|
||||
# define z_off_t long
|
||||
# define z_off_t long long
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && defined(Z_LARGE64)
|
||||
# define z_off64_t off64_t
|
||||
#elif defined(__MINGW32__)
|
||||
# define z_off64_t long long
|
||||
#elif defined(_WIN32) && !defined(__GNUC__)
|
||||
# define z_off64_t __int64
|
||||
#elif defined(__GO32__)
|
||||
# define z_off64_t offset_t
|
||||
#else
|
||||
# if defined(_WIN32) && !defined(__GNUC__)
|
||||
# define z_off64_t __int64
|
||||
# else
|
||||
# define z_off64_t z_off_t
|
||||
# endif
|
||||
# define z_off64_t z_off_t
|
||||
#endif
|
||||
|
||||
/* MVS linker does not support external names larger than 8 bytes */
|
||||
|
||||
Vendored
+246
-98
@@ -1,7 +1,7 @@
|
||||
/* zlib.h -- interface of the 'zlib' general purpose compression library
|
||||
version 1.3.1, January 22nd, 2024
|
||||
version 1.3.2.1, February xxth, 2026
|
||||
|
||||
Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler
|
||||
Copyright (C) 1995-2026 Jean-loup Gailly and Mark Adler
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -24,25 +24,29 @@
|
||||
|
||||
|
||||
The data format used by the zlib library is described by RFCs (Request for
|
||||
Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
|
||||
Comments) 1950 to 1952 at https://datatracker.ietf.org/doc/html/rfc1950
|
||||
(zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
|
||||
*/
|
||||
|
||||
#ifndef ZLIB_H
|
||||
#define ZLIB_H
|
||||
|
||||
#include "zconf.h"
|
||||
#ifdef ZLIB_BUILD
|
||||
# include <zconf.h>
|
||||
#else
|
||||
# include "zconf.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ZLIB_VERSION "1.3.1"
|
||||
#define ZLIB_VERNUM 0x1310
|
||||
#define ZLIB_VERSION "1.3.2.1-motley"
|
||||
#define ZLIB_VERNUM 0x1321
|
||||
#define ZLIB_VER_MAJOR 1
|
||||
#define ZLIB_VER_MINOR 3
|
||||
#define ZLIB_VER_REVISION 1
|
||||
#define ZLIB_VER_SUBREVISION 0
|
||||
#define ZLIB_VER_REVISION 2
|
||||
#define ZLIB_VER_SUBREVISION 1
|
||||
|
||||
/*
|
||||
The 'zlib' compression library provides in-memory compression and
|
||||
@@ -359,7 +363,6 @@ ZEXTERN int ZEXPORT deflate(z_streamp strm, int flush);
|
||||
continue compressing.
|
||||
*/
|
||||
|
||||
|
||||
ZEXTERN int ZEXPORT deflateEnd(z_streamp strm);
|
||||
/*
|
||||
All dynamically allocated data structures for this stream are freed.
|
||||
@@ -441,7 +444,7 @@ ZEXTERN int ZEXPORT inflate(z_streamp strm, int flush);
|
||||
|
||||
The Z_BLOCK option assists in appending to or combining deflate streams.
|
||||
To assist in this, on return inflate() always sets strm->data_type to the
|
||||
number of unused bits in the last byte taken from strm->next_in, plus 64 if
|
||||
number of unused bits in the input taken from strm->next_in, plus 64 if
|
||||
inflate() is currently decoding the last block in the deflate stream, plus
|
||||
128 if inflate() returned immediately after decoding an end-of-block code or
|
||||
decoding the complete header up to just before the first byte of the deflate
|
||||
@@ -587,18 +590,21 @@ ZEXTERN int ZEXPORT deflateInit2(z_streamp strm,
|
||||
|
||||
The strategy parameter is used to tune the compression algorithm. Use the
|
||||
value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
|
||||
filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
|
||||
string match), or Z_RLE to limit match distances to one (run-length
|
||||
encoding). Filtered data consists mostly of small values with a somewhat
|
||||
random distribution. In this case, the compression algorithm is tuned to
|
||||
compress them better. The effect of Z_FILTERED is to force more Huffman
|
||||
coding and less string matching; it is somewhat intermediate between
|
||||
Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as
|
||||
fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The
|
||||
strategy parameter only affects the compression ratio but not the
|
||||
correctness of the compressed output even if it is not set appropriately.
|
||||
Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
|
||||
decoder for special applications.
|
||||
filter (or predictor), Z_RLE to limit match distances to one (run-length
|
||||
encoding), or Z_HUFFMAN_ONLY to force Huffman encoding only (no string
|
||||
matching). Filtered data consists mostly of small values with a somewhat
|
||||
random distribution, as produced by the PNG filters. In this case, the
|
||||
compression algorithm is tuned to compress them better. The effect of
|
||||
Z_FILTERED is to force more Huffman coding and less string matching than the
|
||||
default; it is intermediate between Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.
|
||||
Z_RLE is almost as fast as Z_HUFFMAN_ONLY, but should give better
|
||||
compression for PNG image data than Huffman only. The degree of string
|
||||
matching from most to none is: Z_DEFAULT_STRATEGY, Z_FILTERED, Z_RLE, then
|
||||
Z_HUFFMAN_ONLY. The strategy parameter affects the compression ratio but
|
||||
never the correctness of the compressed output, even if it is not set
|
||||
optimally for the given data. Z_FIXED uses the default string matching, but
|
||||
prevents the use of dynamic Huffman codes, allowing for a simpler decoder
|
||||
for special applications.
|
||||
|
||||
deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
|
||||
memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
|
||||
@@ -758,8 +764,8 @@ ZEXTERN int ZEXPORT deflateTune(z_streamp strm,
|
||||
returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
|
||||
*/
|
||||
|
||||
ZEXTERN uLong ZEXPORT deflateBound(z_streamp strm,
|
||||
uLong sourceLen);
|
||||
ZEXTERN uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen);
|
||||
ZEXTERN z_size_t ZEXPORT deflateBound_z(z_streamp strm, z_size_t sourceLen);
|
||||
/*
|
||||
deflateBound() returns an upper bound on the compressed size after
|
||||
deflation of sourceLen bytes. It must be called after deflateInit() or
|
||||
@@ -771,6 +777,9 @@ ZEXTERN uLong ZEXPORT deflateBound(z_streamp strm,
|
||||
to return Z_STREAM_END. Note that it is possible for the compressed size to
|
||||
be larger than the value returned by deflateBound() if flush options other
|
||||
than Z_FINISH or Z_NO_FLUSH are used.
|
||||
|
||||
delfateBound_z() is the same, but takes and returns a size_t length. Note
|
||||
that a long is 32 bits on Windows.
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORT deflatePending(z_streamp strm,
|
||||
@@ -785,6 +794,21 @@ ZEXTERN int ZEXPORT deflatePending(z_streamp strm,
|
||||
or bits are Z_NULL, then those values are not set.
|
||||
|
||||
deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
|
||||
stream state was inconsistent. If an int is 16 bits and memLevel is 9, then
|
||||
it is possible for the number of pending bytes to not fit in an unsigned. In
|
||||
that case Z_BUF_ERROR is returned and *pending is set to the maximum value
|
||||
of an unsigned.
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORT deflateUsed(z_streamp strm,
|
||||
int *bits);
|
||||
/*
|
||||
deflateUsed() returns in *bits the most recent number of deflate bits used
|
||||
in the last byte when flushing to a byte boundary. The result is in 1..8, or
|
||||
0 if there has not yet been a flush. This helps determine the location of
|
||||
the last bit of a deflate stream.
|
||||
|
||||
deflateUsed returns Z_OK if success, or Z_STREAM_ERROR if the source
|
||||
stream state was inconsistent.
|
||||
*/
|
||||
|
||||
@@ -987,13 +1011,15 @@ ZEXTERN int ZEXPORT inflatePrime(z_streamp strm,
|
||||
int bits,
|
||||
int value);
|
||||
/*
|
||||
This function inserts bits in the inflate input stream. The intent is
|
||||
that this function is used to start inflating at a bit position in the
|
||||
middle of a byte. The provided bits will be used before any bytes are used
|
||||
from next_in. This function should only be used with raw inflate, and
|
||||
should be used before the first inflate() call after inflateInit2() or
|
||||
inflateReset(). bits must be less than or equal to 16, and that many of the
|
||||
least significant bits of value will be inserted in the input.
|
||||
This function inserts bits in the inflate input stream. The intent is to
|
||||
use inflatePrime() to start inflating at a bit position in the middle of a
|
||||
byte. The provided bits will be used before any bytes are used from
|
||||
next_in. This function should be used with raw inflate, before the first
|
||||
inflate() call, after inflateInit2() or inflateReset(). It can also be used
|
||||
after an inflate() return indicates the end of a deflate block or header
|
||||
when using Z_BLOCK. bits must be less than or equal to 16, and that many of
|
||||
the least significant bits of value will be inserted in the input. The
|
||||
other bits in value can be non-zero, and will be ignored.
|
||||
|
||||
If bits is negative, then the input stream bit buffer is emptied. Then
|
||||
inflatePrime() can be called again to put bits in the buffer. This is used
|
||||
@@ -1001,7 +1027,15 @@ ZEXTERN int ZEXPORT inflatePrime(z_streamp strm,
|
||||
to feeding inflate codes.
|
||||
|
||||
inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
|
||||
stream state was inconsistent.
|
||||
stream state was inconsistent, or if bits is out of range. If inflate was
|
||||
in the middle of processing a header, trailer, or stored block lengths, then
|
||||
it is possible for there to be only eight bits available in the bit buffer.
|
||||
In that case, bits > 8 is considered out of range. However, when used as
|
||||
outlined above, there will always be 16 bits available in the buffer for
|
||||
insertion. As noted in its documentation above, inflate records the number
|
||||
of bits in the bit buffer on return in data_type. 32 minus that is the
|
||||
number of bits available for insertion. inflatePrime does not update
|
||||
data_type with the new number of bits in buffer.
|
||||
*/
|
||||
|
||||
ZEXTERN long ZEXPORT inflateMark(z_streamp strm);
|
||||
@@ -1047,20 +1081,22 @@ ZEXTERN int ZEXPORT inflateGetHeader(z_streamp strm,
|
||||
|
||||
The text, time, xflags, and os fields are filled in with the gzip header
|
||||
contents. hcrc is set to true if there is a header CRC. (The header CRC
|
||||
was valid if done is set to one.) If extra is not Z_NULL, then extra_max
|
||||
contains the maximum number of bytes to write to extra. Once done is true,
|
||||
extra_len contains the actual extra field length, and extra contains the
|
||||
extra field, or that field truncated if extra_max is less than extra_len.
|
||||
If name is not Z_NULL, then up to name_max characters are written there,
|
||||
terminated with a zero unless the length is greater than name_max. If
|
||||
comment is not Z_NULL, then up to comm_max characters are written there,
|
||||
terminated with a zero unless the length is greater than comm_max. When any
|
||||
of extra, name, or comment are not Z_NULL and the respective field is not
|
||||
present in the header, then that field is set to Z_NULL to signal its
|
||||
absence. This allows the use of deflateSetHeader() with the returned
|
||||
structure to duplicate the header. However if those fields are set to
|
||||
allocated memory, then the application will need to save those pointers
|
||||
elsewhere so that they can be eventually freed.
|
||||
was valid if done is set to one.) The extra, name, and comment pointers
|
||||
much each be either Z_NULL or point to space to store that information from
|
||||
the header. If extra is not Z_NULL, then extra_max contains the maximum
|
||||
number of bytes that can be written to extra. Once done is true, extra_len
|
||||
contains the actual extra field length, and extra contains the extra field,
|
||||
or that field truncated if extra_max is less than extra_len. If name is not
|
||||
Z_NULL, then up to name_max characters, including the terminating zero, are
|
||||
written there. If comment is not Z_NULL, then up to comm_max characters,
|
||||
including the terminating zero, are written there. The application can tell
|
||||
that the name or comment did not fit in the provided space by the absence of
|
||||
a terminating zero. If any of extra, name, or comment are not present in
|
||||
the header, then that field's pointer is set to Z_NULL. This allows the use
|
||||
of deflateSetHeader() with the returned structure to duplicate the header.
|
||||
Note that if those fields initially pointed to allocated memory, then the
|
||||
application will need to save them elsewhere so that they can be eventually
|
||||
freed.
|
||||
|
||||
If inflateGetHeader is not used, then the header information is simply
|
||||
discarded. The header is always checked for validity, including the header
|
||||
@@ -1208,13 +1244,14 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags(void);
|
||||
21: FASTEST -- deflate algorithm with only one, lowest compression level
|
||||
22,23: 0 (reserved)
|
||||
|
||||
The sprintf variant used by gzprintf (zero is best):
|
||||
The sprintf variant used by gzprintf (all zeros is best):
|
||||
24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
|
||||
25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
|
||||
25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() is not secure!
|
||||
26: 0 = returns value, 1 = void -- 1 means inferred string length returned
|
||||
27: 0 = gzprintf() present, 1 = not -- 1 means gzprintf() returns an error
|
||||
|
||||
Remainder:
|
||||
27-31: 0 (reserved)
|
||||
28-31: 0 (reserved)
|
||||
*/
|
||||
|
||||
#ifndef Z_SOLO
|
||||
@@ -1226,11 +1263,14 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags(void);
|
||||
stream-oriented functions. To simplify the interface, some default options
|
||||
are assumed (compression level and memory usage, standard memory allocation
|
||||
functions). The source code of these utility functions can be modified if
|
||||
you need special options.
|
||||
you need special options. The _z versions of the functions use the size_t
|
||||
type for lengths. Note that a long is 32 bits on Windows.
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORT compress(Bytef *dest, uLongf *destLen,
|
||||
ZEXTERN int ZEXPORT compress(Bytef *dest, uLongf *destLen,
|
||||
const Bytef *source, uLong sourceLen);
|
||||
ZEXTERN int ZEXPORT compress_z(Bytef *dest, z_size_t *destLen,
|
||||
const Bytef *source, z_size_t sourceLen);
|
||||
/*
|
||||
Compresses the source buffer into the destination buffer. sourceLen is
|
||||
the byte length of the source buffer. Upon entry, destLen is the total size
|
||||
@@ -1244,9 +1284,12 @@ ZEXTERN int ZEXPORT compress(Bytef *dest, uLongf *destLen,
|
||||
buffer.
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORT compress2(Bytef *dest, uLongf *destLen,
|
||||
ZEXTERN int ZEXPORT compress2(Bytef *dest, uLongf *destLen,
|
||||
const Bytef *source, uLong sourceLen,
|
||||
int level);
|
||||
ZEXTERN int ZEXPORT compress2_z(Bytef *dest, z_size_t *destLen,
|
||||
const Bytef *source, z_size_t sourceLen,
|
||||
int level);
|
||||
/*
|
||||
Compresses the source buffer into the destination buffer. The level
|
||||
parameter has the same meaning as in deflateInit. sourceLen is the byte
|
||||
@@ -1261,21 +1304,24 @@ ZEXTERN int ZEXPORT compress2(Bytef *dest, uLongf *destLen,
|
||||
*/
|
||||
|
||||
ZEXTERN uLong ZEXPORT compressBound(uLong sourceLen);
|
||||
ZEXTERN z_size_t ZEXPORT compressBound_z(z_size_t sourceLen);
|
||||
/*
|
||||
compressBound() returns an upper bound on the compressed size after
|
||||
compress() or compress2() on sourceLen bytes. It would be used before a
|
||||
compress() or compress2() call to allocate the destination buffer.
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORT uncompress(Bytef *dest, uLongf *destLen,
|
||||
ZEXTERN int ZEXPORT uncompress(Bytef *dest, uLongf *destLen,
|
||||
const Bytef *source, uLong sourceLen);
|
||||
ZEXTERN int ZEXPORT uncompress_z(Bytef *dest, z_size_t *destLen,
|
||||
const Bytef *source, z_size_t sourceLen);
|
||||
/*
|
||||
Decompresses the source buffer into the destination buffer. sourceLen is
|
||||
the byte length of the source buffer. Upon entry, destLen is the total size
|
||||
the byte length of the source buffer. On entry, *destLen is the total size
|
||||
of the destination buffer, which must be large enough to hold the entire
|
||||
uncompressed data. (The size of the uncompressed data must have been saved
|
||||
previously by the compressor and transmitted to the decompressor by some
|
||||
mechanism outside the scope of this compression library.) Upon exit, destLen
|
||||
mechanism outside the scope of this compression library.) On exit, *destLen
|
||||
is the actual size of the uncompressed data.
|
||||
|
||||
uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
|
||||
@@ -1285,8 +1331,10 @@ ZEXTERN int ZEXPORT uncompress(Bytef *dest, uLongf *destLen,
|
||||
buffer with the uncompressed data up to that point.
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen,
|
||||
ZEXTERN int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen,
|
||||
const Bytef *source, uLong *sourceLen);
|
||||
ZEXTERN int ZEXPORT uncompress2_z(Bytef *dest, z_size_t *destLen,
|
||||
const Bytef *source, z_size_t *sourceLen);
|
||||
/*
|
||||
Same as uncompress, except that sourceLen is a pointer, where the
|
||||
length of the source is *sourceLen. On return, *sourceLen is the number of
|
||||
@@ -1314,13 +1362,17 @@ ZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode);
|
||||
'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression
|
||||
as in "wb9F". (See the description of deflateInit2 for more information
|
||||
about the strategy parameter.) 'T' will request transparent writing or
|
||||
appending with no compression and not using the gzip format.
|
||||
appending with no compression and not using the gzip format. 'T' cannot be
|
||||
used to force transparent reading. Transparent reading is automatically
|
||||
performed if there is no gzip header at the start. Transparent reading can
|
||||
be disabled with the 'G' option, which will instead return an error if there
|
||||
is no gzip header. 'N' will open the file in non-blocking mode.
|
||||
|
||||
"a" can be used instead of "w" to request that the gzip stream that will
|
||||
be written be appended to the file. "+" will result in an error, since
|
||||
'a' can be used instead of 'w' to request that the gzip stream that will
|
||||
be written be appended to the file. '+' will result in an error, since
|
||||
reading and writing to the same gzip file is not supported. The addition of
|
||||
"x" when writing will create the file exclusively, which fails if the file
|
||||
already exists. On systems that support it, the addition of "e" when
|
||||
'x' when writing will create the file exclusively, which fails if the file
|
||||
already exists. On systems that support it, the addition of 'e' when
|
||||
reading or writing will set the flag to close the file on an execve() call.
|
||||
|
||||
These functions, as well as gzip, will read and decode a sequence of gzip
|
||||
@@ -1339,14 +1391,22 @@ ZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode);
|
||||
insufficient memory to allocate the gzFile state, or if an invalid mode was
|
||||
specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
|
||||
errno can be checked to determine if the reason gzopen failed was that the
|
||||
file could not be opened.
|
||||
file could not be opened. Note that if 'N' is in mode for non-blocking, the
|
||||
open() itself can fail in order to not block. In that case gzopen() will
|
||||
return NULL and errno will be EAGAIN or ENONBLOCK. The call to gzopen() can
|
||||
then be re-tried. If the application would like to block on opening the
|
||||
file, then it can use open() without O_NONBLOCK, and then gzdopen() with the
|
||||
resulting file descriptor and 'N' in the mode, which will set it to non-
|
||||
blocking.
|
||||
*/
|
||||
|
||||
ZEXTERN gzFile ZEXPORT gzdopen(int fd, const char *mode);
|
||||
/*
|
||||
Associate a gzFile with the file descriptor fd. File descriptors are
|
||||
obtained from calls like open, dup, creat, pipe or fileno (if the file has
|
||||
been previously opened with fopen). The mode parameter is as in gzopen.
|
||||
been previously opened with fopen). The mode parameter is as in gzopen. An
|
||||
'e' in mode will set fd's flag to close the file on an execve() call. An 'N'
|
||||
in mode will set fd's non-blocking flag.
|
||||
|
||||
The next call of gzclose on the returned gzFile will also close the file
|
||||
descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
|
||||
@@ -1416,10 +1476,16 @@ ZEXTERN int ZEXPORT gzread(gzFile file, voidp buf, unsigned len);
|
||||
stream. Alternatively, gzerror can be used before gzclose to detect this
|
||||
case.
|
||||
|
||||
gzread can be used to read a gzip file on a non-blocking device. If the
|
||||
input stalls and there is no uncompressed data to return, then gzread() will
|
||||
return -1, and errno will be EAGAIN or EWOULDBLOCK. gzread() can then be
|
||||
called again.
|
||||
|
||||
gzread returns the number of uncompressed bytes actually read, less than
|
||||
len for end of file, or -1 for error. If len is too large to fit in an int,
|
||||
then nothing is read, -1 is returned, and the error state is set to
|
||||
Z_STREAM_ERROR.
|
||||
Z_STREAM_ERROR. If some data was read before an error, then that data is
|
||||
returned until exhausted, after which the next call will signal the error.
|
||||
*/
|
||||
|
||||
ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems,
|
||||
@@ -1443,15 +1509,20 @@ ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems,
|
||||
multiple of size, then the final partial item is nevertheless read into buf
|
||||
and the end-of-file flag is set. The length of the partial item read is not
|
||||
provided, but could be inferred from the result of gztell(). This behavior
|
||||
is the same as the behavior of fread() implementations in common libraries,
|
||||
but it prevents the direct use of gzfread() to read a concurrently written
|
||||
file, resetting and retrying on end-of-file, when size is not 1.
|
||||
is the same as that of fread() implementations in common libraries. This
|
||||
could result in data loss if used with size != 1 when reading a concurrently
|
||||
written file or a non-blocking file. In that case, use size == 1 or gzread()
|
||||
instead.
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len);
|
||||
/*
|
||||
Compress and write the len uncompressed bytes at buf to file. gzwrite
|
||||
returns the number of uncompressed bytes written or 0 in case of error.
|
||||
returns the number of uncompressed bytes written, or 0 in case of error or
|
||||
if len is 0. If the write destination is non-blocking, then gzwrite() may
|
||||
return a number of bytes written that is not 0 and less than len.
|
||||
|
||||
If len does not fit in an int, then 0 is returned and nothing is written.
|
||||
*/
|
||||
|
||||
ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size,
|
||||
@@ -1466,9 +1537,18 @@ ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size,
|
||||
if there was an error. If the multiplication of size and nitems overflows,
|
||||
i.e. the product does not fit in a z_size_t, then nothing is written, zero
|
||||
is returned, and the error state is set to Z_STREAM_ERROR.
|
||||
|
||||
If writing a concurrently read file or a non-blocking file with size != 1,
|
||||
a partial item could be written, with no way of knowing how much of it was
|
||||
not written, resulting in data loss. In that case, use size == 1 or
|
||||
gzwrite() instead.
|
||||
*/
|
||||
|
||||
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||
ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...);
|
||||
#else
|
||||
ZEXTERN int ZEXPORTVA gzprintf();
|
||||
#endif
|
||||
/*
|
||||
Convert, format, compress, and write the arguments (...) to file under
|
||||
control of the string format, as in fprintf. gzprintf returns the number of
|
||||
@@ -1476,11 +1556,19 @@ ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...);
|
||||
of error. The number of uncompressed bytes written is limited to 8191, or
|
||||
one less than the buffer size given to gzbuffer(). The caller should assure
|
||||
that this limit is not exceeded. If it is exceeded, then gzprintf() will
|
||||
return an error (0) with nothing written. In this case, there may also be a
|
||||
buffer overflow with unpredictable consequences, which is possible only if
|
||||
zlib was compiled with the insecure functions sprintf() or vsprintf(),
|
||||
because the secure snprintf() or vsnprintf() functions were not available.
|
||||
This can be determined using zlibCompileFlags().
|
||||
return an error (0) with nothing written.
|
||||
|
||||
In that last case, there may also be a buffer overflow with unpredictable
|
||||
consequences, which is possible only if zlib was compiled with the insecure
|
||||
functions sprintf() or vsprintf(), because the secure snprintf() and
|
||||
vsnprintf() functions were not available. That would only be the case for
|
||||
a non-ANSI C compiler. zlib may have been built without gzprintf() because
|
||||
secure functions were not available and having gzprintf() be insecure was
|
||||
not an option, in which case, gzprintf() returns Z_STREAM_ERROR. All of
|
||||
these possibilities can be determined using zlibCompileFlags().
|
||||
|
||||
If a Z_BUF_ERROR is returned, then nothing was written due to a stall on
|
||||
the non-blocking write destination.
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORT gzputs(gzFile file, const char *s);
|
||||
@@ -1489,6 +1577,11 @@ ZEXTERN int ZEXPORT gzputs(gzFile file, const char *s);
|
||||
the terminating null character.
|
||||
|
||||
gzputs returns the number of characters written, or -1 in case of error.
|
||||
The number of characters written may be less than the length of the string
|
||||
if the write destination is non-blocking.
|
||||
|
||||
If the length of the string does not fit in an int, then -1 is returned
|
||||
and nothing is written.
|
||||
*/
|
||||
|
||||
ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len);
|
||||
@@ -1501,8 +1594,13 @@ ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len);
|
||||
left untouched.
|
||||
|
||||
gzgets returns buf which is a null-terminated string, or it returns NULL
|
||||
for end-of-file or in case of error. If there was an error, the contents at
|
||||
buf are indeterminate.
|
||||
for end-of-file or in case of error. If some data was read before an error,
|
||||
then that data is returned until exhausted, after which the next call will
|
||||
return NULL to signal the error.
|
||||
|
||||
gzgets can be used on a file being concurrently written, and on a non-
|
||||
blocking device, both as for gzread(). However lines may be broken in the
|
||||
middle, leaving it up to the application to reassemble them as needed.
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORT gzputc(gzFile file, int c);
|
||||
@@ -1513,11 +1611,19 @@ ZEXTERN int ZEXPORT gzputc(gzFile file, int c);
|
||||
|
||||
ZEXTERN int ZEXPORT gzgetc(gzFile file);
|
||||
/*
|
||||
Read and decompress one byte from file. gzgetc returns this byte or -1
|
||||
in case of end of file or error. This is implemented as a macro for speed.
|
||||
As such, it does not do all of the checking the other functions do. I.e.
|
||||
it does not check to see if file is NULL, nor whether the structure file
|
||||
points to has been clobbered or not.
|
||||
Read and decompress one byte from file. gzgetc returns this byte or -1 in
|
||||
case of end of file or error. If some data was read before an error, then
|
||||
that data is returned until exhausted, after which the next call will return
|
||||
-1 to signal the error.
|
||||
|
||||
This is implemented as a macro for speed. As such, it does not do all of
|
||||
the checking the other functions do. I.e. it does not check to see if file
|
||||
is NULL, nor whether the structure file points to has been clobbered or not.
|
||||
|
||||
gzgetc can be used to read a gzip file on a non-blocking device. If the
|
||||
input stalls and there is no uncompressed data to return, then gzgetc() will
|
||||
return -1, and errno will be EAGAIN or EWOULDBLOCK. gzread() can then be
|
||||
called again.
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORT gzungetc(int c, gzFile file);
|
||||
@@ -1530,6 +1636,11 @@ ZEXTERN int ZEXPORT gzungetc(int c, gzFile file);
|
||||
output buffer size of pushed characters is allowed. (See gzbuffer above.)
|
||||
The pushed character will be discarded if the stream is repositioned with
|
||||
gzseek() or gzrewind().
|
||||
|
||||
gzungetc(-1, file) will force any pending seek to execute. Then gztell()
|
||||
will report the position, even if the requested seek reached end of file.
|
||||
This can be used to determine the number of uncompressed bytes in a gzip
|
||||
file without having to read it into a buffer.
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORT gzflush(gzFile file, int flush);
|
||||
@@ -1559,7 +1670,8 @@ ZEXTERN z_off_t ZEXPORT gzseek(gzFile file,
|
||||
If the file is opened for reading, this function is emulated but can be
|
||||
extremely slow. If the file is opened for writing, only forward seeks are
|
||||
supported; gzseek then compresses a sequence of zeroes up to the new
|
||||
starting position.
|
||||
starting position. For reading or writing, any actual seeking is deferred
|
||||
until the next read or write operation, or close operation when writing.
|
||||
|
||||
gzseek returns the resulting offset location as measured in bytes from
|
||||
the beginning of the uncompressed stream, or -1 in case of error, in
|
||||
@@ -1567,7 +1679,7 @@ ZEXTERN z_off_t ZEXPORT gzseek(gzFile file,
|
||||
would be before the current position.
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORT gzrewind(gzFile file);
|
||||
ZEXTERN int ZEXPORT gzrewind(gzFile file);
|
||||
/*
|
||||
Rewind file. This function is supported only for reading.
|
||||
|
||||
@@ -1575,7 +1687,7 @@ ZEXTERN int ZEXPORT gzrewind(gzFile file);
|
||||
*/
|
||||
|
||||
/*
|
||||
ZEXTERN z_off_t ZEXPORT gztell(gzFile file);
|
||||
ZEXTERN z_off_t ZEXPORT gztell(gzFile file);
|
||||
|
||||
Return the starting position for the next gzread or gzwrite on file.
|
||||
This position represents a number of bytes in the uncompressed data stream,
|
||||
@@ -1620,8 +1732,11 @@ ZEXTERN int ZEXPORT gzdirect(gzFile file);
|
||||
|
||||
If gzdirect() is used immediately after gzopen() or gzdopen() it will
|
||||
cause buffers to be allocated to allow reading the file to determine if it
|
||||
is a gzip file. Therefore if gzbuffer() is used, it should be called before
|
||||
gzdirect().
|
||||
is a gzip file. Therefore if gzbuffer() is used, it should be called before
|
||||
gzdirect(). If the input is being written concurrently or the device is non-
|
||||
blocking, then gzdirect() may give a different answer once four bytes of
|
||||
input have been accumulated, which is what is needed to confirm or deny a
|
||||
gzip header. Before this, gzdirect() will return true (1).
|
||||
|
||||
When writing, gzdirect() returns true (1) if transparent writing was
|
||||
requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note:
|
||||
@@ -1631,7 +1746,7 @@ ZEXTERN int ZEXPORT gzdirect(gzFile file);
|
||||
gzip file reading and decompression, which may not be desired.)
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORT gzclose(gzFile file);
|
||||
ZEXTERN int ZEXPORT gzclose(gzFile file);
|
||||
/*
|
||||
Flush all pending output for file, if necessary, close file and
|
||||
deallocate the (de)compression state. Note that once file is closed, you
|
||||
@@ -1659,9 +1774,10 @@ ZEXTERN int ZEXPORT gzclose_w(gzFile file);
|
||||
ZEXTERN const char * ZEXPORT gzerror(gzFile file, int *errnum);
|
||||
/*
|
||||
Return the error message for the last error which occurred on file.
|
||||
errnum is set to zlib error number. If an error occurred in the file system
|
||||
and not in the compression library, errnum is set to Z_ERRNO and the
|
||||
application may consult errno to get the exact error code.
|
||||
If errnum is not NULL, *errnum is set to zlib error number. If an error
|
||||
occurred in the file system and not in the compression library, *errnum is
|
||||
set to Z_ERRNO and the application may consult errno to get the exact error
|
||||
code.
|
||||
|
||||
The application must not modify the returned string. Future calls to
|
||||
this function may invalidate the previously returned string. If file is
|
||||
@@ -1712,7 +1828,8 @@ ZEXTERN uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len);
|
||||
ZEXTERN uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf,
|
||||
z_size_t len);
|
||||
/*
|
||||
Same as adler32(), but with a size_t length.
|
||||
Same as adler32(), but with a size_t length. Note that a long is 32 bits
|
||||
on Windows.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -1748,7 +1865,8 @@ ZEXTERN uLong ZEXPORT crc32(uLong crc, const Bytef *buf, uInt len);
|
||||
ZEXTERN uLong ZEXPORT crc32_z(uLong crc, const Bytef *buf,
|
||||
z_size_t len);
|
||||
/*
|
||||
Same as crc32(), but with a size_t length.
|
||||
Same as crc32(), but with a size_t length. Note that a long is 32 bits on
|
||||
Windows.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -1758,14 +1876,14 @@ ZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2);
|
||||
seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
|
||||
calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
|
||||
check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
|
||||
len2. len2 must be non-negative.
|
||||
len2. len2 must be non-negative, otherwise zero is returned.
|
||||
*/
|
||||
|
||||
/*
|
||||
ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2);
|
||||
|
||||
Return the operator corresponding to length len2, to be used with
|
||||
crc32_combine_op(). len2 must be non-negative.
|
||||
crc32_combine_op(). len2 must be non-negative, otherwise zero is returned.
|
||||
*/
|
||||
|
||||
ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op);
|
||||
@@ -1844,6 +1962,11 @@ ZEXTERN int ZEXPORT gzgetc_(gzFile file); /* backward compatibility */
|
||||
# undef z_gzgetc
|
||||
# define z_gzgetc(g) \
|
||||
((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g))
|
||||
#elif defined(Z_CR_PREFIX_SET)
|
||||
# undef gzgetc
|
||||
# define gzgetc(g) \
|
||||
((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) \
|
||||
: (Cr_z_gzgetc)(g))
|
||||
#else
|
||||
# define gzgetc(g) \
|
||||
((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g))
|
||||
@@ -1875,22 +1998,47 @@ ZEXTERN int ZEXPORT gzgetc_(gzFile file); /* backward compatibility */
|
||||
# define z_crc32_combine z_crc32_combine64
|
||||
# define z_crc32_combine_gen z_crc32_combine_gen64
|
||||
# else
|
||||
# ifdef gzopen
|
||||
# undef gzopen
|
||||
# endif
|
||||
# define gzopen gzopen64
|
||||
# ifdef gzseek
|
||||
# undef gzseek
|
||||
# endif
|
||||
# define gzseek gzseek64
|
||||
# ifdef gztell
|
||||
# undef gztell
|
||||
# endif
|
||||
# define gztell gztell64
|
||||
# ifdef gzoffset
|
||||
# undef gzoffset
|
||||
# endif
|
||||
# define gzoffset gzoffset64
|
||||
# ifdef adler32_combine
|
||||
# undef adler32_combine
|
||||
# endif
|
||||
# define adler32_combine adler32_combine64
|
||||
# define crc32_combine crc32_combine64
|
||||
# define crc32_combine_gen crc32_combine_gen64
|
||||
# ifdef crc32_combine
|
||||
# undef crc32_combine
|
||||
# endif
|
||||
# ifdef crc32_combine64
|
||||
# undef crc32_combine64
|
||||
# endif
|
||||
# ifdef crc32_combine_gen
|
||||
# undef crc32_combine_gen
|
||||
# endif
|
||||
# ifdef crc32_combine_op
|
||||
# undef crc32_combine_op
|
||||
# endif
|
||||
# endif
|
||||
# ifndef Z_LARGE64
|
||||
ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *);
|
||||
ZEXTERN z_off_t ZEXPORT gzseek64(gzFile, z_off_t, int);
|
||||
ZEXTERN z_off_t ZEXPORT gztell64(gzFile);
|
||||
ZEXTERN z_off_t ZEXPORT gzoffset64(gzFile);
|
||||
ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t);
|
||||
ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t);
|
||||
# endif
|
||||
#else
|
||||
ZEXTERN gzFile ZEXPORT gzopen(const char *, const char *);
|
||||
|
||||
Vendored
+49
-36
@@ -1,5 +1,5 @@
|
||||
/* zutil.c -- target dependent utility functions for the compression library
|
||||
* Copyright (C) 1995-2017 Jean-loup Gailly
|
||||
* Copyright (C) 1995-2026 Jean-loup Gailly
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@@ -86,28 +86,36 @@ uLong ZEXPORT zlibCompileFlags(void) {
|
||||
flags += 1L << 21;
|
||||
#endif
|
||||
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||
# ifdef NO_vsnprintf
|
||||
flags += 1L << 25;
|
||||
# ifdef HAS_vsprintf_void
|
||||
flags += 1L << 26;
|
||||
# endif
|
||||
# else
|
||||
# ifdef HAS_vsnprintf_void
|
||||
flags += 1L << 26;
|
||||
# endif
|
||||
# endif
|
||||
# ifdef NO_vsnprintf
|
||||
# ifdef ZLIB_INSECURE
|
||||
flags += 1L << 25;
|
||||
# else
|
||||
flags += 1L << 27;
|
||||
# endif
|
||||
# ifdef HAS_vsprintf_void
|
||||
flags += 1L << 26;
|
||||
# endif
|
||||
# else
|
||||
# ifdef HAS_vsnprintf_void
|
||||
flags += 1L << 26;
|
||||
# endif
|
||||
# endif
|
||||
#else
|
||||
flags += 1L << 24;
|
||||
# ifdef NO_snprintf
|
||||
flags += 1L << 25;
|
||||
# ifdef HAS_sprintf_void
|
||||
flags += 1L << 26;
|
||||
# endif
|
||||
# else
|
||||
# ifdef HAS_snprintf_void
|
||||
flags += 1L << 26;
|
||||
# endif
|
||||
# endif
|
||||
# ifdef NO_snprintf
|
||||
# ifdef ZLIB_INSECURE
|
||||
flags += 1L << 25;
|
||||
# else
|
||||
flags += 1L << 27;
|
||||
# endif
|
||||
# ifdef HAS_sprintf_void
|
||||
flags += 1L << 26;
|
||||
# endif
|
||||
# else
|
||||
# ifdef HAS_snprintf_void
|
||||
flags += 1L << 26;
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
return flags;
|
||||
}
|
||||
@@ -142,28 +150,33 @@ const char * ZEXPORT zError(int err) {
|
||||
|
||||
#ifndef HAVE_MEMCPY
|
||||
|
||||
void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len) {
|
||||
if (len == 0) return;
|
||||
do {
|
||||
*dest++ = *source++; /* ??? to be unrolled */
|
||||
} while (--len != 0);
|
||||
void ZLIB_INTERNAL zmemcpy(void FAR *dst, const void FAR *src, z_size_t n) {
|
||||
uchf *p = dst;
|
||||
const uchf *q = src;
|
||||
while (n) {
|
||||
*p++ = *q++;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len) {
|
||||
uInt j;
|
||||
|
||||
for (j = 0; j < len; j++) {
|
||||
if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
|
||||
int ZLIB_INTERNAL zmemcmp(const void FAR *s1, const void FAR *s2, z_size_t n) {
|
||||
const uchf *p = s1, *q = s2;
|
||||
while (n) {
|
||||
if (*p++ != *q++)
|
||||
return (int)p[-1] - (int)q[-1];
|
||||
n--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len) {
|
||||
if (len == 0) return;
|
||||
do {
|
||||
*dest++ = 0; /* ??? to be unrolled */
|
||||
} while (--len != 0);
|
||||
void ZLIB_INTERNAL zmemzero(void FAR *b, z_size_t len) {
|
||||
uchf *p = b;
|
||||
while (len) {
|
||||
*p++ = 0;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef Z_SOLO
|
||||
|
||||
Vendored
+109
-11
@@ -1,5 +1,5 @@
|
||||
/* zutil.h -- internal interface and configuration of the compression library
|
||||
* Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler
|
||||
* Copyright (C) 1995-2026 Jean-loup Gailly, Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@@ -28,6 +28,21 @@
|
||||
# include <string.h>
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
#ifdef NO_ERRNO_H
|
||||
# ifdef _WIN32_WCE
|
||||
/* The Microsoft C Run-Time Library for Windows CE doesn't have
|
||||
* errno. We define it as a global variable to simplify porting.
|
||||
* Its value is always 0 and should not be used. We rename it to
|
||||
* avoid conflict with other libraries that use the same workaround.
|
||||
*/
|
||||
# define errno z_errno
|
||||
# endif
|
||||
extern int errno;
|
||||
#else
|
||||
# ifndef _WIN32_WCE
|
||||
# include <errno.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef local
|
||||
# define local static
|
||||
@@ -36,6 +51,10 @@
|
||||
define "local" for the non-static meaning of "static", for readability
|
||||
(compile with -Dlocal if your debugger can't find static symbols) */
|
||||
|
||||
extern const char deflate_copyright[];
|
||||
extern const char inflate_copyright[];
|
||||
extern const char inflate9_copyright[];
|
||||
|
||||
typedef unsigned char uch;
|
||||
typedef uch FAR uchf;
|
||||
typedef unsigned short ush;
|
||||
@@ -48,6 +67,8 @@ typedef unsigned long ulg;
|
||||
# define Z_U8 unsigned long
|
||||
# elif (ULLONG_MAX == 0xffffffffffffffff)
|
||||
# define Z_U8 unsigned long long
|
||||
# elif (ULONG_LONG_MAX == 0xffffffffffffffff)
|
||||
# define Z_U8 unsigned long long
|
||||
# elif (UINT_MAX == 0xffffffffffffffff)
|
||||
# define Z_U8 unsigned
|
||||
# endif
|
||||
@@ -63,7 +84,9 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
|
||||
/* To be used only when the state is known to be valid */
|
||||
|
||||
/* common constants */
|
||||
|
||||
#if MAX_WBITS < 9 || MAX_WBITS > 15
|
||||
# error MAX_WBITS must be in 9..15
|
||||
#endif
|
||||
#ifndef DEF_WBITS
|
||||
# define DEF_WBITS MAX_WBITS
|
||||
#endif
|
||||
@@ -141,7 +164,7 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
|
||||
# define OS_CODE 7
|
||||
#endif
|
||||
|
||||
#ifdef __acorn
|
||||
#if defined(__acorn) || defined(__riscos)
|
||||
# define OS_CODE 13
|
||||
#endif
|
||||
|
||||
@@ -168,11 +191,10 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
|
||||
#endif
|
||||
|
||||
/* provide prototypes for these when building zlib without LFS */
|
||||
#if !defined(_WIN32) && \
|
||||
(!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
|
||||
ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t);
|
||||
#ifndef Z_LARGE64
|
||||
ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t);
|
||||
#endif
|
||||
|
||||
/* common defaults */
|
||||
@@ -211,9 +233,9 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
|
||||
# define zmemzero(dest, len) memset(dest, 0, len)
|
||||
# endif
|
||||
#else
|
||||
void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len);
|
||||
int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len);
|
||||
void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len);
|
||||
void ZLIB_INTERNAL zmemcpy(void FAR *, const void FAR *, z_size_t);
|
||||
int ZLIB_INTERNAL zmemcmp(const void FAR *, const void FAR *, z_size_t);
|
||||
void ZLIB_INTERNAL zmemzero(void FAR *, z_size_t);
|
||||
#endif
|
||||
|
||||
/* Diagnostic functions */
|
||||
@@ -251,4 +273,80 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
|
||||
#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
|
||||
(((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define zalign(x) __declspec(align(x))
|
||||
#else
|
||||
#define zalign(x) __attribute__((aligned((x))))
|
||||
#endif
|
||||
|
||||
#ifdef Z_ONCE
|
||||
/*
|
||||
Create a local z_once() function depending on the availability of atomics.
|
||||
*/
|
||||
|
||||
/* Check for the availability of atomics. */
|
||||
#if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \
|
||||
!defined(__STDC_NO_ATOMICS__)
|
||||
|
||||
#include <stdatomic.h>
|
||||
typedef struct {
|
||||
atomic_flag begun;
|
||||
atomic_int done;
|
||||
} z_once_t;
|
||||
#define Z_ONCE_INIT {ATOMIC_FLAG_INIT, 0}
|
||||
|
||||
/*
|
||||
Run the provided init() function exactly once, even if multiple threads
|
||||
invoke once() at the same time. The state must be a once_t initialized with
|
||||
Z_ONCE_INIT.
|
||||
*/
|
||||
local void z_once(z_once_t *state, void (*init)(void)) {
|
||||
if (!atomic_load(&state->done)) {
|
||||
if (atomic_flag_test_and_set(&state->begun))
|
||||
while (!atomic_load(&state->done))
|
||||
;
|
||||
else {
|
||||
init();
|
||||
atomic_store(&state->done, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else /* no atomics */
|
||||
|
||||
#warning zlib not thread-safe
|
||||
|
||||
typedef struct z_once_s {
|
||||
volatile int begun;
|
||||
volatile int done;
|
||||
} z_once_t;
|
||||
#define Z_ONCE_INIT {0, 0}
|
||||
|
||||
/* Test and set. Alas, not atomic, but tries to limit the period of
|
||||
vulnerability. */
|
||||
local int test_and_set(int volatile *flag) {
|
||||
int was;
|
||||
|
||||
was = *flag;
|
||||
*flag = 1;
|
||||
return was;
|
||||
}
|
||||
|
||||
/* Run the provided init() function once. This is not thread-safe. */
|
||||
local void z_once(z_once_t *state, void (*init)(void)) {
|
||||
if (!state->done) {
|
||||
if (test_and_set(&state->begun))
|
||||
while (!state->done)
|
||||
;
|
||||
else {
|
||||
init();
|
||||
state->done = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* ?atomics */
|
||||
|
||||
#endif /* Z_ONCE */
|
||||
|
||||
#endif /* ZUTIL_H */
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
// Compressed zlib bytes over the vendored zlib, the copy Node bundles: deflate,
|
||||
// raw deflate and gzip output match Node's for every level, strategy, memLevel,
|
||||
// windowBits and dictionary, for text, binary and a 1 MiB input that slides the
|
||||
// window, and for streams that flush and change parameters between writes.
|
||||
import { createHash } from "node:crypto";
|
||||
import {
|
||||
constants,
|
||||
createDeflate,
|
||||
createGzip,
|
||||
deflateRawSync,
|
||||
deflateSync,
|
||||
gunzipSync,
|
||||
gzipSync,
|
||||
inflateRawSync,
|
||||
inflateSync,
|
||||
type Deflate,
|
||||
type Gzip,
|
||||
type ZlibOptions,
|
||||
} from "node:zlib";
|
||||
|
||||
const digest = (bytes: Buffer): string =>
|
||||
`${bytes.length} ${createHash("sha256").update(bytes).digest("hex").slice(0, 16)}`;
|
||||
|
||||
const words = ["stream", "pipeline", "émetteur", "π", "buffer", "deflate", "\u0000", "window"];
|
||||
const parts: string[] = [];
|
||||
for (let i = 0; i < 3000; i++) parts.push(`${words[i % words.length]}-${(i * 7919) % 1000}`);
|
||||
const text = Buffer.from(parts.join(" "), "utf8");
|
||||
|
||||
let seed = 0x2545f491;
|
||||
const binary = Buffer.alloc(20000);
|
||||
for (let i = 0; i < binary.length; i++) {
|
||||
seed = (seed * 1103515245 + 12345) >>> 0;
|
||||
binary[i] = i % 3 === 0 ? seed >>> 24 : (i >> 4) & 0xff;
|
||||
}
|
||||
|
||||
const large = Buffer.alloc(1 << 20);
|
||||
for (let i = 0; i < large.length; i++) large[i] = text[(i * 31) % text.length]! ^ ((i >> 12) & 7);
|
||||
|
||||
for (const level of [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) {
|
||||
const deflated = deflateSync(text, { level });
|
||||
console.log("deflate", level, digest(deflated), inflateSync(deflated).equals(text));
|
||||
console.log("raw", level, digest(deflateRawSync(binary, { level })));
|
||||
console.log("gzip", level, digest(gzipSync(text, { level })));
|
||||
}
|
||||
|
||||
const variants: [string, ZlibOptions][] = [
|
||||
["filtered", { strategy: constants.Z_FILTERED }],
|
||||
["huffman only", { strategy: constants.Z_HUFFMAN_ONLY }],
|
||||
["rle", { strategy: constants.Z_RLE }],
|
||||
["fixed", { strategy: constants.Z_FIXED }],
|
||||
["memLevel 1", { memLevel: 1 }],
|
||||
["memLevel 9", { memLevel: 9 }],
|
||||
["windowBits 9", { windowBits: 9 }],
|
||||
["windowBits 12", { windowBits: 12 }],
|
||||
["level 9 memLevel 9", { level: 9, memLevel: 9 }],
|
||||
["dictionary", { dictionary: Buffer.from("stream pipeline buffer deflate window") }],
|
||||
];
|
||||
for (const [label, options] of variants) {
|
||||
const deflated = deflateSync(text, options);
|
||||
console.log(label, digest(deflated), digest(deflateRawSync(binary, options)));
|
||||
console.log(label, "inflates", inflateSync(deflated, options).equals(text));
|
||||
}
|
||||
|
||||
for (const level of [1, 6, 9]) {
|
||||
const gz = gzipSync(large, { level });
|
||||
console.log("1 MiB gzip", level, digest(gz), gunzipSync(gz).equals(large));
|
||||
const raw = deflateRawSync(large, { level, windowBits: 10 });
|
||||
console.log("1 MiB raw windowBits 10", level, digest(raw), inflateRawSync(raw, { windowBits: 10 }).equals(large));
|
||||
}
|
||||
|
||||
function collect(stream: Deflate | Gzip, label: string, done: () => void): void {
|
||||
const chunks: Buffer[] = [];
|
||||
stream.on("data", (chunk: Buffer) => chunks.push(chunk));
|
||||
stream.on("end", () => {
|
||||
console.log(label, digest(Buffer.concat(chunks)));
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
const flushed = createDeflate({ level: 6 });
|
||||
collect(flushed, "stream sync flush", () => {
|
||||
const changed = createGzip({ level: 1 });
|
||||
collect(changed, "stream params", () => console.log("done"));
|
||||
changed.write(text.subarray(0, 8000));
|
||||
changed.flush(constants.Z_FULL_FLUSH, () => {
|
||||
changed.params(9, constants.Z_DEFAULT_STRATEGY, () => {
|
||||
changed.write(text.subarray(8000));
|
||||
changed.end(binary);
|
||||
});
|
||||
});
|
||||
});
|
||||
flushed.write(text.subarray(0, 5000));
|
||||
flushed.flush(constants.Z_SYNC_FLUSH, () => {
|
||||
flushed.write(binary);
|
||||
flushed.end(text.subarray(5000));
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
// Inflation over the vendored zlib's chunked inflate: inputs fed in pieces of
|
||||
// 1 to 4096 bytes, output chunks of 64 bytes to 64 KiB, raw windowBits 9 to 15,
|
||||
// concatenated gzip members, back-references across a 1 MiB window, and a
|
||||
// truncated input. The output and the error match Node's.
|
||||
const zlib = require("node:zlib");
|
||||
const { createHash } = require("node:crypto");
|
||||
|
||||
const digest = (bytes) => `${bytes.length} ${createHash("sha256").update(bytes).digest("hex").slice(0, 16)}`;
|
||||
|
||||
const parts = [];
|
||||
for (let i = 0; i < 20000; i++) parts.push(`row ${i % 977} ${"abcdefgh".slice(i % 8)} ${(i * 2654435761) % 4093}`);
|
||||
const text = Buffer.from(parts.join("\n"));
|
||||
const large = Buffer.alloc(1 << 20);
|
||||
for (let i = 0; i < large.length; i++) large[i] = text[(i * 13) % text.length] ^ ((i >> 15) & 3);
|
||||
|
||||
const gz = zlib.gzipSync(large, { level: 6 });
|
||||
for (const chunkSize of [64, 1024, 16384, 65536]) {
|
||||
console.log("gunzip chunkSize", chunkSize, digest(zlib.gunzipSync(gz, { chunkSize })));
|
||||
}
|
||||
for (const windowBits of [9, 10, 12, 15]) {
|
||||
const raw = zlib.deflateRawSync(text, { windowBits, level: 9 });
|
||||
console.log("raw windowBits", windowBits, digest(zlib.inflateRawSync(raw, { windowBits })));
|
||||
}
|
||||
const members = Buffer.concat([zlib.gzipSync(text.subarray(0, 1000)), zlib.gzipSync(text.subarray(1000, 5000))]);
|
||||
console.log("members", digest(zlib.gunzipSync(members)));
|
||||
try {
|
||||
zlib.inflateSync(zlib.deflateSync(text).subarray(0, 2000));
|
||||
} catch (e) {
|
||||
console.log("truncated", e.code, e.errno, e.message);
|
||||
}
|
||||
|
||||
function feed(input, pieceSize, outSize, next) {
|
||||
const inflate = zlib.createGunzip({ chunkSize: outSize });
|
||||
const hash = createHash("sha256");
|
||||
let length = 0;
|
||||
inflate.on("data", (chunk) => {
|
||||
hash.update(chunk);
|
||||
length += chunk.length;
|
||||
});
|
||||
inflate.on("end", () => {
|
||||
console.log("stream piece", pieceSize, "chunk", outSize, length, hash.digest("hex").slice(0, 16));
|
||||
next();
|
||||
});
|
||||
let offset = 0;
|
||||
const pump = () => {
|
||||
while (offset < input.length) {
|
||||
const piece = input.subarray(offset, offset + pieceSize);
|
||||
offset += pieceSize;
|
||||
if (!inflate.write(piece)) {
|
||||
inflate.once("drain", pump);
|
||||
return;
|
||||
}
|
||||
}
|
||||
inflate.end();
|
||||
};
|
||||
pump();
|
||||
}
|
||||
|
||||
const head = zlib.gzipSync(large.subarray(0, 1 << 16), { level: 6 });
|
||||
const runs = [
|
||||
[head, 1, 64],
|
||||
[gz, 7, 1024],
|
||||
[gz, 333, 4096],
|
||||
[gz, 4096, 65536],
|
||||
];
|
||||
const step = (i) => {
|
||||
if (i < runs.length) feed(runs[i][0], runs[i][1], runs[i][2], () => step(i + 1));
|
||||
};
|
||||
step(0);
|
||||
@@ -0,0 +1 @@
|
||||
{ "plain": 5000, "san": 3200 }
|
||||
@@ -0,0 +1 @@
|
||||
{ "plain": 9000, "san": 13300 }
|
||||
@@ -316,6 +316,8 @@ describe.skipIf(!zigOnPath())("wasm32-wasi differential", () => {
|
||||
// Weak-collection hashes mix 32-bit pointers in 64 bits.
|
||||
"4591-weak-keys-union-records.ts",
|
||||
"7742-weak-collections-many-keys.ts",
|
||||
// zlib's portable build (CPU_NO_SIMD) compresses to Node's bytes.
|
||||
"8405-zlib-compressed-bytes.ts",
|
||||
])("the LLVM target runs %s byte-identically to Node", async (fixture) => {
|
||||
const entry = join(repoRoot, "tests/corpus", fixture);
|
||||
const outDir = await mkdtemp("/tmp/scriptc-wasi-");
|
||||
|
||||
Reference in New Issue
Block a user