summaryrefslogtreecommitdiff
path: root/neozip/deflate_p.h
blob: f60970bab37666b82f00fb182e39169a1b93ba1d (plain)
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/* deflate_p.h -- Private inline functions and macros shared with more than
 *                one deflate method
 *
 * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 *
 */

#ifndef DEFLATE_P_H
#define DEFLATE_P_H

#include "functable.h"
#include "fallback_builtins.h"
#include "zmemory.h"

/* Forward declare common non-inlined functions declared in deflate.c */

#ifdef ZLIB_DEBUG
/* ===========================================================================
 * Check that the match at match_start is indeed a match.
 */
static inline void check_match(deflate_state *s, uint32_t start, uint32_t match, int length) {
    /* check that the match length is valid*/
    if (length < STD_MIN_MATCH || length > STD_MAX_MATCH) {
        fprintf(stderr, " start %u, match %u, length %d\n", start, match, length);
        z_error("invalid match length");
    }
    /* check that the match isn't at the same position as the start string */
    if (match == start) {
        fprintf(stderr, " start %u, match %u, length %d\n", start, match, length);
        z_error("invalid match position");
    }
    /* check that the match is indeed a match */
    if (memcmp(s->window + match, s->window + start, length) != 0) {
        int32_t i = 0;
        fprintf(stderr, " start %u, match %u, length %d\n", start, match, length);
        do {
            fprintf(stderr, "  %03d: match [%02x] start [%02x]\n", i++,
                s->window[match++], s->window[start++]);
        } while (--length != 0);
        z_error("invalid match");
    }
    if (z_verbose > 1) {
        fprintf(stderr, "\\[%u,%d]", start-match, length);
        do {
            putc(s->window[start++], stderr);
        } while (--length != 0);
    }
}
#else
#define check_match(s, start, match, length)
#endif

Z_INTERNAL void PREFIX(flush_pending)(PREFIX3(stream) *strm);

/* ===========================================================================
 * Save the match info and tally the frequency counts. Return true if
 * the current block must be flushed.
 */

extern const unsigned char Z_INTERNAL zng_length_code[];
extern const unsigned char Z_INTERNAL zng_dist_code[];

static inline int zng_tr_tally_lit(deflate_state *s, unsigned char c) {
    /* c is the unmatched char */
    unsigned int sym_next = s->sym_next;
#ifdef LIT_MEM
    s->d_buf[sym_next] = 0;
    s->l_buf[sym_next] = c;
    s->sym_next = sym_next + 1;
#else
#  if OPTIMAL_CMP >= 32
    zng_memwrite_4(&s->sym_buf[sym_next], Z_U32_TO_LE((uint32_t)c << 16));
#  else
    s->sym_buf[sym_next] = 0;
    s->sym_buf[sym_next+1] = 0;
    s->sym_buf[sym_next+2] = c;
#  endif
    s->sym_next = sym_next + 3;
#endif
    s->dyn_ltree[c].Freq++;
    Tracevv((stderr, "%c", c));
    Assert(c <= (STD_MAX_MATCH-STD_MIN_MATCH), "zng_tr_tally: bad literal");
    return (s->sym_next == s->sym_end);
}

static inline int zng_tr_tally_dist(deflate_state* s, uint32_t dist, uint32_t len) {
    /* dist: distance of matched string */
    /* len: match length-STD_MIN_MATCH */
    unsigned int sym_next = s->sym_next;
#ifdef LIT_MEM
    Assert(dist <= UINT16_MAX, "dist should fit in uint16_t");
    Assert(len <= UINT8_MAX, "len should fit in uint8_t");
    s->d_buf[sym_next] = (uint16_t)dist;
    s->l_buf[sym_next] = (uint8_t)len;
    s->sym_next = sym_next + 1;
#else
#  if OPTIMAL_CMP >= 32
    zng_memwrite_4(&s->sym_buf[sym_next], Z_U32_TO_LE(dist | ((uint32_t)len << 16)));
#  else
    s->sym_buf[sym_next] = (uint8_t)(dist);
    s->sym_buf[sym_next+1] = (uint8_t)(dist >> 8);
    s->sym_buf[sym_next+2] = (uint8_t)len;
#  endif
    s->sym_next = sym_next + 3;
#endif
    s->matches++;
    dist--;
    Assert(dist < MAX_DIST(s) && (uint16_t)d_code(dist) < (uint16_t)D_CODES,
        "zng_tr_tally: bad match");

    s->dyn_ltree[zng_length_code[len] + LITERALS + 1].Freq++;
    s->dyn_dtree[d_code(dist)].Freq++;
    return (s->sym_next == s->sym_end);
}

/* =========================================================================
 * Flush as much pending output as possible. All deflate() output, except for some
 * deflate_stored() output, goes through this function so some applications may wish to
 * modify it to avoid allocating a large strm->next_out buffer and copying into it.
 * See also read_buf().
 */
Z_FORCEINLINE static void flush_pending_inline(PREFIX3(stream) *strm) {
    uint32_t len;
    deflate_state *s = strm->state;

    zng_tr_flush_bits(s);
    len = MIN(s->pending, strm->avail_out);
    if (len == 0)
        return;

    Tracev((stderr, "[FLUSH]"));
    memcpy(strm->next_out, s->pending_out, len);
    strm->next_out  += len;
    s->pending_out  += len;
    strm->total_out += len;
    strm->avail_out -= len;
    s->pending      -= len;
    if (s->pending == 0)
        s->pending_out = s->pending_buf;
}

/* ===========================================================================
 * Reverse the first len bits of a code using bit manipulation
 */
Z_FORCEINLINE static uint16_t bi_reverse(uint16_t code, int len) {
    /* code: the value to invert */
    /* len: its bit length */
    Assert(len >= 1 && len <= 15, "code length must be 1-15");
    return zng_bitreverse16(code) >> (16 - len);
}

/* ===========================================================================
 * Read a new buffer from the current input stream, update the adler32 and total number of
 * bytes read.  All deflate() input goes through this function so some applications may wish
 * to modify it to avoid allocating a large strm->next_in buffer and copying from it.
 * See also flush_pending_inline().
 */
Z_FORCEINLINE static unsigned read_buf(PREFIX3(stream) *strm, unsigned char *buf, unsigned size) {
    deflate_state *s = strm->state;
    uint32_t len = MIN(strm->avail_in, size);

    if (len == 0)
        return 0;

    if (!DEFLATE_NEED_CHECKSUM(strm)) {
        memcpy(buf, strm->next_in, len);
#ifdef GZIP
    } else if (s->wrap == 2) {
        strm->adler = FUNCTABLE_CALL(crc32_copy)(strm->adler, buf, strm->next_in, len);
#endif
    } else if (s->wrap == 1) {
        strm->adler = FUNCTABLE_CALL(adler32_copy)(strm->adler, buf, strm->next_in, len);
    } else {
        memcpy(buf, strm->next_in, len);
    }

    strm->avail_in -= len;
    strm->next_in  += len;
    strm->total_in += len;
    return len;
}

/* ===========================================================================
 * Flush the current block, with given end-of-file flag.
 * IN assertion: strstart is set to the end of the current match.
 */
#define FLUSH_BLOCK_ONLY(s, last) { \
    zng_tr_flush_block(s, (s->block_start >= 0 ? \
                   &s->window[(unsigned)s->block_start] : \
                   NULL), \
                   (uint32_t)((int)s->strstart - s->block_start), \
                   (last)); \
    s->block_start = (int)s->strstart; \
    PREFIX(flush_pending)(s->strm); \
}

/* Same but force premature exit if necessary. */
#define FLUSH_BLOCK(s, last) { \
    FLUSH_BLOCK_ONLY(s, last); \
    if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \
}

/* Maximum stored block length in deflate format (not including header). */
#define MAX_STORED 65535

/* Compression function. Returns the block state after the call. */
typedef block_state (*compress_func) (deflate_state *s, int flush);
/* Match function. Returns the longest match. */
typedef uint32_t    (*match_func)    (deflate_state *const s, uint32_t cur_match);

#endif