xiuos/tool/shell/letter-shell/file_ext/gunzip.c

1026 lines
25 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 <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <iot-vfs_posix.h>
#include <gunzip.h>
#include "utility.h"
#define USE_HEAP_MEM
struct globals {
uint32_t crc32;
int in_fd;
int out_fd;
size_t outcnt;
size_t outbuf_cnt;
unsigned char window[GUNZIP_WSIZE];
unsigned char bytebuffer[GUNZIP_BYTEBUFFER_MAX];
uint32_t bytebuffer_offset;
uint32_t bytebuffer_size;
uint32_t to_read;
uint32_t bi_buf;
uint32_t bi_valid;
uint32_t inflate_codes_ml;
uint32_t inflate_codes_md;
uint32_t inflate_codes_bb;
uint32_t inflate_codes_k;
uint32_t inflate_codes_w;
uint32_t inflate_codes_bl;
uint32_t inflate_codes_bd;
uint32_t inflate_codes_nn;
uint32_t inflate_codes_dd;
huft_t *inflate_codes_tl;
huft_t *inflate_codes_td;
int resume_copy;
int method;
int need_another_block;
int eof;
uint32_t inflate_stored_n;
uint32_t inflate_stored_b;
uint32_t inflate_stored_k;
uint32_t inflate_stored_w;
};
#ifdef USE_HEAP_MEM
static struct globals *glbp;
#define GLB (*glbp)
#else
struct globals GLB;
#endif
static const uint16_t mask_bits[] = {
0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
};
static const uint16_t cplens[] = {
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
};
static const uint8_t cplext[] = {
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5,
5, 5, 5, 0, 99, 99
};
static const uint16_t cpdist[] = {
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, 8193, 12289, 16385, 24577
};
static const uint8_t cpdext[] = {
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
11, 11, 12, 12, 13, 13
};
static const uint8_t border[] = {
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
};
static void InitInflateCodes(uint32_t bl, uint32_t bd)
{
GLB.inflate_codes_bl = bl;
GLB.inflate_codes_bd = bd;
GLB.inflate_codes_bb = GLB.bi_buf;
GLB.inflate_codes_k = GLB.bi_valid;
GLB.inflate_codes_w = GLB.outbuf_cnt;
GLB.inflate_codes_ml = mask_bits[bl];
GLB.inflate_codes_md = mask_bits[bd];
}
static int InflateCodes();
static void HuftFree(huft_t *p)
{
huft_t *q;
while (p) {
q = (--p)->t;
free(p);
p = q;
}
}
static int HuftBuild(const uint32_t *b, const uint32_t n,
const uint32_t s, const uint16_t *d,
const unsigned char *e, huft_t **t, uint32_t *m)
{
uint32_t a;
uint32_t c[BMAX + 1];
uint32_t eob_len;
uint32_t f;
int g;
int htl;
uint32_t i;
uint32_t j;
int k;
const uint32_t *p;
huft_t *q;
huft_t r;
huft_t *u[BMAX];
uint32_t v[NMAX + 1];
int ws[BMAX + 1];
int w;
uint32_t x[BMAX + 1];
uint32_t *xp;
int y;
uint32_t z;
eob_len = n > 256 ? b[256] : BMAX;
*t = NULL;
memset(c, 0, sizeof(c));
p = b;
i = n;
do {
c[*p]++;
p++;
} while (--i);
if (c[0] == n) {
q = malloc(3 * sizeof(*q));
memset(q, 0, 3 * sizeof(*q));
q[1].e = 99;
q[1].b = 1;
q[2].e = 99;
q[2].b = 1;
*t = q + 1;
*m = 1;
return 0;
}
for (j = 1; (j <= BMAX) && (c[j] == 0); j++)
continue;
k = j;
for (i = BMAX; (c[i] == 0) && i; i--)
continue;
g = i;
*m = (*m < j) ? j : ((*m > i) ? i : *m);
for (y = 1 << j; j < i; j++, y <<= 1) {
y -= c[j];
if (y < 0)
return -1;
}
y -= c[i];
if (y < 0)
return -1;
c[i] += y;
x[1] = j = 0;
p = c + 1;
xp = x + 2;
while (--i) {
j += *p++;
*xp++ = j;
}
memset(v, 0xff, sizeof(v));
p = b;
i = 0;
do {
j = *p++;
if (j != 0) {
v[x[j]++] = i;
}
} while (++i < n);
x[0] = i = 0;
p = v;
htl = -1;
w = ws[0] = 0;
u[0] = NULL;
q = NULL;
z = 0;
for (; k <= g; k++) {
a = c[k];
while (a--) {
while (k > ws[htl + 1]) {
w = ws[++htl];
z = g - w;
z = z > *m ? *m : z;
j = k - w;
f = 1 << j;
if (f > a + 1) {
f -= a + 1;
xp = c + k;
while (++j < z) {
f <<= 1;
if (f <= *++xp) {
break;
}
f -= *xp;
}
}
j = (w + j > eob_len && w < eob_len) ? eob_len - w : j;
z = 1 << j;
ws[htl+1] = w + j;
q = malloc((z + 1) * sizeof(huft_t));
memset(q, 0, (z + 1) * sizeof(huft_t));
*t = q + 1;
t = &(q->t);
u[htl] = ++q;
if (htl) {
x[htl] = i;
r.b = (unsigned char)(w - ws[htl - 1]);
r.e = (unsigned char)(16 + j);
r.t = q;
j = (i & ((1 << w) - 1)) >> ws[htl - 1];
u[htl - 1][j] = r;
}
}
r.b = (unsigned char)(k - w);
if (*p == 0xffffffff) {
r.e = 99;
} else if (*p < s) {
r.e = (unsigned char)(*p < 256 ? 16 : 15);
r.n = (unsigned short)(*p++);
} else {
r.e = (unsigned char)e[*p - s];
r.n = d[*p++ - s];
}
f = 1 << (k - w);
for (j = i >> w; j < z; j += f) {
q[j] = r;
}
for (j = 1 << (k - 1); i & j; j >>= 1) {
i ^= j;
}
i ^= j;
while ((i & ((1 << w) - 1)) != x[htl]) {
w = ws[--htl];
}
}
}
*m = ws[1];
return y != 0 && g != 1 ? -1 : 0;
}
int FillBitBuffer(uint32_t *bitbuffer, uint32_t *current_len,
uint32_t required_len)
{
while (*current_len < required_len) {
if (GLB.bytebuffer_offset >= GLB.bytebuffer_size) {
uint32_t size = GUNZIP_BYTEBUFFER_MAX - 4;
if (GLB.to_read >= 0 && GLB.to_read < size)
size = GLB.to_read;
GLB.bytebuffer_size = read(GLB.in_fd, &GLB.bytebuffer[4], size);
if (GLB.bytebuffer_size == 0) {
return -1;
}
if (GLB.to_read >= 0)
GLB.to_read -= GLB.bytebuffer_size;
GLB.bytebuffer_size += 4;
GLB.bytebuffer_offset = 4;
}
*bitbuffer |= (uint32_t)GLB.bytebuffer[GLB.bytebuffer_offset]
<< *current_len;
GLB.bytebuffer_offset++;
*current_len += 8;
}
return 0;
}
static int InflateBlock()
{
uint32_t ll[286 + 30];
uint32_t t;
uint32_t b;
uint32_t k;
b = GLB.bi_buf;
k = GLB.bi_valid;
if (FillBitBuffer(&b, &k, 1) < 0)
return -1;
GLB.eof = b & 1;
b >>= 1;
k -= 1;
if (FillBitBuffer(&b, &k, 2) < 0)
return -1;
t = b & 0x3;
b >>= 2;
k -= 2;
GLB.bi_buf = b;
GLB.bi_valid = k;
switch (t) {
case 0: {
uint32_t n;
uint32_t b_stored;
uint32_t k_stored;
b_stored = GLB.bi_buf;
k_stored = GLB.bi_valid;
n = k_stored & 0x7;
b_stored >>= n;
k_stored -= n;
if (FillBitBuffer(&b_stored, &k_stored, 16) < 0)
return -1;
n = b_stored & 0xffff;
b_stored >>= 16;
k_stored -= 16;
if (FillBitBuffer(&b_stored, &k_stored, 16) < 0)
return -1;
if (n != ((~b_stored) & 0xffff))
return -1;
b_stored >>= 16;
k_stored -= 16;
GLB.inflate_stored_n = n;
GLB.inflate_stored_b = b_stored;
GLB.inflate_stored_k = k_stored;
return STORED;
}
case 1: {
int i;
uint32_t bl;
uint32_t bd;
for (i = 0; i < 144; i++)
ll[i] = 8;
for (; i < 256; i++)
ll[i] = 9;
for (; i < 280; i++)
ll[i] = 7;
for (; i < 288; i++)
ll[i] = 8;
bl = 7;
HuftBuild(ll, 288, 257, cplens, cplext,
&GLB.inflate_codes_tl, &bl);
for (i = 0; i < 30; i++)
ll[i] = 5;
bd = 5;
HuftBuild(ll, 30, 0, cpdist, cpdext,
&GLB.inflate_codes_td, &bd);
InitInflateCodes(bl, bd);
return CODES;
}
case 2: {
int dbits = 6;
int lbits = 9;
huft_t *td;
uint32_t i;
uint32_t j;
uint32_t l;
uint32_t m;
uint32_t n;
uint32_t bl;
uint32_t bd;
uint32_t nb;
uint32_t nl;
uint32_t nd;
uint32_t b_dynamic;
uint32_t k_dynamic;
b_dynamic = GLB.bi_buf;
k_dynamic = GLB.bi_valid;
if (FillBitBuffer(&b_dynamic, &k_dynamic, 5) < 0)
return -1;
nl = 257 + (b_dynamic & 0x1f);
b_dynamic >>= 5;
k_dynamic -= 5;
if (FillBitBuffer(&b_dynamic, &k_dynamic, 5) < 0)
return -1;
nd = 1 + (b_dynamic & 0x1f);
b_dynamic >>= 5;
k_dynamic -= 5;
if (FillBitBuffer(&b_dynamic, &k_dynamic, 4) < 0)
return -1;
nb = 4 + (b_dynamic & 0xf);
b_dynamic >>= 4;
k_dynamic -= 4;
if (nl > 286 || nd > 30)
return -1;
for (j = 0; j < nb; j++) {
if (FillBitBuffer(&b_dynamic, &k_dynamic, 3) < 0)
return -1;
ll[border[j]] = b_dynamic & 0x7;
b_dynamic >>= 3;
k_dynamic -= 3;
}
for (; j < 19; j++)
ll[border[j]] = 0;
bl = 7;
i = HuftBuild(ll, 19, 19, NULL, NULL,
&GLB.inflate_codes_tl, &bl);
if (i < 0)
return -1;
n = nl + nd;
m = mask_bits[bl];
i = l = 0;
while (i < n) {
if (FillBitBuffer(&b_dynamic, &k_dynamic, bl) < 0)
return -1;
td = GLB.inflate_codes_tl + (b_dynamic & m);
j = td->b;
b_dynamic >>= j;
k_dynamic -= j;
j = td->n;
if (j < 16) {
ll[i++] = l = j;
} else if (j == 16) {
if (FillBitBuffer(&b_dynamic, &k_dynamic, 2) < 0)
return -1;
j = 3 + (b_dynamic & 3);
b_dynamic >>= 2;
k_dynamic -= 2;
if (i + j > n)
return -1;
while (j--) {
ll[i++] = l;
}
} else if (j == 17) {
if (FillBitBuffer(&b_dynamic, &k_dynamic, 3) < 0)
return -1;
j = 3 + (b_dynamic & 7);
b_dynamic >>= 3;
k_dynamic -= 3;
if (i + j > n)
return -1;
while (j--) {
ll[i++] = 0;
}
l = 0;
} else {
if (FillBitBuffer(&b_dynamic, &k_dynamic, 7) < 0)
return -1;
j = 11 + ((unsigned) b_dynamic & 0x7f);
b_dynamic >>= 7;
k_dynamic -= 7;
if ((unsigned) i + j > n)
return -1;
while (j--)
ll[i++] = 0;
l = 0;
}
}
HuftFree(GLB.inflate_codes_tl);
GLB.bi_buf = b_dynamic;
GLB.bi_valid = k_dynamic;
bl = lbits;
i = HuftBuild(ll, nl, 257, cplens, cplext,
&GLB.inflate_codes_tl, &bl);
if (i < 0)
return -1;
bd = dbits;
i = HuftBuild(ll + nl, nd, 0, cpdist, cpdext,
&GLB.inflate_codes_td, &bd);
if (i < 0)
return -1;
InitInflateCodes(bl, bd);
return CODES;
}
default:
return -1;
}
}
static int InflateStored()
{
while (GLB.inflate_stored_n--) {
if (FillBitBuffer(&GLB.inflate_stored_b,
&GLB.inflate_stored_k, 8) < 0)
return -1;
GLB.window[GLB.inflate_stored_w++] =
(unsigned char)GLB.inflate_stored_b;
GLB.inflate_stored_b >>= 8;
GLB.inflate_stored_k -= 8;
if (GLB.inflate_stored_w == GUNZIP_WSIZE) {
GLB.outbuf_cnt = GLB.inflate_stored_w;
GLB.inflate_stored_w = 0;
return 1;
}
}
GLB.outbuf_cnt = GLB.inflate_stored_w;
GLB.bi_buf = GLB.inflate_stored_b;
GLB.bi_valid = GLB.inflate_stored_k;
return 0;
}
static int InflateCodes()
{
unsigned e;
huft_t *t;
if (GLB.resume_copy)
goto do_copy;
while (1) {
if (FillBitBuffer(&GLB.inflate_codes_bb,
&GLB.inflate_codes_k,GLB.inflate_codes_bl) < 0)
return -1;
t = GLB.inflate_codes_tl +
(GLB.inflate_codes_bb & GLB.inflate_codes_ml);
e = t->e;
if (e > 16)
do {
if (e == 99)
return -1;
GLB.inflate_codes_bb >>= t->b;
GLB.inflate_codes_k -= t->b;
e -= 16;
if (FillBitBuffer(&GLB.inflate_codes_bb,
&GLB.inflate_codes_k, e) < 0)
return -1;
t = t->t + (GLB.inflate_codes_bb & mask_bits[e]);
e = t->e;
} while (e > 16);
GLB.inflate_codes_bb >>= t->b;
GLB.inflate_codes_k -= t->b;
if (e == 16) {
GLB.window[GLB.inflate_codes_w++] = (unsigned char)t->n;
if (GLB.inflate_codes_w == GUNZIP_WSIZE) {
GLB.outbuf_cnt = GLB.inflate_codes_w;
GLB.inflate_codes_w = 0;
return 1;
}
} else {
if (e == 15)
break;
if (FillBitBuffer(&GLB.inflate_codes_bb,
&GLB.inflate_codes_k, e) < 0)
return -1;
GLB.inflate_codes_nn = t->n +
(GLB.inflate_codes_bb & mask_bits[e]);
GLB.inflate_codes_bb >>= e;
GLB.inflate_codes_k -= e;
if (FillBitBuffer(&GLB.inflate_codes_bb,
&GLB.inflate_codes_k, GLB.inflate_codes_bd) < 0)
return -1;
t = GLB.inflate_codes_td +
(GLB.inflate_codes_bb & GLB.inflate_codes_md);
e = t->e;
if (e > 16)
do {
if (e == 99)
return -1;
GLB.inflate_codes_bb >>= t->b;
GLB.inflate_codes_k -= t->b;
e -= 16;
if (FillBitBuffer(&GLB.inflate_codes_bb,
&GLB.inflate_codes_k, e) < 0)
return -1;
t = t->t + (GLB.inflate_codes_bb & mask_bits[e]);
e = t->e;
} while (e > 16);
GLB.inflate_codes_bb >>= t->b;
GLB.inflate_codes_k -= t->b;
if (FillBitBuffer(&GLB.inflate_codes_bb,
&GLB.inflate_codes_k, e) < 0)
return -1;
GLB.inflate_codes_dd = GLB.inflate_codes_w - t->n -
(GLB.inflate_codes_bb & mask_bits[e]);
GLB.inflate_codes_bb >>= e;
GLB.inflate_codes_k -= e;
do_copy:
do {
uint32_t delta;
GLB.inflate_codes_dd &= GUNZIP_WSIZE - 1;
e = GUNZIP_WSIZE -
(GLB.inflate_codes_dd > GLB.inflate_codes_w ?
GLB.inflate_codes_dd : GLB.inflate_codes_w);
delta = GLB.inflate_codes_w > GLB.inflate_codes_dd ?
GLB.inflate_codes_w - GLB.inflate_codes_dd :
GLB.inflate_codes_dd - GLB.inflate_codes_w;
if (e > GLB.inflate_codes_nn)
e = GLB.inflate_codes_nn;
GLB.inflate_codes_nn -= e;
if (delta >= e) {
memcpy(GLB.window + GLB.inflate_codes_w,
GLB.window + GLB.inflate_codes_dd, e);
GLB.inflate_codes_w += e;
GLB.inflate_codes_dd += e;
} else {
do {
GLB.window[GLB.inflate_codes_w++] =
GLB.window[GLB.inflate_codes_dd++];
} while (--e);
}
if (GLB.inflate_codes_w == GUNZIP_WSIZE) {
GLB.outbuf_cnt = GLB.inflate_codes_w;
GLB.resume_copy = (GLB.inflate_codes_nn != 0);
GLB.inflate_codes_w = 0;
return 1;
}
} while (GLB.inflate_codes_nn);
GLB.resume_copy = 0;
}
}
GLB.outbuf_cnt = GLB.inflate_codes_w;
GLB.bi_buf = GLB.inflate_codes_bb;
GLB.bi_valid = GLB.inflate_codes_k;
HuftFree(GLB.inflate_codes_tl);
HuftFree(GLB.inflate_codes_td);
GLB.inflate_codes_tl = NULL;
GLB.inflate_codes_td = NULL;
return 0;
}
static void UpdateCrc32(unsigned char *buf, size_t len)
{
for (int i = 0; i < len; i++) {
GLB.crc32 = GLB.crc32 ^ buf[i];
for (int j = 0; j < 8; j++)
GLB.crc32 = (GLB.crc32 >> 1) ^
(0xedb88320 & -(GLB.crc32 & 1));
}
}
static int InflateGetNextWindow()
{
while (1) {
int ret;
if (GLB.need_another_block) {
if (GLB.eof) {
UpdateCrc32(GLB.window, GLB.outbuf_cnt);
GLB.eof = 0;
return 0;
}
GLB.method = InflateBlock();
GLB.need_another_block = 0;
}
switch (GLB.method) {
case STORED:
ret = InflateStored();
break;
case CODES:
ret = InflateCodes();
break;
default:
return -1;
}
if (ret < 0)
return -1;
if (ret == 1) {
UpdateCrc32(GLB.window, GLB.outbuf_cnt);
return 1;
}
GLB.need_another_block = 1;
}
}
static inline int FlushOutbuf()
{
int written_size = write(GLB.out_fd, GLB.window, GLB.outbuf_cnt);
int ret = written_size == GLB.outbuf_cnt ? 0 : -1;
GLB.outcnt += written_size;
GLB.outbuf_cnt = 0;
return ret;
}
static int inflate()
{
GLB.crc32 = ~0;
GLB.outcnt = 0;
GLB.outbuf_cnt = 0;
GLB.method = -1;
GLB.need_another_block = 1;
GLB.resume_copy = 0;
GLB.bi_buf = 0;
GLB.bi_valid = 0;
while (1) {
int ret = InflateGetNextWindow();
if (ret < 0)
return -1;
if (FlushOutbuf() < 0)
return -1;
if (ret == 0)
break;
}
if (GLB.bi_valid >= 8) {
GLB.bytebuffer_offset--;
GLB.bytebuffer[GLB.bytebuffer_offset] = GLB.bi_buf & 0xff;
GLB.bi_buf >>= 8;
GLB.bi_valid -= 8;
}
return 0;
}
static int FillByteBuffer(int n)
{
int count = GLB.bytebuffer_size - GLB.bytebuffer_offset;
if (count < n) {
memmove(GLB.bytebuffer,
&GLB.bytebuffer[GLB.bytebuffer_offset], count);
GLB.bytebuffer_offset = 0;
GLB.bytebuffer_size = read(GLB.in_fd,
&GLB.bytebuffer[count], GUNZIP_BYTEBUFFER_MAX - count);
if ((int)GLB.bytebuffer_size < 0)
return -1;
GLB.bytebuffer_size += count;
if (GLB.bytebuffer_size < n)
return -1;
}
return 0;
}
static uint16_t BufferRead16()
{
uint16_t res;
res = GLB.bytebuffer[GLB.bytebuffer_offset];
res |= GLB.bytebuffer[GLB.bytebuffer_offset + 1] << 8;
GLB.bytebuffer_offset += 2;
return res;
}
static uint32_t BufferRead32()
{
uint32_t res;
res = GLB.bytebuffer[GLB.bytebuffer_offset];
res |= (uint32_t)GLB.bytebuffer[GLB.bytebuffer_offset + 1] << 8;
res |= (uint32_t)GLB.bytebuffer[GLB.bytebuffer_offset + 2] << 16;
res |= (uint32_t)GLB.bytebuffer[GLB.bytebuffer_offset + 3] << 24;
GLB.bytebuffer_offset += 4;
return res;
}
int InflateUnzip(int zip_fd, int dst_fd, uint32_t cmpsize,
uint32_t ucmpsize, uint32_t crc32) {
int ret = 0;
#ifdef USE_HEAP_MEM
glbp = malloc(sizeof(struct globals));
if (glbp == NULL) {
KPrintf("Memory too small\n");
return -1;
}
#endif
memset(&GLB, 0, sizeof(struct globals));
GLB.to_read = cmpsize;
GLB.bytebuffer_offset = 4;
GLB.in_fd = zip_fd;
GLB.out_fd = dst_fd;
if ((ret = inflate()) < 0)
goto free_glbp;
ret = ucmpsize == GLB.outcnt && ~crc32 == GLB.crc32;
free_glbp:
#ifdef USE_HEAP_MEM
free(glbp);
#endif
return ret;
}
static int GunzipCheckFooter()
{
int crc32, length;
if (FillByteBuffer(8) < 0)
return -1;
crc32 = BufferRead32();
length = BufferRead32();
if (~GLB.crc32 != crc32 || length != GLB.outcnt)
return -1;
return 0;
}
static int GunzipCheckHeader()
{
GzipHdr_t hdr;
if (FillByteBuffer(8) < 0)
return -1;
memcpy(&hdr, &GLB.bytebuffer[GLB.bytebuffer_offset], 8);
GLB.bytebuffer_offset += 8;
if (hdr.gz_method != 8)
return -1;
if (hdr.flags & 0x04) {
uint16_t extra_len;
extra_len = BufferRead16();
if (FillByteBuffer(extra_len) < 0)
return -1;
GLB.bytebuffer_offset += extra_len;
}
if (hdr.flags & 0x18) {
while (1) {
do {
if (FillByteBuffer(1) < 0)
return -1;
} while (GLB.bytebuffer[GLB.bytebuffer_offset++] != 0);
if ((hdr.flags & 0x18) != 0x18)
break;
hdr.flags &= ~0x18;
}
}
if (hdr.flags & 0x02) {
if (FillByteBuffer(2) < 0)
return -1;
GLB.bytebuffer_offset += 2;
}
return 0;
}
static int GunzipCheckMagic()
{
uint16_t magic;
if (FillByteBuffer(2) < 0)
return -1;
magic = BufferRead16();
if (magic != 0x8b1f)
return -1;
return 0;
}
int GzipDecompress(char *file_name)
{
int ret = 0;
#ifdef USE_HEAP_MEM
glbp = malloc(sizeof(struct globals));
if (glbp == NULL) {
KPrintf("Memory too small\n");
return -1;
}
#endif
memset(&GLB, 0, sizeof(struct globals));
GLB.to_read = -1;
if ((GLB.in_fd = open(file_name, O_RDONLY)) < 0) {
ret = -1;
goto free_glbp;
}
if (TruncateExtension(file_name, ".gz") < 0) {
KPrintf("Invalid extension: %s\n", file_name);
ret = -1;
goto close_in_fd;
}
if ((GLB.out_fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC)) < 0) {
ret = -1;
goto close_in_fd;
}
strcat(file_name, ".gz");
if (GunzipCheckMagic() < 0) {
KPrintf("Invalid magic number: %s\n", file_name);
ret = -1;
goto close_out_fd;
}
again:
if (GunzipCheckHeader() < 0) {
KPrintf("Invalid header: %s\n", file_name);
ret = -1;
goto close_out_fd;
}
if ((inflate()) < 0) {
ret = -1;
goto close_out_fd;
}
if (GunzipCheckFooter() < 0) {
KPrintf("Invalid footer (checksum or length): %s\n", file_name);
ret = -1;
}
if (GunzipCheckMagic() == 0)
goto again;
close_out_fd:
close(GLB.out_fd);
close_in_fd:
close(GLB.in_fd);
free_glbp:
#ifdef USE_HEAP_MEM
free(glbp);
#endif
return ret;
}
static void GunzipPrintUsage()
{
KPrintf("Usage: gunzip [FILEs]...\n");
KPrintf("File names MUST end with the .gz extension\n");
}
int gunzip(int argc, char **argv)
{
int ret = 0;
if (argc < 2) {
GunzipPrintUsage();
return 0;
}
for (int i = 1; i < argc; i++)
if (GzipDecompress(argv[i]) < 0)
ret = -1;
if (ret < 0)
KPrintf("Failed to extract (some) file(s)\n");
return 0;
}
#endif