657 lines
15 KiB
C
657 lines
15 KiB
C
/*
|
|
* Copyright (c) 2020 AIIT XUOS Lab
|
|
* XiUOS is licensed under Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
* http://license.coscl.org.cn/MulanPSL2
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PSL v2 for more details.
|
|
*/
|
|
|
|
#include <xiuos.h>
|
|
|
|
#if defined(FS_VFS) && defined(TOOL_SHELL)
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <iot-vfs_posix.h>
|
|
#include "utility.h"
|
|
|
|
|
|
#define MAX_GROUPS 6
|
|
#define GROUP_SIZE 50
|
|
#define MAX_HUFCODE_BITS 20
|
|
#define MAX_SYMBOLS 258
|
|
#define SYMBOL_RUNA 0
|
|
#define SYMBOL_RUNB 1
|
|
|
|
#define BZIP2_MAGIC ('B' + 'Z' * 256)
|
|
|
|
#define IOBUF_SIZE 4096
|
|
|
|
#define RET_ERROR -1
|
|
#define RET_LASTBLOCK -2
|
|
|
|
|
|
struct GroupData {
|
|
int32_t limit[MAX_HUFCODE_BITS+1], base[MAX_HUFCODE_BITS], permute[MAX_SYMBOLS];
|
|
int minLen, maxLen;
|
|
};
|
|
|
|
|
|
typedef struct BunZipData {
|
|
|
|
uint32_t inbufBitCount, inbufBits;
|
|
int in_fd, out_fd, inbufCount, inbufPos;
|
|
uint8_t *inbuf;
|
|
|
|
int writeCopies, writePos, writeRunCountdown, writeCount;
|
|
int writeCurrent;
|
|
|
|
uint32_t headerCRC, totalCRC, writeCRC;
|
|
|
|
uint32_t *dbuf;
|
|
uint32_t dbufSize;
|
|
|
|
uint32_t crc32Table[256];
|
|
uint8_t selectors[32768];
|
|
struct GroupData groups[MAX_GROUPS];
|
|
} BunZipData_t;
|
|
|
|
|
|
static int GetBits(BunZipData_t *bd, int bits_wanted, uint32_t *bits)
|
|
{
|
|
uint32_t b = 0;
|
|
|
|
int bit_count = bd->inbufBitCount;
|
|
|
|
while (bit_count < bits_wanted) {
|
|
|
|
if (bd->inbufPos == bd->inbufCount) {
|
|
bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE);
|
|
if (bd->inbufCount <= 0)
|
|
return -1;
|
|
bd->inbufPos = 0;
|
|
}
|
|
|
|
if (bit_count >= 24) {
|
|
b = bd->inbufBits & ((1U << bit_count) - 1);
|
|
bits_wanted -= bit_count;
|
|
b <<= bits_wanted;
|
|
bit_count = 0;
|
|
}
|
|
|
|
bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++];
|
|
bit_count += 8;
|
|
}
|
|
|
|
bit_count -= bits_wanted;
|
|
bd->inbufBitCount = bit_count;
|
|
b |= (bd->inbufBits >> bit_count) & ((1 << bits_wanted) - 1);
|
|
*bits = b;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int GetNextBlock(BunZipData_t *bd)
|
|
{
|
|
int groupCount, selector,
|
|
i, j, symCount, symTotal, nSelectors, byteCount[256];
|
|
uint8_t uc, symToByte[256], mtfSymbol[256], *selectors;
|
|
uint32_t *dbuf;
|
|
uint32_t origPtr, t;
|
|
uint32_t dbufCount, runPos;
|
|
uint32_t runCnt = runCnt;
|
|
uint32_t tmp;
|
|
|
|
dbuf = bd->dbuf;
|
|
selectors = bd->selectors;
|
|
|
|
if (GetBits(bd, 24, (uint32_t *)&i) < 0)
|
|
return RET_ERROR;
|
|
if (GetBits(bd, 24, (uint32_t *)&j) < 0)
|
|
return RET_ERROR;
|
|
if (GetBits(bd, 32, &bd->headerCRC) < 0)
|
|
return RET_ERROR;
|
|
if ((i == 0x177245) && (j == 0x385090))
|
|
return RET_LASTBLOCK;
|
|
if ((i != 0x314159) || (j != 0x265359))
|
|
return RET_ERROR;
|
|
|
|
if (GetBits(bd, 1, &tmp) < 0)
|
|
return RET_ERROR;
|
|
if (tmp)
|
|
return RET_ERROR;
|
|
if (GetBits(bd, 24, (uint32_t *)&origPtr) < 0)
|
|
return RET_ERROR;
|
|
if (origPtr > bd->dbufSize)
|
|
return RET_ERROR;
|
|
|
|
symTotal = 0;
|
|
i = 0;
|
|
if (GetBits(bd, 16, &t) < 0)
|
|
return RET_ERROR;
|
|
do {
|
|
if (t & (1 << 15)) {
|
|
uint32_t inner_map;
|
|
if (GetBits(bd, 16, &inner_map) < 0)
|
|
return RET_ERROR;
|
|
do {
|
|
if (inner_map & (1 << 15))
|
|
symToByte[symTotal++] = i;
|
|
inner_map <<= 1;
|
|
i++;
|
|
} while (i & 15);
|
|
i -= 16;
|
|
}
|
|
t <<= 1;
|
|
i += 16;
|
|
} while (i < 256);
|
|
|
|
if (GetBits(bd, 3, (uint32_t *)&groupCount) < 0)
|
|
return RET_ERROR;
|
|
if (groupCount < 2 || groupCount > MAX_GROUPS)
|
|
return RET_ERROR;
|
|
|
|
|
|
for (i = 0; i < groupCount; i++)
|
|
mtfSymbol[i] = i;
|
|
if (GetBits(bd, 15, (uint32_t *)&nSelectors) < 0)
|
|
return RET_ERROR;
|
|
if (!nSelectors)
|
|
return RET_ERROR;
|
|
for (i = 0; i < nSelectors; i++) {
|
|
uint8_t tmp_byte;
|
|
|
|
int n = 0;
|
|
while (GetBits(bd, 1, &tmp) == 0 && tmp) {
|
|
n++;
|
|
if (n >= groupCount)
|
|
return RET_ERROR;
|
|
}
|
|
|
|
tmp_byte = mtfSymbol[n];
|
|
while (--n >= 0)
|
|
mtfSymbol[n + 1] = mtfSymbol[n];
|
|
mtfSymbol[0] = selectors[i] = tmp_byte;
|
|
}
|
|
|
|
|
|
symCount = symTotal + 2;
|
|
for (j = 0; j < groupCount; j++) {
|
|
uint8_t length[MAX_SYMBOLS];
|
|
|
|
uint32_t temp[MAX_HUFCODE_BITS+1];
|
|
struct GroupData *hufGroup;
|
|
int32_t *base, *limit;
|
|
int minLen, maxLen, pp, len_m1;
|
|
|
|
|
|
if (GetBits(bd, 5, (uint32_t *)&len_m1) < 0)
|
|
return RET_ERROR;
|
|
len_m1 -= 1;
|
|
for (i = 0; i < symCount; i++) {
|
|
for (;;) {
|
|
int two_bits;
|
|
if ((uint32_t)len_m1 > (MAX_HUFCODE_BITS - 1))
|
|
return RET_ERROR;
|
|
|
|
if (GetBits(bd, 2, (uint32_t *)&two_bits) < 0)
|
|
return RET_ERROR;
|
|
if (two_bits < 2) {
|
|
bd->inbufBitCount++;
|
|
break;
|
|
}
|
|
|
|
len_m1 += (((two_bits+1) & 2) - 1);
|
|
}
|
|
length[i] = len_m1 + 1;
|
|
}
|
|
|
|
minLen = maxLen = length[0];
|
|
for (i = 1; i < symCount; i++) {
|
|
if (length[i] > maxLen)
|
|
maxLen = length[i];
|
|
else if (length[i] < minLen)
|
|
minLen = length[i];
|
|
}
|
|
|
|
hufGroup = bd->groups + j;
|
|
hufGroup->minLen = minLen;
|
|
hufGroup->maxLen = maxLen;
|
|
|
|
base = &hufGroup->base[0] - 1;
|
|
limit = &hufGroup->limit[0] - 1;
|
|
|
|
pp = 0;
|
|
for (i = minLen; i <= maxLen; i++) {
|
|
int k;
|
|
temp[i] = limit[i] = 0;
|
|
for (k = 0; k < symCount; k++)
|
|
if (length[k] == i)
|
|
hufGroup->permute[pp++] = k;
|
|
}
|
|
|
|
for (i = 0; i < symCount; i++)
|
|
temp[length[i]]++;
|
|
|
|
pp = t = 0;
|
|
for (i = minLen; i < maxLen;) {
|
|
uint32_t temp_i = temp[i];
|
|
|
|
pp += temp_i;
|
|
|
|
limit[i] = (pp << (maxLen - i)) - 1;
|
|
pp <<= 1;
|
|
t += temp_i;
|
|
base[++i] = pp - t;
|
|
}
|
|
limit[maxLen] = pp + temp[maxLen] - 1;
|
|
limit[maxLen+1] = INT32_MAX;
|
|
base[minLen] = 0;
|
|
}
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
byteCount[i] = 0;
|
|
mtfSymbol[i] = (uint8_t)i;
|
|
}
|
|
|
|
runPos = dbufCount = selector = 0;
|
|
for (;;) {
|
|
struct GroupData *hufGroup;
|
|
int *base, *limit;
|
|
int nextSym;
|
|
uint8_t ngrp;
|
|
|
|
symCount = GROUP_SIZE - 1;
|
|
if (selector >= nSelectors)
|
|
return RET_ERROR;
|
|
ngrp = selectors[selector++];
|
|
if (ngrp >= groupCount)
|
|
return RET_ERROR;
|
|
hufGroup = bd->groups + ngrp;
|
|
base = (int *)hufGroup->base - 1;
|
|
limit = (int *)hufGroup->limit - 1;
|
|
|
|
continue_this_group:
|
|
|
|
if (1) {
|
|
|
|
int new_cnt;
|
|
while ((new_cnt = bd->inbufBitCount - hufGroup->maxLen) < 0) {
|
|
|
|
if (bd->inbufPos == bd->inbufCount) {
|
|
if (GetBits(bd, hufGroup->maxLen, (uint32_t *)&nextSym) < 0)
|
|
return RET_ERROR;
|
|
goto got_huff_bits;
|
|
}
|
|
bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++];
|
|
bd->inbufBitCount += 8;
|
|
};
|
|
bd->inbufBitCount = new_cnt;
|
|
nextSym = (bd->inbufBits >> new_cnt) & ((1 << hufGroup->maxLen) - 1);
|
|
got_huff_bits: ;
|
|
} else {
|
|
if (GetBits(bd, hufGroup->maxLen, (uint32_t *)&nextSym) < 0)
|
|
return RET_ERROR;
|
|
}
|
|
|
|
i = hufGroup->minLen;
|
|
while (nextSym > limit[i])
|
|
++i;
|
|
j = hufGroup->maxLen - i;
|
|
if (j < 0)
|
|
return RET_ERROR;
|
|
bd->inbufBitCount += j;
|
|
|
|
|
|
nextSym = (nextSym >> j) - base[i];
|
|
if ((unsigned)nextSym >= MAX_SYMBOLS)
|
|
return RET_ERROR;
|
|
nextSym = hufGroup->permute[nextSym];
|
|
|
|
|
|
if ((unsigned)nextSym <= SYMBOL_RUNB) {
|
|
|
|
|
|
if (runPos == 0) {
|
|
runPos = 1;
|
|
runCnt = 0;
|
|
}
|
|
|
|
runCnt += (runPos << nextSym);
|
|
if (runPos < bd->dbufSize) runPos <<= 1;
|
|
goto end_of_huffman_loop;
|
|
}
|
|
|
|
if (runPos != 0) {
|
|
uint8_t tmp_byte;
|
|
if (dbufCount + runCnt > bd->dbufSize)
|
|
return RET_ERROR;
|
|
tmp_byte = symToByte[mtfSymbol[0]];
|
|
byteCount[tmp_byte] += runCnt;
|
|
while ((int)--runCnt >= 0)
|
|
dbuf[dbufCount++] = (uint32_t)tmp_byte;
|
|
runPos = 0;
|
|
}
|
|
|
|
if (nextSym > symTotal)
|
|
break;
|
|
if (dbufCount >= bd->dbufSize)
|
|
return RET_ERROR;
|
|
i = nextSym - 1;
|
|
uc = mtfSymbol[i];
|
|
|
|
do {
|
|
mtfSymbol[i] = mtfSymbol[i - 1];
|
|
} while (--i);
|
|
mtfSymbol[0] = uc;
|
|
uc = symToByte[uc];
|
|
|
|
byteCount[uc]++;
|
|
dbuf[dbufCount++] = (uint32_t)uc;
|
|
|
|
end_of_huffman_loop:
|
|
if (--symCount >= 0) goto continue_this_group;
|
|
}
|
|
|
|
j = 0;
|
|
for (i = 0; i < 256; i++) {
|
|
int tmp_count = j + byteCount[i];
|
|
byteCount[i] = j;
|
|
j = tmp_count;
|
|
}
|
|
|
|
for (i = 0; i < dbufCount; i++) {
|
|
uint8_t tmp_byte = (uint8_t)dbuf[i];
|
|
int tmp_count = byteCount[tmp_byte];
|
|
dbuf[tmp_count] |= (i << 8);
|
|
byteCount[tmp_byte] = tmp_count + 1;
|
|
}
|
|
|
|
if (dbufCount) {
|
|
uint32_t tmp;
|
|
if ((int)origPtr >= dbufCount)
|
|
return RET_ERROR;
|
|
tmp = dbuf[origPtr];
|
|
bd->writeCurrent = (uint8_t)tmp;
|
|
bd->writePos = (tmp >> 8);
|
|
bd->writeRunCountdown = 5;
|
|
}
|
|
bd->writeCount = dbufCount;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ReadBunzip(BunZipData_t *bd, char *outbuf, int len)
|
|
{
|
|
const uint32_t *dbuf;
|
|
int pos, current, previous;
|
|
uint32_t CRC;
|
|
|
|
|
|
if (bd->writeCount < 0)
|
|
return bd->writeCount;
|
|
|
|
dbuf = bd->dbuf;
|
|
|
|
|
|
pos = bd->writePos;
|
|
current = bd->writeCurrent;
|
|
CRC = bd->writeCRC;
|
|
|
|
|
|
if (bd->writeCopies) {
|
|
|
|
dec_writeCopies:
|
|
|
|
--bd->writeCopies;
|
|
|
|
for (;;) {
|
|
|
|
|
|
if (--len < 0) {
|
|
|
|
goto outbuf_full;
|
|
}
|
|
|
|
|
|
*outbuf++ = current;
|
|
CRC = (CRC << 8) ^ bd->crc32Table[(CRC >> 24) ^ current];
|
|
|
|
|
|
if (bd->writeCopies) {
|
|
|
|
goto dec_writeCopies;
|
|
}
|
|
decode_next_byte:
|
|
if (--bd->writeCount < 0)
|
|
break;
|
|
|
|
previous = current;
|
|
pos = dbuf[pos];
|
|
current = (uint8_t)pos;
|
|
pos >>= 8;
|
|
|
|
if (--bd->writeRunCountdown != 0) {
|
|
if (current != previous)
|
|
bd->writeRunCountdown = 4;
|
|
} else {
|
|
|
|
bd->writeCopies = current;
|
|
current = previous;
|
|
bd->writeRunCountdown = 5;
|
|
|
|
|
|
if (!bd->writeCopies) goto decode_next_byte;
|
|
|
|
|
|
--bd->writeCopies;
|
|
}
|
|
}
|
|
|
|
|
|
bd->writeCRC = CRC = ~CRC;
|
|
bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ CRC;
|
|
|
|
if (CRC != bd->headerCRC) {
|
|
bd->totalCRC = bd->headerCRC + 1;
|
|
return RET_LASTBLOCK;
|
|
}
|
|
}
|
|
|
|
{
|
|
int r = GetNextBlock(bd);
|
|
if (r) {
|
|
bd->writeCount = r;
|
|
return (r != RET_LASTBLOCK) ? r : len;
|
|
}
|
|
}
|
|
|
|
CRC = ~0;
|
|
pos = bd->writePos;
|
|
current = bd->writeCurrent;
|
|
goto decode_next_byte;
|
|
|
|
outbuf_full:
|
|
bd->writePos = pos;
|
|
bd->writeCurrent = current;
|
|
bd->writeCRC = CRC;
|
|
|
|
bd->writeCopies++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void Crc32FilltableBigEndian(uint32_t *crc_table)
|
|
{
|
|
uint32_t polynomial = 0x04c11db7;
|
|
uint32_t c;
|
|
unsigned i, j;
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
c = i << 24;
|
|
for (j = 8; j; j--) {
|
|
c = (c & 0x80000000) ? ((c << 1) ^ polynomial) : (c << 1);
|
|
}
|
|
*crc_table++ = c;
|
|
}
|
|
}
|
|
|
|
static int StartBunzip(BunZipData_t **bdp, int in_fd,
|
|
const void *inbuf, int len)
|
|
{
|
|
BunZipData_t *bd;
|
|
uint32_t i;
|
|
enum {
|
|
BZh0 = ('B' << 24) + ('Z' << 16) + ('h' << 8) + '0',
|
|
h0 = ('h' << 8) + '0',
|
|
};
|
|
|
|
i = sizeof(BunZipData_t);
|
|
if (in_fd != -1)
|
|
i += IOBUF_SIZE;
|
|
|
|
bd = *bdp = malloc(i);
|
|
if (bd == NULL)
|
|
return RET_ERROR;
|
|
memset(bd, 0, sizeof(*bd));
|
|
|
|
bd->in_fd = in_fd;
|
|
if (in_fd == -1) {
|
|
bd->inbuf = (void *)inbuf;
|
|
} else {
|
|
bd->inbuf = (uint8_t *)(bd + 1);
|
|
memcpy(bd->inbuf, inbuf, len);
|
|
}
|
|
bd->inbufCount = len;
|
|
|
|
Crc32FilltableBigEndian(bd->crc32Table);
|
|
|
|
if (GetBits(bd, 16, (uint32_t *)&i) < 0)
|
|
return RET_ERROR;
|
|
if ((unsigned)(i - h0 - 1) >= 9)
|
|
return RET_ERROR;
|
|
|
|
bd->dbufSize = 100000 * (i - h0);
|
|
|
|
bd->dbuf = malloc(bd->dbufSize * sizeof(bd->dbuf[0]));
|
|
if (!bd->dbuf) {
|
|
free(bd);
|
|
return RET_ERROR;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int Bzip2Decompress(char *file_name)
|
|
{
|
|
BunZipData_t *bd;
|
|
char *out_buf;
|
|
int i;
|
|
uint32_t len;
|
|
int in_fd, out_fd;
|
|
uint16_t magic;
|
|
int ret = 0;
|
|
|
|
if ((in_fd = open(file_name, O_RDONLY)) < 0)
|
|
return RET_ERROR;
|
|
|
|
if (TruncateExtension(file_name, ".bz2") < 0) {
|
|
ret = RET_ERROR;
|
|
goto close_in_fd;
|
|
}
|
|
if ((out_fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC)) < 0) {
|
|
ret = RET_ERROR;
|
|
goto close_in_fd;
|
|
}
|
|
|
|
if ((out_buf = malloc(IOBUF_SIZE)) == NULL) {
|
|
ret = RET_ERROR;
|
|
goto close_out_fd;
|
|
}
|
|
|
|
if (read(in_fd, &magic, 2) != 2 || magic != BZIP2_MAGIC) {
|
|
ret = -1;
|
|
goto free_out_buf;
|
|
}
|
|
|
|
len = 0;
|
|
while (1) {
|
|
i = StartBunzip(&bd, in_fd, out_buf + 2, len);
|
|
if (i == 0) {
|
|
while (1) {
|
|
i = ReadBunzip(bd, out_buf, IOBUF_SIZE);
|
|
if (i < 0)
|
|
break;
|
|
i = IOBUF_SIZE - i;
|
|
if (i == 0)
|
|
break;
|
|
if (write(out_fd, out_buf, i) != i) {
|
|
ret = RET_ERROR;
|
|
goto free_bd;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (i != 0 && i != RET_LASTBLOCK)
|
|
break;
|
|
if (bd->headerCRC != bd->totalCRC)
|
|
break;
|
|
|
|
i = 0;
|
|
|
|
len = bd->inbufCount - bd->inbufPos;
|
|
memcpy(out_buf, &bd->inbuf[bd->inbufPos], len);
|
|
if (len < 2) {
|
|
if (read(in_fd, out_buf + len, 2 - len) != 2 - len)
|
|
break;
|
|
len = 2;
|
|
}
|
|
if (*(uint16_t *)out_buf != BZIP2_MAGIC)
|
|
break;
|
|
free(bd->dbuf);
|
|
free(bd);
|
|
len -=2;
|
|
}
|
|
|
|
free_bd:
|
|
free(bd->dbuf);
|
|
free(bd);
|
|
free_out_buf:
|
|
free(out_buf);
|
|
close_out_fd:
|
|
close(out_fd);
|
|
close_in_fd:
|
|
close(in_fd);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void Bunzip2PrintUsage()
|
|
{
|
|
KPrintf("Usage: bunzip2 [FILES]....\n");
|
|
KPrintf("File names MUST end with the .bz2 extension\n");
|
|
}
|
|
|
|
int bunzip2(int argc, char **argv)
|
|
{
|
|
if (argc < 2) {
|
|
Bunzip2PrintUsage();
|
|
return 0;
|
|
}
|
|
|
|
for (int i = 1; i < argc; i++)
|
|
if (Bzip2Decompress(argv[i]) < 0)
|
|
KPrintf("Operation failed: %s\n", argv[i]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
#endif
|