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

1021 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 <iot-vfs_posix.h>
#include <string.h>
#include <stdio.h>
#include <gzip.h>
#include <stdlib.h>
#include <stdint.h>
#include "utility.h"
#define USE_HEAP_MEM
static const uint8_t extra_lbits[LENGTH_CODES] = {
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,
};
static const uint8_t extra_dbits[D_CODES] = {
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 extra_blbits[BL_CODES] = {
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 2, 3, 7,
};
static const uint8_t bl_order[BL_CODES] = {
16, 17, 18, 0, 8, 7, 9,
6, 10, 5, 11, 4, 12, 3,
13, 2, 14, 1, 15,
};
struct globals {
unsigned char window[2 * WSIZE];
unsigned char l_buf[LIT_BUFSIZE];
uint16_t d_buf[DIST_BUFSIZE];
unsigned char flag_buf[LIT_BUFSIZE / 8];
unsigned char outbuf[OUTBUF_SIZE];
uint16_t prev[2 * WSIZE];
#define HEAD (GLB.prev + WSIZE)
uint32_t bi_buf;
uint32_t bi_valid;
#define BUF_SIZE 32
unsigned char flags;
unsigned char flag_bit;
int last_lit;
int last_dist;
int last_flags;
int in_fd, out_fd;
uint32_t crc32;
int block_start;
int ins_h;
int prev_length;
int strstart;
int match_start;
int lookahead;
int incnt;
int outcnt;
int eofile;
uint16_t heap[HEAP_SIZE];
int heap_len;
int heap_max;
CtDate_t dyn_ltree[HEAP_SIZE];
CtDate_t dyn_dtree[2 * D_CODES + 1];
CtDate_t static_ltree[L_CODES + 2];
CtDate_t static_dtree[D_CODES];
CtDate_t bl_tree[2 * BL_CODES + 1];
TreeDesc_t l_desc;
TreeDesc_t d_desc;
TreeDesc_t bl_desc;
uint16_t bl_count[MAX_BITS + 1];
unsigned char depth[2 * L_CODES + 1];
unsigned char length_code[MAX_MATCH - MIN_MATCH + 1];
int base_length[LENGTH_CODES];
unsigned char dist_code[512];
int base_dist[D_CODES];
int opt_len;
int static_len;
};
#ifdef USE_HEAP_MEM
static struct globals *glbp;
#define GLB (*glbp)
#else
struct globals GLB;
#endif
static void FlushOutbuf()
{
write(GLB.out_fd, GLB.outbuf, GLB.outcnt);
GLB.outcnt = 0;
}
static inline void output8(unsigned char u8)
{
GLB.outbuf[GLB.outcnt++] = u8;
if (GLB.outcnt == OUTBUF_SIZE)
FlushOutbuf();
}
static inline void output16(uint32_t u16)
{
output8(u16);
output8(u16 >> 8);
}
static inline void output32(uint32_t u32)
{
output16(u32);
output16(u32 >> 16);
}
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 size_t ReadFile(void *buf, size_t size)
{
size_t ReadSize;
ReadSize = read(GLB.in_fd, buf, size);
GLB.incnt += ReadSize;
UpdateCrc32(buf, ReadSize);
return ReadSize;
}
static int LongestMatch(int curr_match)
{
int chain_length = MAX_CHAIN_LEN;
unsigned char *str = &GLB.window[GLB.strstart];
unsigned char *match;
int length;
int best_length = GLB.prev_length;
int limit = GLB.strstart > MAX_DIST ? GLB.strstart - MAX_DIST : 0;
for (chain_length = MAX_CHAIN_LEN; curr_match > limit && chain_length > 0;
curr_match = GLB.prev[curr_match & WMASK], chain_length--) {
match = &GLB.window[curr_match];
if (match[best_length] != str[best_length] || match[0] != str[0]
|| match[1] != str[1])
continue;
length = 2;
while (length < MAX_MATCH && match[length] == str[length])
length++;
if (length > best_length) {
GLB.match_start = curr_match;
best_length = length;
if (length >= MAX_MATCH)
break;
}
}
return best_length;
}
#define D_CODE(dist) ((dist) < 256 ? GLB.dist_code[dist] : \
GLB.dist_code[256 + ((dist) >> 7)])
static int CtTally(int dist, int lc)
{
GLB.l_buf[GLB.last_lit++] = lc;
if (dist == 0) {
GLB.dyn_ltree[lc].freq++;
} else {
dist--;
GLB.dyn_ltree[GLB.length_code[lc] + LITERALS + 1].freq++;
GLB.dyn_dtree[D_CODE(dist)].freq++;
GLB.d_buf[GLB.last_dist++] = dist;
GLB.flags |= GLB.flag_bit;
}
GLB.flag_bit <<= 1;
if ((GLB.last_lit & 0x7) == 0) {
GLB.flag_buf[GLB.last_flags++] = GLB.flags;
GLB.flags = 0;
GLB.flag_bit = 1;
}
return (GLB.last_lit == LIT_BUFSIZE - 1 ||
GLB.last_dist == DIST_BUFSIZE);
}
static void SendBits(uint32_t value, int length)
{
uint32_t new_buf;
new_buf = GLB.bi_buf | (value << GLB.bi_valid);
length += GLB.bi_valid;
if (length >= BUF_SIZE) {
value >>= (BUF_SIZE - GLB.bi_valid);
output32(new_buf);
new_buf = value;
length -= BUF_SIZE;
}
GLB.bi_buf = new_buf;
GLB.bi_valid = length;
}
#define SEND_CODE(c, tree) SendBits(tree[c].code, tree[c].len)
static void CompressBlock(CtDate_t *ltree, CtDate_t *dtree)
{
int dist;
int lc;
int lx = 0;
int dx = 0;
int fx = 0;
unsigned char flag = 0;
uint32_t code;
int extra;
if (GLB.last_lit != 0) {
do {
if ((lx & 0x7) == 0)
flag = GLB.flag_buf[fx++];
lc = GLB.l_buf[lx++];
if ((flag & 1) == 0) {
SEND_CODE(lc, ltree);
} else {
code = GLB.length_code[lc];
SEND_CODE(code + LITERALS + 1, ltree);
extra = extra_lbits[code];
if (extra != 0) {
lc -= GLB.base_length[code];
SendBits(lc, extra);
}
dist = GLB.d_buf[dx++];
code = D_CODE(dist);
SEND_CODE(code, dtree);
extra = extra_dbits[code];
if (extra != 0) {
dist -= GLB.base_dist[code];
SendBits(dist, extra);
}
}
flag >>= 1;
} while (lx < GLB.last_lit);
}
SEND_CODE(END_BLOCK, ltree);
}
static void SendTree(CtDate_t *tree, int max_code)
{
int prevlen = -1;
int currlen;
int nextlen = tree[0].len;
int count = 0;
int max_count = 7;
int min_count = 4;
if (nextlen == 0) {
max_count = 138;
min_count = 3;
}
for (int n = 0; n <= max_code; n++) {
currlen = nextlen;
nextlen = tree[n + 1].len;
if (++count < max_count && currlen == nextlen) {
continue;
} else if (count < min_count) {
do {
SEND_CODE(currlen, GLB.bl_tree);
} while (--count);
} else if (currlen != 0) {
if (currlen != prevlen) {
SEND_CODE(currlen, GLB.bl_tree);
count--;
}
SEND_CODE(REP_3_6, GLB.bl_tree);
SendBits(count - 3, 2);
} else if (count <= 10) {
SEND_CODE(REPZ_3_10, GLB.bl_tree);
SendBits(count - 3, 3);
} else {
SEND_CODE(REPZ_11_138, GLB.bl_tree);
SendBits(count - 11, 7);
}
count = 0;
prevlen = currlen;
if (nextlen == 0) {
max_count = 138;
min_count = 3;
} else if (currlen == nextlen) {
max_count = 6;
min_count = 3;
} else {
max_count = 7;
min_count = 4;
}
}
}
static void SendAllTrees(int lcodes, int dcodes, int blcodes)
{
SendBits(lcodes - 257, 5);
SendBits(dcodes - 1, 5);
SendBits(blcodes - 4, 4);
for (int rank = 0; rank < blcodes; rank++)
SendBits(GLB.bl_tree[bl_order[rank]].len, 3);
SendTree(GLB.dyn_ltree, lcodes - 1);
SendTree(GLB.dyn_dtree, dcodes - 1);
}
static void BiWindup()
{
uint32_t bits = GLB.bi_buf;
int cnt = GLB.bi_valid;
while (cnt > 0) {
output8(bits);
bits >>= 8;
cnt -= 8;
}
GLB.bi_buf = 0;
GLB.bi_valid = 0;
}
static void CopyBlock(unsigned char *buf, size_t len, int with_header)
{
BiWindup();
if (with_header) {
uint32_t v = ((uint16_t)len | ((~len) << 16));
output32(v);
}
for (int i = 0; i < len; i++)
output8(buf[i]);
}
static void ScanTree(CtDate_t *tree, int max_code)
{
int n;
int prevlen = -1;
int currlen;
int nextlen = tree[0].len;
int count = 0;
int max_count = 7;
int min_count = 4;
if (nextlen == 0) {
max_count = 138;
min_count = 3;
}
tree[max_code + 1].len = 0xffff;
for (n = 0; n <= max_code; n++) {
currlen = nextlen;
nextlen = tree[n + 1].len;
if (++count < max_count && currlen == nextlen)
continue;
if (count < min_count) {
GLB.bl_tree[currlen].freq += count;
} else if (currlen != 0) {
if (currlen != prevlen)
GLB.bl_tree[currlen].freq++;
GLB.bl_tree[REP_3_6].freq++;
} else if (count <= 10) {
GLB.bl_tree[REPZ_3_10].freq++;
} else {
GLB.bl_tree[REPZ_11_138].freq++;
}
count = 0;
prevlen = currlen;
max_count = 7;
min_count = 4;
if (nextlen == 0) {
max_count = 138;
min_count = 3;
} else if (currlen == nextlen) {
max_count = 6;
min_count = 3;
}
}
}
#define NODE_SMALLER(tree, n, m) (tree[n].freq < tree[m].freq || \
(tree[n].freq == tree[m].freq && \
GLB.depth[n] <= GLB.depth[m]))
static void HeapAdjust(CtDate_t *tree, int k)
{
int v = GLB.heap[k];
int j = k * 2;
while (j <= GLB.heap_len) {
if (j < GLB.heap_len &&
NODE_SMALLER(tree, GLB.heap[j + 1], GLB.heap[j]))
j++;
if (NODE_SMALLER(tree, v, GLB.heap[j]))
break;
GLB.heap[k] = GLB.heap[j];
k = j;
j *= 2;
}
GLB.heap[k] = v;
}
#define HEAP_POP(tree, top) do { \
top = GLB.heap[1]; \
GLB.heap[1] = GLB.heap[GLB.heap_len--]; \
HeapAdjust(tree, 1); \
} while (0)
static void GenBitlen(TreeDesc_t *desc)
{
CtDate_t *tree = desc->dyn_tree;
CtDate_t *stree = desc->static_tree;
const uint8_t *extra = desc->extra_bits;
int base = desc->extra_base;
int max_code = desc->max_code;
int max_length = desc->max_length;
int h;
int n, m;
int bits;
int xbits;
uint16_t f;
int overflow = 0;
for (bits = 0; bits <= MAX_BITS; bits++)
GLB.bl_count[bits] = 0;
tree[GLB.heap[GLB.heap_max]].len = 0;
for (h = GLB.heap_max + 1; h < HEAP_SIZE; h++) {
n = GLB.heap[h];
bits = tree[tree[n].father].len + 1;
if (bits > max_length) {
bits = max_length;
overflow++;
}
tree[n].len = bits;
if (n > max_code)
continue;
GLB.bl_count[bits]++;
xbits = 0;
if (n >= base)
xbits = extra[n - base];
f = tree[n].freq;
GLB.opt_len += f * (bits + xbits);
if (stree)
GLB.static_len += f * (stree[n].len + xbits);
}
if (overflow == 0)
return;
do {
bits = max_length - 1;
while (GLB.bl_count[bits] == 0)
bits--;
GLB.bl_count[bits]--;
GLB.bl_count[bits + 1] += 2;
GLB.bl_count[max_length]--;
overflow -= 2;
} while (overflow > 0);
for (bits = max_length; bits > 0; bits--) {
n = GLB.bl_count[bits];
while (n > 0) {
m = GLB.heap[--h];
if (m > max_code)
continue;
if (tree[m].len != bits) {
GLB.opt_len += (int)(bits - tree[m].len) *
tree[m].freq;
tree[m].len = bits;
}
n--;
}
}
}
static unsigned BiReverse (unsigned code, int len)
{
unsigned ret = 0;
while (1) {
ret |= code & 1;
if (--len == 0)
return ret;
code >>= 1;
ret <<= 1;
}
}
static void GenCodes(CtDate_t * tree, int max_code)
{
uint16_t next_code[MAX_BITS + 1];
uint16_t code = 0;
int bits;
int n;
for (bits = 1; bits <= MAX_BITS; bits++)
next_code[bits] = code = (code + GLB.bl_count[bits - 1]) << 1;
for (n = 0; n <= max_code; n++) {
int len = tree[n].len;
if (len == 0)
continue;
tree[n].code = BiReverse (next_code[len]++, len);
}
}
static void BuildTree(TreeDesc_t *desc)
{
CtDate_t *tree = desc->dyn_tree;
CtDate_t *stree = desc->static_tree;
int elems = desc->elems;
int m, n;
int max_code = -1;
int node = elems;
GLB.heap_len = 0;
GLB.heap_max = HEAP_SIZE;
for (n = 0; n < elems; n++) {
if (tree[n].freq != 0) {
GLB.heap[++GLB.heap_len] = max_code = n;
GLB.depth[n] = 0;
} else {
tree[n].len = 0;
}
}
while (GLB.heap_len < 2) {
int new = GLB.heap[++GLB.heap_len] = (max_code < 2 ?
++max_code : 0);
tree[new].freq = 1;
GLB.depth[new] = 0;
GLB.opt_len--;
if (stree)
GLB.static_len -= stree[new].len;
}
desc->max_code = max_code;
for (n = GLB.heap_len / 2; n >= 1; n--)
HeapAdjust(tree, n);
do {
HEAP_POP(tree, n);
m = GLB.heap[1];
GLB.heap[--GLB.heap_max] = n;
GLB.heap[--GLB.heap_max] = m;
tree[node].freq = tree[n].freq + tree[m].freq;
GLB.depth[node] = MAX(GLB.depth[n], GLB.depth[m]) + 1;
tree[n].father = tree[m].father = node;
GLB.heap[1] = node++;
HeapAdjust(tree, 1);
} while (GLB.heap_len >= 2);
GLB.heap[--GLB.heap_max] = GLB.heap[1];
GenBitlen(desc);
GenCodes(tree, max_code);
}
static int BuildBlTree()
{
int max_blindex;
ScanTree(GLB.dyn_ltree, GLB.l_desc.max_code);
ScanTree(GLB.dyn_dtree, GLB.d_desc.max_code);
BuildTree(&GLB.bl_desc);
for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--)
if (GLB.bl_tree[bl_order[max_blindex]].len != 0)
break;
GLB.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
return max_blindex;
}
static void InitBlock(void)
{
int n;
for (n = 0; n < L_CODES; n++)
GLB.dyn_ltree[n].freq = 0;
for (n = 0; n < D_CODES; n++)
GLB.dyn_dtree[n].freq = 0;
for (n = 0; n < BL_CODES; n++)
GLB.bl_tree[n].freq = 0;
GLB.dyn_ltree[END_BLOCK].freq = 1;
GLB.opt_len = GLB.static_len = 0;
GLB.last_lit = GLB.last_dist = GLB.last_flags = 0;
GLB.flags = 0;
GLB.flag_bit = 1;
}
static void FlushBlock(unsigned char *buf, uint32_t stored_len, int eof)
{
uint32_t opt_lenb, static_lenb;
int max_blindex;
GLB.flag_buf[GLB.last_flags] = GLB.flags;
BuildTree(&GLB.l_desc);
BuildTree(&GLB.d_desc);
max_blindex = BuildBlTree();
opt_lenb = (GLB.opt_len + 3 + 7) >> 3;
static_lenb = (GLB.static_len + 3 + 7) >> 3;
if (static_lenb < opt_lenb)
opt_lenb = static_lenb;
if (stored_len + 4 <= opt_lenb && buf != NULL) {
SendBits((STORED_BLOCK << 1) + eof, 3);
CopyBlock(buf, stored_len, 1);
} else if (static_lenb == opt_lenb) {
SendBits((STATIC_TREES << 1) + eof, 3);
CompressBlock(GLB.static_ltree, GLB.static_dtree);
} else {
SendBits((DYN_TREES << 1) + eof, 3);
SendAllTrees(GLB.l_desc.max_code + 1,
GLB.d_desc.max_code + 1, max_blindex + 1);
CompressBlock(GLB.dyn_ltree, GLB.dyn_dtree);
}
InitBlock();
if (eof)
BiWindup();
}
#define FLUSH_BLOCK(eof) FlushBlock( \
GLB.block_start >= 0 \
? &GLB.window[GLB.block_start] \
: NULL, \
(uint32_t)GLB.strstart - GLB.block_start, \
(eof) \
)
static void FillWindow()
{
uint32_t n, m;
uint32_t more = 2 * WSIZE - GLB.lookahead - GLB.strstart;
if (more == (uint32_t)-1) {
more--;
} else if (GLB.strstart >= WSIZE + MAX_DIST) {
memcpy(GLB.window, &GLB.window[WSIZE], WSIZE);
GLB.match_start -= WSIZE;
GLB.strstart -= WSIZE;
GLB.block_start -= WSIZE;
for (n = 0; n < HASH_SIZE; n++) {
m = HEAD[n];
HEAD[n] = m >= WSIZE ? m - WSIZE : 0;
}
for (n = 0; n < WSIZE; n++) {
m = GLB.prev[n];
GLB.prev[n] = m >= WSIZE ? m - WSIZE : 0;
}
more += WSIZE;
}
if (!GLB.eofile) {
n = ReadFile(GLB.window + GLB.strstart +
GLB.lookahead, more);
if (n == 0 || n == (unsigned) -1)
GLB.eofile = 1;
else
GLB.lookahead += n;
}
}
static void FillWindowIfNeeded(void)
{
while (GLB.lookahead < MIN_LOOKAHEAD && !GLB.eofile)
FillWindow();
}
#define UPDATE_HASH(h, c) (h = (((h) << HASH_SHIFT) ^ (c)) & HASH_MASK)
#define INSERT_STRING(s, match_head) do { \
UPDATE_HASH(GLB.ins_h, GLB.window[(s) + MIN_MATCH - 1]); \
GLB.prev[(s) & WMASK] = HEAD[GLB.ins_h]; \
match_head = HEAD[GLB.ins_h]; \
HEAD[GLB.ins_h] = (s); \
} while (0)
static void deflate()
{
int hash_head;
int prev_match;
int flush;
int match_available = 0;
int match_length = MIN_MATCH - 1;
while (GLB.lookahead) {
INSERT_STRING(GLB.strstart, hash_head);
GLB.prev_length = match_length;
prev_match = GLB.match_start;
match_length = MIN_MATCH - 1;
if (hash_head && GLB.prev_length < MAX_LAZY_MATCH &&
GLB.strstart - hash_head <= MAX_DIST) {
match_length = LongestMatch(hash_head);
if (match_length > GLB.lookahead)
match_length = GLB.lookahead;
if (match_length == MIN_MATCH &&
GLB.strstart - GLB.match_start > 4096)
match_length--;
}
if (GLB.prev_length >= MIN_MATCH &&
match_length <= GLB.prev_length) {
flush = CtTally(GLB.strstart - 1 - prev_match,
GLB.prev_length - MIN_MATCH);
GLB.lookahead -= GLB.prev_length - 1;
for (GLB.prev_length -= 2; GLB.prev_length > 0;
GLB.prev_length--) {
GLB.strstart++;
INSERT_STRING(GLB.strstart, hash_head);
}
match_available = 0;
match_length = MIN_MATCH - 1;
GLB.strstart++;
if (flush) {
FLUSH_BLOCK(0);
GLB.block_start = GLB.strstart;
}
} else if (match_available) {
if (CtTally(0, GLB.window[GLB.strstart - 1])) {
FLUSH_BLOCK(0);
GLB.block_start = GLB.strstart;
}
GLB.strstart++;
GLB.lookahead--;
} else {
match_available = 1;
GLB.strstart++;
GLB.lookahead--;
}
FillWindowIfNeeded();
}
if (match_available)
CtTally(0, GLB.window[GLB.strstart - 1]);
FLUSH_BLOCK(1);
}
static void CtInit()
{
int n;
int length;
int code;
int dist;
length = 0;
for (code = 0; code < LENGTH_CODES - 1; code++) {
GLB.base_length[code] = length;
for (n = 0; n < (1 << extra_lbits[code]); n++) {
GLB.length_code[length++] = code;
}
}
GLB.length_code[length - 1] = code;
dist = 0;
for (code = 0; code < 16; code++) {
GLB.base_dist[code] = dist;
for (n = 0; n < (1 << extra_dbits[code]); n++) {
GLB.dist_code[dist++] = code;
}
}
dist >>= 7;
for (; code < D_CODES; code++) {
GLB.base_dist[code] = dist << 7;
for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {
GLB.dist_code[256 + dist++] = code;
}
}
n = 0;
while (n <= 143)
GLB.static_ltree[n++].len = 8;
while (n <= 255)
GLB.static_ltree[n++].len = 9;
while (n <= 279)
GLB.static_ltree[n++].len = 7;
while (n <= 287)
GLB.static_ltree[n++].len = 8;
GLB.bl_count[7] = 279 - 255;
GLB.bl_count[8] = (143 + 1) + (287 - 279);
GLB.bl_count[9] = 255 - 143;
GenCodes((CtDate_t *)GLB.static_ltree, L_CODES + 1);
for (n = 0; n < D_CODES; n++) {
GLB.static_dtree[n].len = 5;
GLB.static_dtree[n].code = BiReverse (n, 5);
}
InitBlock();
}
static void LmInit()
{
unsigned j;
memset(HEAD, 0, (1 << HASH_BITS) * sizeof(*HEAD));
GLB.lookahead = ReadFile(GLB.window,
sizeof(int) <= 2 ? (unsigned) WSIZE : 2 * WSIZE);
if (GLB.lookahead == 0 || GLB.lookahead == (unsigned) -1) {
GLB.eofile = 1;
GLB.lookahead = 0;
return;
}
FillWindowIfNeeded();
for (j = 0; j < MIN_MATCH - 1; j++)
UPDATE_HASH(GLB.ins_h, GLB.window[j]);
}
int GzipCompress(char *file_name)
{
int ret = 0;
char *gz_file_name;
struct stat statbuf;
#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));
if ((GLB.in_fd = open(file_name, O_RDONLY)) < 0) {
ret = -1;
goto free_glbp;
}
fstat(GLB.in_fd, &statbuf);
if (!S_ISREG(statbuf.st_mode)) {
ret = -1;
goto free_glbp;
}
if ((gz_file_name = malloc(strlen(file_name) + 4)) == NULL) {
ret = -1;
goto close_in_fd;
}
strcpy(gz_file_name, file_name);
strcat(gz_file_name, ".gz");
if ((GLB.out_fd =
open(gz_file_name, O_WRONLY | O_CREAT | O_TRUNC)) < 0) {
ret = -1;
goto free_gz_file_name;
}
GLB.crc32 = ~0;
GLB.l_desc.dyn_tree = GLB.dyn_ltree;
GLB.l_desc.static_tree = GLB.static_ltree;
GLB.l_desc.extra_bits = extra_lbits;
GLB.l_desc.extra_base = LITERALS + 1;
GLB.l_desc.elems = L_CODES;
GLB.l_desc.max_length = MAX_BITS;
GLB.d_desc.dyn_tree = GLB.dyn_dtree;
GLB.d_desc.static_tree = GLB.static_dtree;
GLB.d_desc.extra_bits = extra_dbits;
GLB.d_desc.elems = D_CODES;
GLB.d_desc.max_length = MAX_BITS;
GLB.bl_desc.dyn_tree = GLB.bl_tree;
GLB.bl_desc.extra_bits = extra_blbits,
GLB.bl_desc.elems = BL_CODES;
GLB.bl_desc.max_length = MAX_BL_BITS;
CtInit();
LmInit();
output32(0x00088b1f);
output32(0x0);
output16(0x2 | 0x300);
FlushOutbuf();
deflate();
output32(~GLB.crc32);
output32(GLB.incnt);
FlushOutbuf();
if (GLB.incnt != statbuf.st_size)
ret = -1;
close(GLB.out_fd);
free_gz_file_name:
free(gz_file_name);
close_in_fd:
close(GLB.in_fd);
free_glbp:
#ifdef USE_HEAP_MEM
free(glbp);
#endif
return ret;
}
extern int GzipDecompress(char *file_name);
static void GzipPrintUsage()
{
KPrintf("Usage: gzip [OPTIONS]... [FILES]...\n");
KPrintf("Supported option flags:\n");
KPrintf(" d decompress gzip file(s)\n");
}
int gzip(int argc, char **argv)
{
int (*gzip_func)(char *file_name) = GzipCompress;
if (argc < 2) {
GzipPrintUsage();
return 0;
}
if (argv[1][0] == '-') {
if (strlen(argv[1]) != 2 || argv[1][1] != 'd') {
KPrintf("Bad options\n");
GzipPrintUsage();
return 0;
}
gzip_func = GzipDecompress;
argv++;
argc--;
}
for (int i = 1; i < argc; i++)
if (gzip_func(argv[i]) < 0) {
KPrintf("Operation failed\n");
break;
}
return 0;
}
#endif