spacedrive/libmineziper/src/libmineziper_zip.c
2024-02-22 11:53:40 +01:00

167 lines
No EOL
3.4 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libmineziper_huffman_tree.h"
#include "libmineziper_zip.h"
zip init_zip(char* data, int size)
{
zip z = {.start = data, .size = size};
get_eocd(&z);
get_cdh(&z);
return z;
}
void get_eocd(zip* z)
{
if (z->size < START_EOCD_SEARCH)
return;
char* se = &z->start[z->size - START_EOCD_SEARCH];
while (se > z->start)
{
if (strcmp(se, EOCD_SIG) == 0)
{
z->eocd = (EOCD*) se;
z->entries = z->eocd->number_of_entries;
z->lfh_off = malloc(z->entries * sizeof(int));
z->cdh_filename_length = malloc(z->entries * sizeof(int));
if (!z->lfh_off || !z->cdh_filename_length)
{
printf(
"[ERROR] Failed to allocate CDH/LFH buffer for %d entries\n",
z->entries);
exit(1);
}
break;
}
se--;
}
}
void get_cdh(zip* z)
{
if (z->eocd == 0 || z->eocd->off_cdh == 0)
{
fprintf(stderr, "[ERROR]: No EOCD found when fetching CDH.\n");
exit(-1);
}
z->cd = z->start + z->eocd->off_cdh;
CDH* cdh = (CDH*) z->cd;
for (int i = 0; i < z->eocd->number_of_entries; i++)
{
z->lfh_off[i] = cdh->off_lfh;
z->cdh_filename_length[i] = cdh->filename_length;
cdh = (CDH*) (((char*) cdh) + sizeof(CDH) + cdh->filename_length +
cdh->extraf_length + cdh->file_comment_length);
}
}
char* decode_type1_block_vuln(bitstream* bs, char* decoded_data)
{
tree tr = build_default_tree();
tree tr_dist = build_default_dist_tree();
int i = 0, token;
while ((token = next_token(bs, tr)) != END_OF_BLOCK)
{
if (token < END_OF_BLOCK)
{
decoded_data[i++] = token;
}
else
{
int length = decode_length_token(bs, token);
if ((token = next_token(bs, tr_dist)) == END_OF_BLOCK)
{
printf("[ERROR] Got EndOfBlock when decoding distance token\n");
exit(1);
}
int distance = decode_distance_token(bs, token);
for (int j = 0; j < length; j++)
{
decoded_data[i] = decoded_data[i - distance];
i++;
}
}
}
}
char* decode_type1_block_v2(
bitstream* bs,
int uncompressed_size,
char* decoded_data)
{
tree tr = build_default_tree();
tree tr_dist = build_default_dist_tree();
int i = 0, token;
while (i < uncompressed_size && (token = next_token(bs, tr)) != END_OF_BLOCK)
{
if (token < END_OF_BLOCK)
{
decoded_data[i++] = token;
}
else
{
int length = decode_length_token(bs, token);
if ((token = next_token(bs, tr_dist)) == END_OF_BLOCK)
{
printf("[ERROR] Got EndOfBlock when decoding distance token\n");
exit(1);
}
int distance = decode_distance_token(bs, token);
for (int j = 0; j < length; j++)
{
decoded_data[i] = decoded_data[i - distance];
i++;
}
}
}
}
int get_number_bit_length_code(DHCH* dhch)
{
return (dhch->bit_length_code & 0b1111) + 4;
}
int get_number_dist_code(DHCH* dhch)
{
return (dhch->dist_codes & 0b11111) + 1;
}
int get_number_litteral_code(DHCH* dhch)
{
return (dhch->literal_codes & 0b11111) + 257;
}
short decode_length_token(bitstream* bs, int token)
{
token -= END_OF_BLOCK + 1;
int extra = get_bits(bs, extra_bits_length_codes[token]);
return length_codes[token] + extra;
}
int decode_distance_token(bitstream* bs, int token)
{
int extra = get_bits(bs, extra_bits_distance_codes[token]);
return distance_codes[token] + extra;
}