forked from wkoszek/mini_gzip
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmini_gzip.c
138 lines (122 loc) · 2.85 KB
/
mini_gzip.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
* BSD 2-clause license
* Copyright (c) 2013 Wojciech A. Koszek <wkoszek@FreeBSD.org>
*
* Based on:
*
* https://github.com/strake/gzip.git
*
* I had to rewrite it, since strake's version was powered by UNIX FILE* API,
* while the key objective was to perform memory-to-memory operations
*/
#include <assert.h>
#include <stdint.h>
#include <string.h>
#ifdef MINI_GZ_DEBUG
#include <stdio.h>
#endif
#include "miniz.h"
#include "mini_gzip.h"
int
mini_gz_start(struct mini_gzip *gz_ptr, void *mem, size_t mem_len)
{
uint8_t *hptr, *hauxptr, *mem8_ptr;
uint16_t fextra_len;
assert(gz_ptr != NULL);
mem8_ptr = (uint8_t *)mem;
hptr = mem8_ptr + 0; // .gz header
hauxptr = mem8_ptr + 10; // auxillary header
gz_ptr->hdr_ptr = hptr;
gz_ptr->data_ptr = 0;
gz_ptr->data_len = 0;
gz_ptr->total_len = mem_len;
gz_ptr->chunk_size = 1024;
if (hptr[0] != 0x1F || hptr[1] != 0x8B) {
GZDBG("hptr[0] = %02x hptr[1] = %02x\n", hptr[0], hptr[1]);
return (-1);
}
if (hptr[2] != 8) {
return (-2);
}
if (hptr[3] & 0x4) {
fextra_len = hauxptr[1] << 8 | hauxptr[0];
gz_ptr->fextra_len = fextra_len;
hauxptr += 2;
gz_ptr->fextra_ptr = hauxptr;
}
if (hptr[3] & 0x8) {
gz_ptr->fname_ptr = hauxptr;
while (*hauxptr != '\0') {
hauxptr++;
}
hauxptr++;
}
if (hptr[3] & 0x10) {
gz_ptr->fcomment_ptr = hauxptr;
while (*hauxptr != '\0') {
hauxptr++;
}
hauxptr++;
}
if (hptr[3] & 0x2) /* FCRC */ {
gz_ptr->fcrc = (*(uint16_t *)hauxptr);
hauxptr += 2;
}
gz_ptr->data_ptr = hauxptr;
gz_ptr->data_len = mem_len - (hauxptr - hptr);
gz_ptr->magic = MINI_GZIP_MAGIC;
return (0);
}
void
mini_gz_chunksize_set(struct mini_gzip *gz_ptr, int chunk_size)
{
assert(gz_ptr != 0);
assert(gz_ptr->magic == MINI_GZIP_MAGIC);
gz_ptr->chunk_size = chunk_size;
}
void
mini_gz_init(struct mini_gzip *gz_ptr)
{
memset(gz_ptr, 0xffffffff, sizeof(*gz_ptr));
gz_ptr->magic = MINI_GZIP_MAGIC;
mini_gz_chunksize_set(gz_ptr, 1024);
}
int
mini_gz_unpack(struct mini_gzip *gz_ptr, void *mem_out, size_t mem_out_len)
{
z_stream s;
int ret, in_bytes_avail, bytes_to_read;
assert(gz_ptr != 0);
assert(gz_ptr->data_len > 0);
assert(gz_ptr->magic == MINI_GZIP_MAGIC);
memset (&s, 0, sizeof (z_stream));
inflateInit2(&s, -MZ_DEFAULT_WINDOW_BITS);
in_bytes_avail = gz_ptr->data_len;
s.avail_out = mem_out_len;
s.next_in = gz_ptr->data_ptr;
s.next_out = mem_out;
for (;;) {
bytes_to_read = MINI_GZ_MIN(gz_ptr->chunk_size, in_bytes_avail);
s.avail_in += bytes_to_read;
ret = mz_inflate(&s, MZ_SYNC_FLUSH);
in_bytes_avail -= bytes_to_read;
if (s.avail_out == 0 && in_bytes_avail != 0) {
return (-3);
}
assert(ret != MZ_BUF_ERROR);
if (ret == MZ_PARAM_ERROR) {
return (-1);
}
if (ret == MZ_DATA_ERROR) {
return (-2);
}
if (ret == MZ_STREAM_END) {
break;
}
}
ret = inflateEnd(&s);
if (ret != Z_OK) {
return (-4);
}
return (s.total_out);
}