update
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/* Minimal LZ4 decompressor for EROFS FreeBSD */
|
||||
#include <sys/param.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include "compress.h"
|
||||
|
||||
#define EROFS_LZ4_TOKEN_LITERAL_SHIFT 4
|
||||
#define EROFS_LZ4_TOKEN_MATCH_MASK 0x0f
|
||||
#define EROFS_LZ4_MAX_RUN 15
|
||||
#define EROFS_LZ4_EXT_SENTINEL 255
|
||||
#define EROFS_LZ4_MIN_MATCH 4
|
||||
#define EROFS_LZ4_OFFSET_BYTES 2
|
||||
|
||||
static int
|
||||
lz4_finish(const uint8_t *ip, const uint8_t *iend, int partial)
|
||||
{
|
||||
if (partial)
|
||||
return (0);
|
||||
while (ip < iend) {
|
||||
if (*ip++ != 0)
|
||||
return (EINTEGRITY);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
z_erofs_lz4_decompress(const struct z_erofs_decompress_req *rq)
|
||||
{
|
||||
const uint8_t *ip, *iend;
|
||||
uint8_t *op, *oend;
|
||||
unsigned int token;
|
||||
size_t length, copylen;
|
||||
size_t offset;
|
||||
|
||||
ip = rq->in;
|
||||
iend = ip + rq->inputsize;
|
||||
op = rq->out;
|
||||
oend = op + rq->outputsize;
|
||||
if (iend < ip || oend < op)
|
||||
return (EINTEGRITY);
|
||||
|
||||
while (ip < iend) {
|
||||
token = *ip++;
|
||||
length = token >> EROFS_LZ4_TOKEN_LITERAL_SHIFT;
|
||||
if (length == EROFS_LZ4_MAX_RUN) {
|
||||
unsigned int value;
|
||||
do {
|
||||
if (ip >= iend)
|
||||
return (EINTEGRITY);
|
||||
value = *ip++;
|
||||
if (length > SIZE_MAX - value)
|
||||
return (EINTEGRITY);
|
||||
length += value;
|
||||
} while (value == EROFS_LZ4_EXT_SENTINEL);
|
||||
}
|
||||
if (length > (size_t)(iend - ip))
|
||||
return (EINTEGRITY);
|
||||
if (!rq->partial_decoding && length > (size_t)(oend - op))
|
||||
return (EINTEGRITY);
|
||||
copylen = MIN(length, (size_t)(oend - op));
|
||||
memcpy(op, ip, copylen);
|
||||
ip += length;
|
||||
op += copylen;
|
||||
if (op == oend)
|
||||
return (lz4_finish(ip, iend, rq->partial_decoding));
|
||||
if (ip >= iend)
|
||||
break;
|
||||
if (ip + EROFS_LZ4_OFFSET_BYTES > iend)
|
||||
return (EINTEGRITY);
|
||||
offset = le16dec(ip);
|
||||
ip += EROFS_LZ4_OFFSET_BYTES;
|
||||
if (offset == 0 || offset >
|
||||
(size_t)(op - (uint8_t *)rq->out))
|
||||
return (EINTEGRITY);
|
||||
length = token & EROFS_LZ4_TOKEN_MATCH_MASK;
|
||||
if (length == EROFS_LZ4_MAX_RUN) {
|
||||
unsigned int value;
|
||||
do {
|
||||
if (ip >= iend)
|
||||
return (EINTEGRITY);
|
||||
value = *ip++;
|
||||
if (length > SIZE_MAX - value)
|
||||
return (EINTEGRITY);
|
||||
length += value;
|
||||
} while (value == EROFS_LZ4_EXT_SENTINEL);
|
||||
}
|
||||
if (length > SIZE_MAX - EROFS_LZ4_MIN_MATCH)
|
||||
return (EINTEGRITY);
|
||||
length += EROFS_LZ4_MIN_MATCH;
|
||||
if (!rq->partial_decoding && length > (size_t)(oend - op))
|
||||
return (EINTEGRITY);
|
||||
copylen = MIN(length, (size_t)(oend - op));
|
||||
while (copylen-- != 0) {
|
||||
*op = *(op - offset);
|
||||
++op;
|
||||
}
|
||||
if (op == oend)
|
||||
return (lz4_finish(ip, iend, rq->partial_decoding));
|
||||
}
|
||||
return (op == oend ?
|
||||
lz4_finish(ip, iend, rq->partial_decoding) : EINTEGRITY);
|
||||
}
|
||||
Reference in New Issue
Block a user