18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Huffman decoder, part of New Generation Entropy library
38c2ecf20Sopenharmony_ci * Copyright (C) 2013-2016, Yann Collet.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
88c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are
98c2ecf20Sopenharmony_ci * met:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *   * Redistributions of source code must retain the above copyright
128c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer.
138c2ecf20Sopenharmony_ci *   * Redistributions in binary form must reproduce the above
148c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following disclaimer
158c2ecf20Sopenharmony_ci * in the documentation and/or other materials provided with the
168c2ecf20Sopenharmony_ci * distribution.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
198c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
208c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
218c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
228c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
238c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
248c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
258c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
268c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
278c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
288c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
298c2ecf20Sopenharmony_ci *
308c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it under
318c2ecf20Sopenharmony_ci * the terms of the GNU General Public License version 2 as published by the
328c2ecf20Sopenharmony_ci * Free Software Foundation. This program is dual-licensed; you may select
338c2ecf20Sopenharmony_ci * either version 2 of the GNU General Public License ("GPL") or BSD license
348c2ecf20Sopenharmony_ci * ("BSD").
358c2ecf20Sopenharmony_ci *
368c2ecf20Sopenharmony_ci * You can contact the author at :
378c2ecf20Sopenharmony_ci * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
388c2ecf20Sopenharmony_ci */
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/* **************************************************************
418c2ecf20Sopenharmony_ci*  Compiler specifics
428c2ecf20Sopenharmony_ci****************************************************************/
438c2ecf20Sopenharmony_ci#define FORCE_INLINE static __always_inline
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/* **************************************************************
468c2ecf20Sopenharmony_ci*  Dependencies
478c2ecf20Sopenharmony_ci****************************************************************/
488c2ecf20Sopenharmony_ci#include "bitstream.h" /* BIT_* */
498c2ecf20Sopenharmony_ci#include "fse.h"       /* header compression */
508c2ecf20Sopenharmony_ci#include "huf.h"
518c2ecf20Sopenharmony_ci#include <linux/compiler.h>
528c2ecf20Sopenharmony_ci#include <linux/kernel.h>
538c2ecf20Sopenharmony_ci#include <linux/string.h> /* memcpy, memset */
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/* **************************************************************
568c2ecf20Sopenharmony_ci*  Error Management
578c2ecf20Sopenharmony_ci****************************************************************/
588c2ecf20Sopenharmony_ci#define HUF_STATIC_ASSERT(c)                                   \
598c2ecf20Sopenharmony_ci	{                                                      \
608c2ecf20Sopenharmony_ci		enum { HUF_static_assert = 1 / (int)(!!(c)) }; \
618c2ecf20Sopenharmony_ci	} /* use only *after* variable declarations */
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/*-***************************/
648c2ecf20Sopenharmony_ci/*  generic DTableDesc       */
658c2ecf20Sopenharmony_ci/*-***************************/
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_citypedef struct {
688c2ecf20Sopenharmony_ci	BYTE maxTableLog;
698c2ecf20Sopenharmony_ci	BYTE tableType;
708c2ecf20Sopenharmony_ci	BYTE tableLog;
718c2ecf20Sopenharmony_ci	BYTE reserved;
728c2ecf20Sopenharmony_ci} DTableDesc;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic DTableDesc HUF_getDTableDesc(const HUF_DTable *table)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	DTableDesc dtd;
778c2ecf20Sopenharmony_ci	memcpy(&dtd, table, sizeof(dtd));
788c2ecf20Sopenharmony_ci	return dtd;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/*-***************************/
828c2ecf20Sopenharmony_ci/*  single-symbol decoding   */
838c2ecf20Sopenharmony_ci/*-***************************/
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_citypedef struct {
868c2ecf20Sopenharmony_ci	BYTE byte;
878c2ecf20Sopenharmony_ci	BYTE nbBits;
888c2ecf20Sopenharmony_ci} HUF_DEltX2; /* single-symbol decoding */
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cisize_t HUF_readDTableX2_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	U32 tableLog = 0;
938c2ecf20Sopenharmony_ci	U32 nbSymbols = 0;
948c2ecf20Sopenharmony_ci	size_t iSize;
958c2ecf20Sopenharmony_ci	void *const dtPtr = DTable + 1;
968c2ecf20Sopenharmony_ci	HUF_DEltX2 *const dt = (HUF_DEltX2 *)dtPtr;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	U32 *rankVal;
998c2ecf20Sopenharmony_ci	BYTE *huffWeight;
1008c2ecf20Sopenharmony_ci	size_t spaceUsed32 = 0;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	rankVal = (U32 *)workspace + spaceUsed32;
1038c2ecf20Sopenharmony_ci	spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1;
1048c2ecf20Sopenharmony_ci	huffWeight = (BYTE *)((U32 *)workspace + spaceUsed32);
1058c2ecf20Sopenharmony_ci	spaceUsed32 += ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if ((spaceUsed32 << 2) > workspaceSize)
1088c2ecf20Sopenharmony_ci		return ERROR(tableLog_tooLarge);
1098c2ecf20Sopenharmony_ci	workspace = (U32 *)workspace + spaceUsed32;
1108c2ecf20Sopenharmony_ci	workspaceSize -= (spaceUsed32 << 2);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	HUF_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable));
1138c2ecf20Sopenharmony_ci	/* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	iSize = HUF_readStats_wksp(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize, workspace, workspaceSize);
1168c2ecf20Sopenharmony_ci	if (HUF_isError(iSize))
1178c2ecf20Sopenharmony_ci		return iSize;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	/* Table header */
1208c2ecf20Sopenharmony_ci	{
1218c2ecf20Sopenharmony_ci		DTableDesc dtd = HUF_getDTableDesc(DTable);
1228c2ecf20Sopenharmony_ci		if (tableLog > (U32)(dtd.maxTableLog + 1))
1238c2ecf20Sopenharmony_ci			return ERROR(tableLog_tooLarge); /* DTable too small, Huffman tree cannot fit in */
1248c2ecf20Sopenharmony_ci		dtd.tableType = 0;
1258c2ecf20Sopenharmony_ci		dtd.tableLog = (BYTE)tableLog;
1268c2ecf20Sopenharmony_ci		memcpy(DTable, &dtd, sizeof(dtd));
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	/* Calculate starting value for each rank */
1308c2ecf20Sopenharmony_ci	{
1318c2ecf20Sopenharmony_ci		U32 n, nextRankStart = 0;
1328c2ecf20Sopenharmony_ci		for (n = 1; n < tableLog + 1; n++) {
1338c2ecf20Sopenharmony_ci			U32 const curr = nextRankStart;
1348c2ecf20Sopenharmony_ci			nextRankStart += (rankVal[n] << (n - 1));
1358c2ecf20Sopenharmony_ci			rankVal[n] = curr;
1368c2ecf20Sopenharmony_ci		}
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	/* fill DTable */
1408c2ecf20Sopenharmony_ci	{
1418c2ecf20Sopenharmony_ci		U32 n;
1428c2ecf20Sopenharmony_ci		for (n = 0; n < nbSymbols; n++) {
1438c2ecf20Sopenharmony_ci			U32 const w = huffWeight[n];
1448c2ecf20Sopenharmony_ci			U32 const length = (1 << w) >> 1;
1458c2ecf20Sopenharmony_ci			U32 u;
1468c2ecf20Sopenharmony_ci			HUF_DEltX2 D;
1478c2ecf20Sopenharmony_ci			D.byte = (BYTE)n;
1488c2ecf20Sopenharmony_ci			D.nbBits = (BYTE)(tableLog + 1 - w);
1498c2ecf20Sopenharmony_ci			for (u = rankVal[w]; u < rankVal[w] + length; u++)
1508c2ecf20Sopenharmony_ci				dt[u] = D;
1518c2ecf20Sopenharmony_ci			rankVal[w] += length;
1528c2ecf20Sopenharmony_ci		}
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	return iSize;
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic BYTE HUF_decodeSymbolX2(BIT_DStream_t *Dstream, const HUF_DEltX2 *dt, const U32 dtLog)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	size_t const val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */
1618c2ecf20Sopenharmony_ci	BYTE const c = dt[val].byte;
1628c2ecf20Sopenharmony_ci	BIT_skipBits(Dstream, dt[val].nbBits);
1638c2ecf20Sopenharmony_ci	return c;
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) *ptr++ = HUF_decodeSymbolX2(DStreamPtr, dt, dtLog)
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr)         \
1698c2ecf20Sopenharmony_ci	if (ZSTD_64bits() || (HUF_TABLELOG_MAX <= 12)) \
1708c2ecf20Sopenharmony_ci	HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
1738c2ecf20Sopenharmony_ci	if (ZSTD_64bits())                     \
1748c2ecf20Sopenharmony_ci	HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ciFORCE_INLINE size_t HUF_decodeStreamX2(BYTE *p, BIT_DStream_t *const bitDPtr, BYTE *const pEnd, const HUF_DEltX2 *const dt, const U32 dtLog)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	BYTE *const pStart = p;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	/* up to 4 symbols at a time */
1818c2ecf20Sopenharmony_ci	while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p <= pEnd - 4)) {
1828c2ecf20Sopenharmony_ci		HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
1838c2ecf20Sopenharmony_ci		HUF_DECODE_SYMBOLX2_1(p, bitDPtr);
1848c2ecf20Sopenharmony_ci		HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
1858c2ecf20Sopenharmony_ci		HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	/* closer to the end */
1898c2ecf20Sopenharmony_ci	while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p < pEnd))
1908c2ecf20Sopenharmony_ci		HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	/* no more data to retrieve from bitstream, hence no need to reload */
1938c2ecf20Sopenharmony_ci	while (p < pEnd)
1948c2ecf20Sopenharmony_ci		HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	return pEnd - pStart;
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic size_t HUF_decompress1X2_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	BYTE *op = (BYTE *)dst;
2028c2ecf20Sopenharmony_ci	BYTE *const oend = op + dstSize;
2038c2ecf20Sopenharmony_ci	const void *dtPtr = DTable + 1;
2048c2ecf20Sopenharmony_ci	const HUF_DEltX2 *const dt = (const HUF_DEltX2 *)dtPtr;
2058c2ecf20Sopenharmony_ci	BIT_DStream_t bitD;
2068c2ecf20Sopenharmony_ci	DTableDesc const dtd = HUF_getDTableDesc(DTable);
2078c2ecf20Sopenharmony_ci	U32 const dtLog = dtd.tableLog;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	{
2108c2ecf20Sopenharmony_ci		size_t const errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize);
2118c2ecf20Sopenharmony_ci		if (HUF_isError(errorCode))
2128c2ecf20Sopenharmony_ci			return errorCode;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	HUF_decodeStreamX2(op, &bitD, oend, dt, dtLog);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	/* check */
2188c2ecf20Sopenharmony_ci	if (!BIT_endOfDStream(&bitD))
2198c2ecf20Sopenharmony_ci		return ERROR(corruption_detected);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	return dstSize;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_cisize_t HUF_decompress1X2_usingDTable(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	DTableDesc dtd = HUF_getDTableDesc(DTable);
2278c2ecf20Sopenharmony_ci	if (dtd.tableType != 0)
2288c2ecf20Sopenharmony_ci		return ERROR(GENERIC);
2298c2ecf20Sopenharmony_ci	return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cisize_t HUF_decompress1X2_DCtx_wksp(HUF_DTable *DCtx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	const BYTE *ip = (const BYTE *)cSrc;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, workspace, workspaceSize);
2378c2ecf20Sopenharmony_ci	if (HUF_isError(hSize))
2388c2ecf20Sopenharmony_ci		return hSize;
2398c2ecf20Sopenharmony_ci	if (hSize >= cSrcSize)
2408c2ecf20Sopenharmony_ci		return ERROR(srcSize_wrong);
2418c2ecf20Sopenharmony_ci	ip += hSize;
2428c2ecf20Sopenharmony_ci	cSrcSize -= hSize;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx);
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic size_t HUF_decompress4X2_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	/* Check */
2508c2ecf20Sopenharmony_ci	if (cSrcSize < 10)
2518c2ecf20Sopenharmony_ci		return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	{
2548c2ecf20Sopenharmony_ci		const BYTE *const istart = (const BYTE *)cSrc;
2558c2ecf20Sopenharmony_ci		BYTE *const ostart = (BYTE *)dst;
2568c2ecf20Sopenharmony_ci		BYTE *const oend = ostart + dstSize;
2578c2ecf20Sopenharmony_ci		const void *const dtPtr = DTable + 1;
2588c2ecf20Sopenharmony_ci		const HUF_DEltX2 *const dt = (const HUF_DEltX2 *)dtPtr;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci		/* Init */
2618c2ecf20Sopenharmony_ci		BIT_DStream_t bitD1;
2628c2ecf20Sopenharmony_ci		BIT_DStream_t bitD2;
2638c2ecf20Sopenharmony_ci		BIT_DStream_t bitD3;
2648c2ecf20Sopenharmony_ci		BIT_DStream_t bitD4;
2658c2ecf20Sopenharmony_ci		size_t const length1 = ZSTD_readLE16(istart);
2668c2ecf20Sopenharmony_ci		size_t const length2 = ZSTD_readLE16(istart + 2);
2678c2ecf20Sopenharmony_ci		size_t const length3 = ZSTD_readLE16(istart + 4);
2688c2ecf20Sopenharmony_ci		size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
2698c2ecf20Sopenharmony_ci		const BYTE *const istart1 = istart + 6; /* jumpTable */
2708c2ecf20Sopenharmony_ci		const BYTE *const istart2 = istart1 + length1;
2718c2ecf20Sopenharmony_ci		const BYTE *const istart3 = istart2 + length2;
2728c2ecf20Sopenharmony_ci		const BYTE *const istart4 = istart3 + length3;
2738c2ecf20Sopenharmony_ci		const size_t segmentSize = (dstSize + 3) / 4;
2748c2ecf20Sopenharmony_ci		BYTE *const opStart2 = ostart + segmentSize;
2758c2ecf20Sopenharmony_ci		BYTE *const opStart3 = opStart2 + segmentSize;
2768c2ecf20Sopenharmony_ci		BYTE *const opStart4 = opStart3 + segmentSize;
2778c2ecf20Sopenharmony_ci		BYTE *op1 = ostart;
2788c2ecf20Sopenharmony_ci		BYTE *op2 = opStart2;
2798c2ecf20Sopenharmony_ci		BYTE *op3 = opStart3;
2808c2ecf20Sopenharmony_ci		BYTE *op4 = opStart4;
2818c2ecf20Sopenharmony_ci		U32 endSignal;
2828c2ecf20Sopenharmony_ci		DTableDesc const dtd = HUF_getDTableDesc(DTable);
2838c2ecf20Sopenharmony_ci		U32 const dtLog = dtd.tableLog;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci		if (length4 > cSrcSize)
2868c2ecf20Sopenharmony_ci			return ERROR(corruption_detected); /* overflow */
2878c2ecf20Sopenharmony_ci		{
2888c2ecf20Sopenharmony_ci			size_t const errorCode = BIT_initDStream(&bitD1, istart1, length1);
2898c2ecf20Sopenharmony_ci			if (HUF_isError(errorCode))
2908c2ecf20Sopenharmony_ci				return errorCode;
2918c2ecf20Sopenharmony_ci		}
2928c2ecf20Sopenharmony_ci		{
2938c2ecf20Sopenharmony_ci			size_t const errorCode = BIT_initDStream(&bitD2, istart2, length2);
2948c2ecf20Sopenharmony_ci			if (HUF_isError(errorCode))
2958c2ecf20Sopenharmony_ci				return errorCode;
2968c2ecf20Sopenharmony_ci		}
2978c2ecf20Sopenharmony_ci		{
2988c2ecf20Sopenharmony_ci			size_t const errorCode = BIT_initDStream(&bitD3, istart3, length3);
2998c2ecf20Sopenharmony_ci			if (HUF_isError(errorCode))
3008c2ecf20Sopenharmony_ci				return errorCode;
3018c2ecf20Sopenharmony_ci		}
3028c2ecf20Sopenharmony_ci		{
3038c2ecf20Sopenharmony_ci			size_t const errorCode = BIT_initDStream(&bitD4, istart4, length4);
3048c2ecf20Sopenharmony_ci			if (HUF_isError(errorCode))
3058c2ecf20Sopenharmony_ci				return errorCode;
3068c2ecf20Sopenharmony_ci		}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci		/* 16-32 symbols per loop (4-8 symbols per stream) */
3098c2ecf20Sopenharmony_ci		endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
3108c2ecf20Sopenharmony_ci		for (; (endSignal == BIT_DStream_unfinished) && (op4 < (oend - 7));) {
3118c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
3128c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
3138c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
3148c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
3158c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX2_1(op1, &bitD1);
3168c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX2_1(op2, &bitD2);
3178c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX2_1(op3, &bitD3);
3188c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX2_1(op4, &bitD4);
3198c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
3208c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
3218c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
3228c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
3238c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX2_0(op1, &bitD1);
3248c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX2_0(op2, &bitD2);
3258c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX2_0(op3, &bitD3);
3268c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX2_0(op4, &bitD4);
3278c2ecf20Sopenharmony_ci			endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
3288c2ecf20Sopenharmony_ci		}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci		/* check corruption */
3318c2ecf20Sopenharmony_ci		if (op1 > opStart2)
3328c2ecf20Sopenharmony_ci			return ERROR(corruption_detected);
3338c2ecf20Sopenharmony_ci		if (op2 > opStart3)
3348c2ecf20Sopenharmony_ci			return ERROR(corruption_detected);
3358c2ecf20Sopenharmony_ci		if (op3 > opStart4)
3368c2ecf20Sopenharmony_ci			return ERROR(corruption_detected);
3378c2ecf20Sopenharmony_ci		/* note : op4 supposed already verified within main loop */
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci		/* finish bitStreams one by one */
3408c2ecf20Sopenharmony_ci		HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog);
3418c2ecf20Sopenharmony_ci		HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog);
3428c2ecf20Sopenharmony_ci		HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog);
3438c2ecf20Sopenharmony_ci		HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci		/* check */
3468c2ecf20Sopenharmony_ci		endSignal = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
3478c2ecf20Sopenharmony_ci		if (!endSignal)
3488c2ecf20Sopenharmony_ci			return ERROR(corruption_detected);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci		/* decoded size */
3518c2ecf20Sopenharmony_ci		return dstSize;
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cisize_t HUF_decompress4X2_usingDTable(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	DTableDesc dtd = HUF_getDTableDesc(DTable);
3588c2ecf20Sopenharmony_ci	if (dtd.tableType != 0)
3598c2ecf20Sopenharmony_ci		return ERROR(GENERIC);
3608c2ecf20Sopenharmony_ci	return HUF_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cisize_t HUF_decompress4X2_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	const BYTE *ip = (const BYTE *)cSrc;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	size_t const hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize, workspace, workspaceSize);
3688c2ecf20Sopenharmony_ci	if (HUF_isError(hSize))
3698c2ecf20Sopenharmony_ci		return hSize;
3708c2ecf20Sopenharmony_ci	if (hSize >= cSrcSize)
3718c2ecf20Sopenharmony_ci		return ERROR(srcSize_wrong);
3728c2ecf20Sopenharmony_ci	ip += hSize;
3738c2ecf20Sopenharmony_ci	cSrcSize -= hSize;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx);
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci/* *************************/
3798c2ecf20Sopenharmony_ci/* double-symbols decoding */
3808c2ecf20Sopenharmony_ci/* *************************/
3818c2ecf20Sopenharmony_citypedef struct {
3828c2ecf20Sopenharmony_ci	U16 sequence;
3838c2ecf20Sopenharmony_ci	BYTE nbBits;
3848c2ecf20Sopenharmony_ci	BYTE length;
3858c2ecf20Sopenharmony_ci} HUF_DEltX4; /* double-symbols decoding */
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_citypedef struct {
3888c2ecf20Sopenharmony_ci	BYTE symbol;
3898c2ecf20Sopenharmony_ci	BYTE weight;
3908c2ecf20Sopenharmony_ci} sortedSymbol_t;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci/* HUF_fillDTableX4Level2() :
3938c2ecf20Sopenharmony_ci * `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */
3948c2ecf20Sopenharmony_cistatic void HUF_fillDTableX4Level2(HUF_DEltX4 *DTable, U32 sizeLog, const U32 consumed, const U32 *rankValOrigin, const int minWeight,
3958c2ecf20Sopenharmony_ci				   const sortedSymbol_t *sortedSymbols, const U32 sortedListSize, U32 nbBitsBaseline, U16 baseSeq)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	HUF_DEltX4 DElt;
3988c2ecf20Sopenharmony_ci	U32 rankVal[HUF_TABLELOG_MAX + 1];
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	/* get pre-calculated rankVal */
4018c2ecf20Sopenharmony_ci	memcpy(rankVal, rankValOrigin, sizeof(rankVal));
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	/* fill skipped values */
4048c2ecf20Sopenharmony_ci	if (minWeight > 1) {
4058c2ecf20Sopenharmony_ci		U32 i, skipSize = rankVal[minWeight];
4068c2ecf20Sopenharmony_ci		ZSTD_writeLE16(&(DElt.sequence), baseSeq);
4078c2ecf20Sopenharmony_ci		DElt.nbBits = (BYTE)(consumed);
4088c2ecf20Sopenharmony_ci		DElt.length = 1;
4098c2ecf20Sopenharmony_ci		for (i = 0; i < skipSize; i++)
4108c2ecf20Sopenharmony_ci			DTable[i] = DElt;
4118c2ecf20Sopenharmony_ci	}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	/* fill DTable */
4148c2ecf20Sopenharmony_ci	{
4158c2ecf20Sopenharmony_ci		U32 s;
4168c2ecf20Sopenharmony_ci		for (s = 0; s < sortedListSize; s++) { /* note : sortedSymbols already skipped */
4178c2ecf20Sopenharmony_ci			const U32 symbol = sortedSymbols[s].symbol;
4188c2ecf20Sopenharmony_ci			const U32 weight = sortedSymbols[s].weight;
4198c2ecf20Sopenharmony_ci			const U32 nbBits = nbBitsBaseline - weight;
4208c2ecf20Sopenharmony_ci			const U32 length = 1 << (sizeLog - nbBits);
4218c2ecf20Sopenharmony_ci			const U32 start = rankVal[weight];
4228c2ecf20Sopenharmony_ci			U32 i = start;
4238c2ecf20Sopenharmony_ci			const U32 end = start + length;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci			ZSTD_writeLE16(&(DElt.sequence), (U16)(baseSeq + (symbol << 8)));
4268c2ecf20Sopenharmony_ci			DElt.nbBits = (BYTE)(nbBits + consumed);
4278c2ecf20Sopenharmony_ci			DElt.length = 2;
4288c2ecf20Sopenharmony_ci			do {
4298c2ecf20Sopenharmony_ci				DTable[i++] = DElt;
4308c2ecf20Sopenharmony_ci			} while (i < end); /* since length >= 1 */
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci			rankVal[weight] += length;
4338c2ecf20Sopenharmony_ci		}
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_citypedef U32 rankVal_t[HUF_TABLELOG_MAX][HUF_TABLELOG_MAX + 1];
4388c2ecf20Sopenharmony_citypedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1];
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_cistatic void HUF_fillDTableX4(HUF_DEltX4 *DTable, const U32 targetLog, const sortedSymbol_t *sortedList, const U32 sortedListSize, const U32 *rankStart,
4418c2ecf20Sopenharmony_ci			     rankVal_t rankValOrigin, const U32 maxWeight, const U32 nbBitsBaseline)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	U32 rankVal[HUF_TABLELOG_MAX + 1];
4448c2ecf20Sopenharmony_ci	const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */
4458c2ecf20Sopenharmony_ci	const U32 minBits = nbBitsBaseline - maxWeight;
4468c2ecf20Sopenharmony_ci	U32 s;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	memcpy(rankVal, rankValOrigin, sizeof(rankVal));
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	/* fill DTable */
4518c2ecf20Sopenharmony_ci	for (s = 0; s < sortedListSize; s++) {
4528c2ecf20Sopenharmony_ci		const U16 symbol = sortedList[s].symbol;
4538c2ecf20Sopenharmony_ci		const U32 weight = sortedList[s].weight;
4548c2ecf20Sopenharmony_ci		const U32 nbBits = nbBitsBaseline - weight;
4558c2ecf20Sopenharmony_ci		const U32 start = rankVal[weight];
4568c2ecf20Sopenharmony_ci		const U32 length = 1 << (targetLog - nbBits);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		if (targetLog - nbBits >= minBits) { /* enough room for a second symbol */
4598c2ecf20Sopenharmony_ci			U32 sortedRank;
4608c2ecf20Sopenharmony_ci			int minWeight = nbBits + scaleLog;
4618c2ecf20Sopenharmony_ci			if (minWeight < 1)
4628c2ecf20Sopenharmony_ci				minWeight = 1;
4638c2ecf20Sopenharmony_ci			sortedRank = rankStart[minWeight];
4648c2ecf20Sopenharmony_ci			HUF_fillDTableX4Level2(DTable + start, targetLog - nbBits, nbBits, rankValOrigin[nbBits], minWeight, sortedList + sortedRank,
4658c2ecf20Sopenharmony_ci					       sortedListSize - sortedRank, nbBitsBaseline, symbol);
4668c2ecf20Sopenharmony_ci		} else {
4678c2ecf20Sopenharmony_ci			HUF_DEltX4 DElt;
4688c2ecf20Sopenharmony_ci			ZSTD_writeLE16(&(DElt.sequence), symbol);
4698c2ecf20Sopenharmony_ci			DElt.nbBits = (BYTE)(nbBits);
4708c2ecf20Sopenharmony_ci			DElt.length = 1;
4718c2ecf20Sopenharmony_ci			{
4728c2ecf20Sopenharmony_ci				U32 const end = start + length;
4738c2ecf20Sopenharmony_ci				U32 u;
4748c2ecf20Sopenharmony_ci				for (u = start; u < end; u++)
4758c2ecf20Sopenharmony_ci					DTable[u] = DElt;
4768c2ecf20Sopenharmony_ci			}
4778c2ecf20Sopenharmony_ci		}
4788c2ecf20Sopenharmony_ci		rankVal[weight] += length;
4798c2ecf20Sopenharmony_ci	}
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_cisize_t HUF_readDTableX4_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	U32 tableLog, maxW, sizeOfSort, nbSymbols;
4858c2ecf20Sopenharmony_ci	DTableDesc dtd = HUF_getDTableDesc(DTable);
4868c2ecf20Sopenharmony_ci	U32 const maxTableLog = dtd.maxTableLog;
4878c2ecf20Sopenharmony_ci	size_t iSize;
4888c2ecf20Sopenharmony_ci	void *dtPtr = DTable + 1; /* force compiler to avoid strict-aliasing */
4898c2ecf20Sopenharmony_ci	HUF_DEltX4 *const dt = (HUF_DEltX4 *)dtPtr;
4908c2ecf20Sopenharmony_ci	U32 *rankStart;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	rankValCol_t *rankVal;
4938c2ecf20Sopenharmony_ci	U32 *rankStats;
4948c2ecf20Sopenharmony_ci	U32 *rankStart0;
4958c2ecf20Sopenharmony_ci	sortedSymbol_t *sortedSymbol;
4968c2ecf20Sopenharmony_ci	BYTE *weightList;
4978c2ecf20Sopenharmony_ci	size_t spaceUsed32 = 0;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	HUF_STATIC_ASSERT((sizeof(rankValCol_t) & 3) == 0);
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	rankVal = (rankValCol_t *)((U32 *)workspace + spaceUsed32);
5028c2ecf20Sopenharmony_ci	spaceUsed32 += (sizeof(rankValCol_t) * HUF_TABLELOG_MAX) >> 2;
5038c2ecf20Sopenharmony_ci	rankStats = (U32 *)workspace + spaceUsed32;
5048c2ecf20Sopenharmony_ci	spaceUsed32 += HUF_TABLELOG_MAX + 1;
5058c2ecf20Sopenharmony_ci	rankStart0 = (U32 *)workspace + spaceUsed32;
5068c2ecf20Sopenharmony_ci	spaceUsed32 += HUF_TABLELOG_MAX + 2;
5078c2ecf20Sopenharmony_ci	sortedSymbol = (sortedSymbol_t *)((U32 *)workspace + spaceUsed32);
5088c2ecf20Sopenharmony_ci	spaceUsed32 += ALIGN(sizeof(sortedSymbol_t) * (HUF_SYMBOLVALUE_MAX + 1), sizeof(U32)) >> 2;
5098c2ecf20Sopenharmony_ci	weightList = (BYTE *)((U32 *)workspace + spaceUsed32);
5108c2ecf20Sopenharmony_ci	spaceUsed32 += ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	if ((spaceUsed32 << 2) > workspaceSize)
5138c2ecf20Sopenharmony_ci		return ERROR(tableLog_tooLarge);
5148c2ecf20Sopenharmony_ci	workspace = (U32 *)workspace + spaceUsed32;
5158c2ecf20Sopenharmony_ci	workspaceSize -= (spaceUsed32 << 2);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	rankStart = rankStart0 + 1;
5188c2ecf20Sopenharmony_ci	memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1));
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	HUF_STATIC_ASSERT(sizeof(HUF_DEltX4) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */
5218c2ecf20Sopenharmony_ci	if (maxTableLog > HUF_TABLELOG_MAX)
5228c2ecf20Sopenharmony_ci		return ERROR(tableLog_tooLarge);
5238c2ecf20Sopenharmony_ci	/* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	iSize = HUF_readStats_wksp(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize, workspace, workspaceSize);
5268c2ecf20Sopenharmony_ci	if (HUF_isError(iSize))
5278c2ecf20Sopenharmony_ci		return iSize;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	/* check result */
5308c2ecf20Sopenharmony_ci	if (tableLog > maxTableLog)
5318c2ecf20Sopenharmony_ci		return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	/* find maxWeight */
5348c2ecf20Sopenharmony_ci	for (maxW = tableLog; rankStats[maxW] == 0; maxW--) {
5358c2ecf20Sopenharmony_ci	} /* necessarily finds a solution before 0 */
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	/* Get start index of each weight */
5388c2ecf20Sopenharmony_ci	{
5398c2ecf20Sopenharmony_ci		U32 w, nextRankStart = 0;
5408c2ecf20Sopenharmony_ci		for (w = 1; w < maxW + 1; w++) {
5418c2ecf20Sopenharmony_ci			U32 curr = nextRankStart;
5428c2ecf20Sopenharmony_ci			nextRankStart += rankStats[w];
5438c2ecf20Sopenharmony_ci			rankStart[w] = curr;
5448c2ecf20Sopenharmony_ci		}
5458c2ecf20Sopenharmony_ci		rankStart[0] = nextRankStart; /* put all 0w symbols at the end of sorted list*/
5468c2ecf20Sopenharmony_ci		sizeOfSort = nextRankStart;
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	/* sort symbols by weight */
5508c2ecf20Sopenharmony_ci	{
5518c2ecf20Sopenharmony_ci		U32 s;
5528c2ecf20Sopenharmony_ci		for (s = 0; s < nbSymbols; s++) {
5538c2ecf20Sopenharmony_ci			U32 const w = weightList[s];
5548c2ecf20Sopenharmony_ci			U32 const r = rankStart[w]++;
5558c2ecf20Sopenharmony_ci			sortedSymbol[r].symbol = (BYTE)s;
5568c2ecf20Sopenharmony_ci			sortedSymbol[r].weight = (BYTE)w;
5578c2ecf20Sopenharmony_ci		}
5588c2ecf20Sopenharmony_ci		rankStart[0] = 0; /* forget 0w symbols; this is beginning of weight(1) */
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	/* Build rankVal */
5628c2ecf20Sopenharmony_ci	{
5638c2ecf20Sopenharmony_ci		U32 *const rankVal0 = rankVal[0];
5648c2ecf20Sopenharmony_ci		{
5658c2ecf20Sopenharmony_ci			int const rescale = (maxTableLog - tableLog) - 1; /* tableLog <= maxTableLog */
5668c2ecf20Sopenharmony_ci			U32 nextRankVal = 0;
5678c2ecf20Sopenharmony_ci			U32 w;
5688c2ecf20Sopenharmony_ci			for (w = 1; w < maxW + 1; w++) {
5698c2ecf20Sopenharmony_ci				U32 curr = nextRankVal;
5708c2ecf20Sopenharmony_ci				nextRankVal += rankStats[w] << (w + rescale);
5718c2ecf20Sopenharmony_ci				rankVal0[w] = curr;
5728c2ecf20Sopenharmony_ci			}
5738c2ecf20Sopenharmony_ci		}
5748c2ecf20Sopenharmony_ci		{
5758c2ecf20Sopenharmony_ci			U32 const minBits = tableLog + 1 - maxW;
5768c2ecf20Sopenharmony_ci			U32 consumed;
5778c2ecf20Sopenharmony_ci			for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) {
5788c2ecf20Sopenharmony_ci				U32 *const rankValPtr = rankVal[consumed];
5798c2ecf20Sopenharmony_ci				U32 w;
5808c2ecf20Sopenharmony_ci				for (w = 1; w < maxW + 1; w++) {
5818c2ecf20Sopenharmony_ci					rankValPtr[w] = rankVal0[w] >> consumed;
5828c2ecf20Sopenharmony_ci				}
5838c2ecf20Sopenharmony_ci			}
5848c2ecf20Sopenharmony_ci		}
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	HUF_fillDTableX4(dt, maxTableLog, sortedSymbol, sizeOfSort, rankStart0, rankVal, maxW, tableLog + 1);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	dtd.tableLog = (BYTE)maxTableLog;
5908c2ecf20Sopenharmony_ci	dtd.tableType = 1;
5918c2ecf20Sopenharmony_ci	memcpy(DTable, &dtd, sizeof(dtd));
5928c2ecf20Sopenharmony_ci	return iSize;
5938c2ecf20Sopenharmony_ci}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_cistatic U32 HUF_decodeSymbolX4(void *op, BIT_DStream_t *DStream, const HUF_DEltX4 *dt, const U32 dtLog)
5968c2ecf20Sopenharmony_ci{
5978c2ecf20Sopenharmony_ci	size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
5988c2ecf20Sopenharmony_ci	memcpy(op, dt + val, 2);
5998c2ecf20Sopenharmony_ci	BIT_skipBits(DStream, dt[val].nbBits);
6008c2ecf20Sopenharmony_ci	return dt[val].length;
6018c2ecf20Sopenharmony_ci}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_cistatic U32 HUF_decodeLastSymbolX4(void *op, BIT_DStream_t *DStream, const HUF_DEltX4 *dt, const U32 dtLog)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
6068c2ecf20Sopenharmony_ci	memcpy(op, dt + val, 1);
6078c2ecf20Sopenharmony_ci	if (dt[val].length == 1)
6088c2ecf20Sopenharmony_ci		BIT_skipBits(DStream, dt[val].nbBits);
6098c2ecf20Sopenharmony_ci	else {
6108c2ecf20Sopenharmony_ci		if (DStream->bitsConsumed < (sizeof(DStream->bitContainer) * 8)) {
6118c2ecf20Sopenharmony_ci			BIT_skipBits(DStream, dt[val].nbBits);
6128c2ecf20Sopenharmony_ci			if (DStream->bitsConsumed > (sizeof(DStream->bitContainer) * 8))
6138c2ecf20Sopenharmony_ci				/* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */
6148c2ecf20Sopenharmony_ci				DStream->bitsConsumed = (sizeof(DStream->bitContainer) * 8);
6158c2ecf20Sopenharmony_ci		}
6168c2ecf20Sopenharmony_ci	}
6178c2ecf20Sopenharmony_ci	return 1;
6188c2ecf20Sopenharmony_ci}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci#define HUF_DECODE_SYMBOLX4_0(ptr, DStreamPtr) ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci#define HUF_DECODE_SYMBOLX4_1(ptr, DStreamPtr)         \
6238c2ecf20Sopenharmony_ci	if (ZSTD_64bits() || (HUF_TABLELOG_MAX <= 12)) \
6248c2ecf20Sopenharmony_ci	ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci#define HUF_DECODE_SYMBOLX4_2(ptr, DStreamPtr) \
6278c2ecf20Sopenharmony_ci	if (ZSTD_64bits())                     \
6288c2ecf20Sopenharmony_ci	ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ciFORCE_INLINE size_t HUF_decodeStreamX4(BYTE *p, BIT_DStream_t *bitDPtr, BYTE *const pEnd, const HUF_DEltX4 *const dt, const U32 dtLog)
6318c2ecf20Sopenharmony_ci{
6328c2ecf20Sopenharmony_ci	BYTE *const pStart = p;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	/* up to 8 symbols at a time */
6358c2ecf20Sopenharmony_ci	while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd - (sizeof(bitDPtr->bitContainer) - 1))) {
6368c2ecf20Sopenharmony_ci		HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
6378c2ecf20Sopenharmony_ci		HUF_DECODE_SYMBOLX4_1(p, bitDPtr);
6388c2ecf20Sopenharmony_ci		HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
6398c2ecf20Sopenharmony_ci		HUF_DECODE_SYMBOLX4_0(p, bitDPtr);
6408c2ecf20Sopenharmony_ci	}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	/* closer to end : up to 2 symbols at a time */
6438c2ecf20Sopenharmony_ci	while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd - 2))
6448c2ecf20Sopenharmony_ci		HUF_DECODE_SYMBOLX4_0(p, bitDPtr);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	while (p <= pEnd - 2)
6478c2ecf20Sopenharmony_ci		HUF_DECODE_SYMBOLX4_0(p, bitDPtr); /* no need to reload : reached the end of DStream */
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	if (p < pEnd)
6508c2ecf20Sopenharmony_ci		p += HUF_decodeLastSymbolX4(p, bitDPtr, dt, dtLog);
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	return p - pStart;
6538c2ecf20Sopenharmony_ci}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_cistatic size_t HUF_decompress1X4_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	BIT_DStream_t bitD;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	/* Init */
6608c2ecf20Sopenharmony_ci	{
6618c2ecf20Sopenharmony_ci		size_t const errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize);
6628c2ecf20Sopenharmony_ci		if (HUF_isError(errorCode))
6638c2ecf20Sopenharmony_ci			return errorCode;
6648c2ecf20Sopenharmony_ci	}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	/* decode */
6678c2ecf20Sopenharmony_ci	{
6688c2ecf20Sopenharmony_ci		BYTE *const ostart = (BYTE *)dst;
6698c2ecf20Sopenharmony_ci		BYTE *const oend = ostart + dstSize;
6708c2ecf20Sopenharmony_ci		const void *const dtPtr = DTable + 1; /* force compiler to not use strict-aliasing */
6718c2ecf20Sopenharmony_ci		const HUF_DEltX4 *const dt = (const HUF_DEltX4 *)dtPtr;
6728c2ecf20Sopenharmony_ci		DTableDesc const dtd = HUF_getDTableDesc(DTable);
6738c2ecf20Sopenharmony_ci		HUF_decodeStreamX4(ostart, &bitD, oend, dt, dtd.tableLog);
6748c2ecf20Sopenharmony_ci	}
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	/* check */
6778c2ecf20Sopenharmony_ci	if (!BIT_endOfDStream(&bitD))
6788c2ecf20Sopenharmony_ci		return ERROR(corruption_detected);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	/* decoded size */
6818c2ecf20Sopenharmony_ci	return dstSize;
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_cisize_t HUF_decompress1X4_usingDTable(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
6858c2ecf20Sopenharmony_ci{
6868c2ecf20Sopenharmony_ci	DTableDesc dtd = HUF_getDTableDesc(DTable);
6878c2ecf20Sopenharmony_ci	if (dtd.tableType != 1)
6888c2ecf20Sopenharmony_ci		return ERROR(GENERIC);
6898c2ecf20Sopenharmony_ci	return HUF_decompress1X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
6908c2ecf20Sopenharmony_ci}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_cisize_t HUF_decompress1X4_DCtx_wksp(HUF_DTable *DCtx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
6938c2ecf20Sopenharmony_ci{
6948c2ecf20Sopenharmony_ci	const BYTE *ip = (const BYTE *)cSrc;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	size_t const hSize = HUF_readDTableX4_wksp(DCtx, cSrc, cSrcSize, workspace, workspaceSize);
6978c2ecf20Sopenharmony_ci	if (HUF_isError(hSize))
6988c2ecf20Sopenharmony_ci		return hSize;
6998c2ecf20Sopenharmony_ci	if (hSize >= cSrcSize)
7008c2ecf20Sopenharmony_ci		return ERROR(srcSize_wrong);
7018c2ecf20Sopenharmony_ci	ip += hSize;
7028c2ecf20Sopenharmony_ci	cSrcSize -= hSize;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	return HUF_decompress1X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx);
7058c2ecf20Sopenharmony_ci}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_cistatic size_t HUF_decompress4X4_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
7088c2ecf20Sopenharmony_ci{
7098c2ecf20Sopenharmony_ci	if (cSrcSize < 10)
7108c2ecf20Sopenharmony_ci		return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	{
7138c2ecf20Sopenharmony_ci		const BYTE *const istart = (const BYTE *)cSrc;
7148c2ecf20Sopenharmony_ci		BYTE *const ostart = (BYTE *)dst;
7158c2ecf20Sopenharmony_ci		BYTE *const oend = ostart + dstSize;
7168c2ecf20Sopenharmony_ci		const void *const dtPtr = DTable + 1;
7178c2ecf20Sopenharmony_ci		const HUF_DEltX4 *const dt = (const HUF_DEltX4 *)dtPtr;
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci		/* Init */
7208c2ecf20Sopenharmony_ci		BIT_DStream_t bitD1;
7218c2ecf20Sopenharmony_ci		BIT_DStream_t bitD2;
7228c2ecf20Sopenharmony_ci		BIT_DStream_t bitD3;
7238c2ecf20Sopenharmony_ci		BIT_DStream_t bitD4;
7248c2ecf20Sopenharmony_ci		size_t const length1 = ZSTD_readLE16(istart);
7258c2ecf20Sopenharmony_ci		size_t const length2 = ZSTD_readLE16(istart + 2);
7268c2ecf20Sopenharmony_ci		size_t const length3 = ZSTD_readLE16(istart + 4);
7278c2ecf20Sopenharmony_ci		size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
7288c2ecf20Sopenharmony_ci		const BYTE *const istart1 = istart + 6; /* jumpTable */
7298c2ecf20Sopenharmony_ci		const BYTE *const istart2 = istart1 + length1;
7308c2ecf20Sopenharmony_ci		const BYTE *const istart3 = istart2 + length2;
7318c2ecf20Sopenharmony_ci		const BYTE *const istart4 = istart3 + length3;
7328c2ecf20Sopenharmony_ci		size_t const segmentSize = (dstSize + 3) / 4;
7338c2ecf20Sopenharmony_ci		BYTE *const opStart2 = ostart + segmentSize;
7348c2ecf20Sopenharmony_ci		BYTE *const opStart3 = opStart2 + segmentSize;
7358c2ecf20Sopenharmony_ci		BYTE *const opStart4 = opStart3 + segmentSize;
7368c2ecf20Sopenharmony_ci		BYTE *op1 = ostart;
7378c2ecf20Sopenharmony_ci		BYTE *op2 = opStart2;
7388c2ecf20Sopenharmony_ci		BYTE *op3 = opStart3;
7398c2ecf20Sopenharmony_ci		BYTE *op4 = opStart4;
7408c2ecf20Sopenharmony_ci		U32 endSignal;
7418c2ecf20Sopenharmony_ci		DTableDesc const dtd = HUF_getDTableDesc(DTable);
7428c2ecf20Sopenharmony_ci		U32 const dtLog = dtd.tableLog;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci		if (length4 > cSrcSize)
7458c2ecf20Sopenharmony_ci			return ERROR(corruption_detected); /* overflow */
7468c2ecf20Sopenharmony_ci		{
7478c2ecf20Sopenharmony_ci			size_t const errorCode = BIT_initDStream(&bitD1, istart1, length1);
7488c2ecf20Sopenharmony_ci			if (HUF_isError(errorCode))
7498c2ecf20Sopenharmony_ci				return errorCode;
7508c2ecf20Sopenharmony_ci		}
7518c2ecf20Sopenharmony_ci		{
7528c2ecf20Sopenharmony_ci			size_t const errorCode = BIT_initDStream(&bitD2, istart2, length2);
7538c2ecf20Sopenharmony_ci			if (HUF_isError(errorCode))
7548c2ecf20Sopenharmony_ci				return errorCode;
7558c2ecf20Sopenharmony_ci		}
7568c2ecf20Sopenharmony_ci		{
7578c2ecf20Sopenharmony_ci			size_t const errorCode = BIT_initDStream(&bitD3, istart3, length3);
7588c2ecf20Sopenharmony_ci			if (HUF_isError(errorCode))
7598c2ecf20Sopenharmony_ci				return errorCode;
7608c2ecf20Sopenharmony_ci		}
7618c2ecf20Sopenharmony_ci		{
7628c2ecf20Sopenharmony_ci			size_t const errorCode = BIT_initDStream(&bitD4, istart4, length4);
7638c2ecf20Sopenharmony_ci			if (HUF_isError(errorCode))
7648c2ecf20Sopenharmony_ci				return errorCode;
7658c2ecf20Sopenharmony_ci		}
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci		/* 16-32 symbols per loop (4-8 symbols per stream) */
7688c2ecf20Sopenharmony_ci		endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
7698c2ecf20Sopenharmony_ci		for (; (endSignal == BIT_DStream_unfinished) & (op4 < (oend - (sizeof(bitD4.bitContainer) - 1)));) {
7708c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX4_2(op1, &bitD1);
7718c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX4_2(op2, &bitD2);
7728c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX4_2(op3, &bitD3);
7738c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX4_2(op4, &bitD4);
7748c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX4_1(op1, &bitD1);
7758c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX4_1(op2, &bitD2);
7768c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX4_1(op3, &bitD3);
7778c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX4_1(op4, &bitD4);
7788c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX4_2(op1, &bitD1);
7798c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX4_2(op2, &bitD2);
7808c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX4_2(op3, &bitD3);
7818c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX4_2(op4, &bitD4);
7828c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX4_0(op1, &bitD1);
7838c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX4_0(op2, &bitD2);
7848c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX4_0(op3, &bitD3);
7858c2ecf20Sopenharmony_ci			HUF_DECODE_SYMBOLX4_0(op4, &bitD4);
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci			endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
7888c2ecf20Sopenharmony_ci		}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci		/* check corruption */
7918c2ecf20Sopenharmony_ci		if (op1 > opStart2)
7928c2ecf20Sopenharmony_ci			return ERROR(corruption_detected);
7938c2ecf20Sopenharmony_ci		if (op2 > opStart3)
7948c2ecf20Sopenharmony_ci			return ERROR(corruption_detected);
7958c2ecf20Sopenharmony_ci		if (op3 > opStart4)
7968c2ecf20Sopenharmony_ci			return ERROR(corruption_detected);
7978c2ecf20Sopenharmony_ci		/* note : op4 already verified within main loop */
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci		/* finish bitStreams one by one */
8008c2ecf20Sopenharmony_ci		HUF_decodeStreamX4(op1, &bitD1, opStart2, dt, dtLog);
8018c2ecf20Sopenharmony_ci		HUF_decodeStreamX4(op2, &bitD2, opStart3, dt, dtLog);
8028c2ecf20Sopenharmony_ci		HUF_decodeStreamX4(op3, &bitD3, opStart4, dt, dtLog);
8038c2ecf20Sopenharmony_ci		HUF_decodeStreamX4(op4, &bitD4, oend, dt, dtLog);
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci		/* check */
8068c2ecf20Sopenharmony_ci		{
8078c2ecf20Sopenharmony_ci			U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
8088c2ecf20Sopenharmony_ci			if (!endCheck)
8098c2ecf20Sopenharmony_ci				return ERROR(corruption_detected);
8108c2ecf20Sopenharmony_ci		}
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci		/* decoded size */
8138c2ecf20Sopenharmony_ci		return dstSize;
8148c2ecf20Sopenharmony_ci	}
8158c2ecf20Sopenharmony_ci}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_cisize_t HUF_decompress4X4_usingDTable(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
8188c2ecf20Sopenharmony_ci{
8198c2ecf20Sopenharmony_ci	DTableDesc dtd = HUF_getDTableDesc(DTable);
8208c2ecf20Sopenharmony_ci	if (dtd.tableType != 1)
8218c2ecf20Sopenharmony_ci		return ERROR(GENERIC);
8228c2ecf20Sopenharmony_ci	return HUF_decompress4X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
8238c2ecf20Sopenharmony_ci}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_cisize_t HUF_decompress4X4_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
8268c2ecf20Sopenharmony_ci{
8278c2ecf20Sopenharmony_ci	const BYTE *ip = (const BYTE *)cSrc;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	size_t hSize = HUF_readDTableX4_wksp(dctx, cSrc, cSrcSize, workspace, workspaceSize);
8308c2ecf20Sopenharmony_ci	if (HUF_isError(hSize))
8318c2ecf20Sopenharmony_ci		return hSize;
8328c2ecf20Sopenharmony_ci	if (hSize >= cSrcSize)
8338c2ecf20Sopenharmony_ci		return ERROR(srcSize_wrong);
8348c2ecf20Sopenharmony_ci	ip += hSize;
8358c2ecf20Sopenharmony_ci	cSrcSize -= hSize;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	return HUF_decompress4X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx);
8388c2ecf20Sopenharmony_ci}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci/* ********************************/
8418c2ecf20Sopenharmony_ci/* Generic decompression selector */
8428c2ecf20Sopenharmony_ci/* ********************************/
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_cisize_t HUF_decompress1X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
8458c2ecf20Sopenharmony_ci{
8468c2ecf20Sopenharmony_ci	DTableDesc const dtd = HUF_getDTableDesc(DTable);
8478c2ecf20Sopenharmony_ci	return dtd.tableType ? HUF_decompress1X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable)
8488c2ecf20Sopenharmony_ci			     : HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable);
8498c2ecf20Sopenharmony_ci}
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_cisize_t HUF_decompress4X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci	DTableDesc const dtd = HUF_getDTableDesc(DTable);
8548c2ecf20Sopenharmony_ci	return dtd.tableType ? HUF_decompress4X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable)
8558c2ecf20Sopenharmony_ci			     : HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable);
8568c2ecf20Sopenharmony_ci}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_citypedef struct {
8598c2ecf20Sopenharmony_ci	U32 tableTime;
8608c2ecf20Sopenharmony_ci	U32 decode256Time;
8618c2ecf20Sopenharmony_ci} algo_time_t;
8628c2ecf20Sopenharmony_cistatic const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] = {
8638c2ecf20Sopenharmony_ci    /* single, double, quad */
8648c2ecf20Sopenharmony_ci    {{0, 0}, {1, 1}, {2, 2}},		     /* Q==0 : impossible */
8658c2ecf20Sopenharmony_ci    {{0, 0}, {1, 1}, {2, 2}},		     /* Q==1 : impossible */
8668c2ecf20Sopenharmony_ci    {{38, 130}, {1313, 74}, {2151, 38}},     /* Q == 2 : 12-18% */
8678c2ecf20Sopenharmony_ci    {{448, 128}, {1353, 74}, {2238, 41}},    /* Q == 3 : 18-25% */
8688c2ecf20Sopenharmony_ci    {{556, 128}, {1353, 74}, {2238, 47}},    /* Q == 4 : 25-32% */
8698c2ecf20Sopenharmony_ci    {{714, 128}, {1418, 74}, {2436, 53}},    /* Q == 5 : 32-38% */
8708c2ecf20Sopenharmony_ci    {{883, 128}, {1437, 74}, {2464, 61}},    /* Q == 6 : 38-44% */
8718c2ecf20Sopenharmony_ci    {{897, 128}, {1515, 75}, {2622, 68}},    /* Q == 7 : 44-50% */
8728c2ecf20Sopenharmony_ci    {{926, 128}, {1613, 75}, {2730, 75}},    /* Q == 8 : 50-56% */
8738c2ecf20Sopenharmony_ci    {{947, 128}, {1729, 77}, {3359, 77}},    /* Q == 9 : 56-62% */
8748c2ecf20Sopenharmony_ci    {{1107, 128}, {2083, 81}, {4006, 84}},   /* Q ==10 : 62-69% */
8758c2ecf20Sopenharmony_ci    {{1177, 128}, {2379, 87}, {4785, 88}},   /* Q ==11 : 69-75% */
8768c2ecf20Sopenharmony_ci    {{1242, 128}, {2415, 93}, {5155, 84}},   /* Q ==12 : 75-81% */
8778c2ecf20Sopenharmony_ci    {{1349, 128}, {2644, 106}, {5260, 106}}, /* Q ==13 : 81-87% */
8788c2ecf20Sopenharmony_ci    {{1455, 128}, {2422, 124}, {4174, 124}}, /* Q ==14 : 87-93% */
8798c2ecf20Sopenharmony_ci    {{722, 128}, {1891, 145}, {1936, 146}},  /* Q ==15 : 93-99% */
8808c2ecf20Sopenharmony_ci};
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci/** HUF_selectDecoder() :
8838c2ecf20Sopenharmony_ci*   Tells which decoder is likely to decode faster,
8848c2ecf20Sopenharmony_ci*   based on a set of pre-determined metrics.
8858c2ecf20Sopenharmony_ci*   @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
8868c2ecf20Sopenharmony_ci*   Assumption : 0 < cSrcSize < dstSize <= 128 KB */
8878c2ecf20Sopenharmony_ciU32 HUF_selectDecoder(size_t dstSize, size_t cSrcSize)
8888c2ecf20Sopenharmony_ci{
8898c2ecf20Sopenharmony_ci	/* decoder timing evaluation */
8908c2ecf20Sopenharmony_ci	U32 const Q = (U32)(cSrcSize * 16 / dstSize); /* Q < 16 since dstSize > cSrcSize */
8918c2ecf20Sopenharmony_ci	U32 const D256 = (U32)(dstSize >> 8);
8928c2ecf20Sopenharmony_ci	U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256);
8938c2ecf20Sopenharmony_ci	U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256);
8948c2ecf20Sopenharmony_ci	DTime1 += DTime1 >> 3; /* advantage to algorithm using less memory, for cache eviction */
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	return DTime1 < DTime0;
8978c2ecf20Sopenharmony_ci}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_citypedef size_t (*decompressionAlgo)(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize);
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_cisize_t HUF_decompress4X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
9028c2ecf20Sopenharmony_ci{
9038c2ecf20Sopenharmony_ci	/* validation checks */
9048c2ecf20Sopenharmony_ci	if (dstSize == 0)
9058c2ecf20Sopenharmony_ci		return ERROR(dstSize_tooSmall);
9068c2ecf20Sopenharmony_ci	if (cSrcSize > dstSize)
9078c2ecf20Sopenharmony_ci		return ERROR(corruption_detected); /* invalid */
9088c2ecf20Sopenharmony_ci	if (cSrcSize == dstSize) {
9098c2ecf20Sopenharmony_ci		memcpy(dst, cSrc, dstSize);
9108c2ecf20Sopenharmony_ci		return dstSize;
9118c2ecf20Sopenharmony_ci	} /* not compressed */
9128c2ecf20Sopenharmony_ci	if (cSrcSize == 1) {
9138c2ecf20Sopenharmony_ci		memset(dst, *(const BYTE *)cSrc, dstSize);
9148c2ecf20Sopenharmony_ci		return dstSize;
9158c2ecf20Sopenharmony_ci	} /* RLE */
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	{
9188c2ecf20Sopenharmony_ci		U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
9198c2ecf20Sopenharmony_ci		return algoNb ? HUF_decompress4X4_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize)
9208c2ecf20Sopenharmony_ci			      : HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize);
9218c2ecf20Sopenharmony_ci	}
9228c2ecf20Sopenharmony_ci}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_cisize_t HUF_decompress4X_hufOnly_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
9258c2ecf20Sopenharmony_ci{
9268c2ecf20Sopenharmony_ci	/* validation checks */
9278c2ecf20Sopenharmony_ci	if (dstSize == 0)
9288c2ecf20Sopenharmony_ci		return ERROR(dstSize_tooSmall);
9298c2ecf20Sopenharmony_ci	if ((cSrcSize >= dstSize) || (cSrcSize <= 1))
9308c2ecf20Sopenharmony_ci		return ERROR(corruption_detected); /* invalid */
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	{
9338c2ecf20Sopenharmony_ci		U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
9348c2ecf20Sopenharmony_ci		return algoNb ? HUF_decompress4X4_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize)
9358c2ecf20Sopenharmony_ci			      : HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize);
9368c2ecf20Sopenharmony_ci	}
9378c2ecf20Sopenharmony_ci}
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_cisize_t HUF_decompress1X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
9408c2ecf20Sopenharmony_ci{
9418c2ecf20Sopenharmony_ci	/* validation checks */
9428c2ecf20Sopenharmony_ci	if (dstSize == 0)
9438c2ecf20Sopenharmony_ci		return ERROR(dstSize_tooSmall);
9448c2ecf20Sopenharmony_ci	if (cSrcSize > dstSize)
9458c2ecf20Sopenharmony_ci		return ERROR(corruption_detected); /* invalid */
9468c2ecf20Sopenharmony_ci	if (cSrcSize == dstSize) {
9478c2ecf20Sopenharmony_ci		memcpy(dst, cSrc, dstSize);
9488c2ecf20Sopenharmony_ci		return dstSize;
9498c2ecf20Sopenharmony_ci	} /* not compressed */
9508c2ecf20Sopenharmony_ci	if (cSrcSize == 1) {
9518c2ecf20Sopenharmony_ci		memset(dst, *(const BYTE *)cSrc, dstSize);
9528c2ecf20Sopenharmony_ci		return dstSize;
9538c2ecf20Sopenharmony_ci	} /* RLE */
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	{
9568c2ecf20Sopenharmony_ci		U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
9578c2ecf20Sopenharmony_ci		return algoNb ? HUF_decompress1X4_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize)
9588c2ecf20Sopenharmony_ci			      : HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize);
9598c2ecf20Sopenharmony_ci	}
9608c2ecf20Sopenharmony_ci}
961