Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/slzwe.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* LZW encoding filter */
18
#include "stdio_.h" /* includes std.h */
19
#include "gdebug.h"
20
#include "strimpl.h"
21
#include "slzwx.h"
22
23
/********************************************************/
24
/* LZW routines are based on:       */
25
/* Dr. Dobbs Journal --- Oct. 1989.       */
26
/* Article on LZW Data Compression by Mark R. Nelson  */
27
/********************************************************/
28
29
/* Define the special codes */
30
84.4k
#define code_reset 256
31
1.12G
#define code_eod 257
32
42.2k
#define code_0 258      /* first assignable code */
33
34
/* Import the stream closing procedure */
35
extern stream_proc_release(s_LZW_release);
36
37
typedef struct lzw_encode_s {
38
        byte datum;     /* last byte of this code */
39
        ushort prefix;      /* code for prefix of this code */
40
} lzw_encode;
41
42
7.02G
#define encode_max 4095    /* max # of codes, must be */
43
                                /* > code_0 and <= 4095 */
44
3.50G
#define hash_size (encode_max + encode_max / 4)
45
46
struct lzw_encode_table_s {
47
        lzw_encode encode[encode_max];
48
        ushort hashed[hash_size];
49
};
50
gs_private_st_simple(st_lzwe_table, lzw_encode_table, "lzw_encode_table");
51
52
/* Hashing function */
53
#define encode_hash(code, chr)\
54
1.64G
  ((uint)((code) * 59 + (chr) * ((hash_size / 256) | 1)) % hash_size)
55
56
/* Internal routine to put a code into the output buffer. */
57
/* Let S = ss->code_size, M = ss->next_code, N = 1 << M. */
58
/* Relevant invariants: 9 <= S <= 12; N / 2 <= M < N; 0 <= code < N; */
59
/* 1 <= ss->bits_left <= 8; only the rightmost (8 - ss->bits_left) */
60
/* bits of ss->bits contain valid data. */
61
static byte *
62
lzw_put_code(register stream_LZW_state *ss, byte *q, uint code)
63
100M
{ uint size = ss->code_size;
64
100M
        byte cb = (ss->bits << ss->bits_left) +
65
100M
                (code >> (size - ss->bits_left));
66
100M
        if_debug2m('W', ss->memory, "[w]writing 0x%x,%d\n", code, ss->code_size);
67
100M
        *++q = cb;
68
100M
        if ( (ss->bits_left += 8 - size) <= 0 )
69
40.5M
        { *++q = code >> -ss->bits_left;
70
40.5M
                ss->bits_left += 8;
71
40.5M
        }
72
100M
        ss->bits = code;
73
100M
        return q;
74
100M
}
75
76
/* Internal routine to reset the encoding table */
77
static void
78
lzw_reset_encode(stream_LZW_state *ss)
79
42.2k
{ register int c;
80
42.2k
        lzw_encode_table *table = ss->table.encode;
81
42.2k
        ss->next_code = code_0;
82
42.2k
        ss->code_size = 9;
83
42.2k
        ss->prev_code = code_eod;
84
216M
        for ( c = 0; c < hash_size; c++ )
85
216M
                table->hashed[c] = code_eod;
86
10.8M
        for ( c = 0; c < 256; c++ )
87
10.8M
        { lzw_encode *ec = &table->encode[c];
88
10.8M
                register ushort *tc = &table->hashed[encode_hash(code_eod, c)];
89
10.8M
                while ( *tc != code_eod )
90
0
                  if ( ++tc == &table->hashed[hash_size] )
91
0
                    tc = &table->hashed[0];
92
10.8M
                *tc = c;
93
10.8M
                ec->datum = c, ec->prefix = code_eod;
94
10.8M
        }
95
42.2k
        table->encode[code_eod].prefix = code_reset; /* guarantee no match */
96
42.2k
}
97
98
347M
#define ss ((stream_LZW_state *)st)
99
100
/* Initialize LZWEncode filter */
101
static int
102
s_LZWE_init(stream_state *st)
103
18.3k
{ ss->bits_left = 8;
104
18.3k
        ss->bits = 0; /* for Purify, the value unimportant due to ss->bits_left == 8 */
105
18.3k
        ss->table.encode = gs_alloc_struct(st->memory,
106
18.3k
                        lzw_encode_table, &st_lzwe_table, "LZWEncode init");
107
18.3k
        if ( ss->table.encode == 0 )
108
0
                return ERRC;   /****** WRONG ******/
109
18.3k
        ss->first = true;
110
18.3k
        lzw_reset_encode(ss);
111
18.3k
        return 0;
112
18.3k
}
113
114
/* Process a buffer */
115
static int
116
s_LZWE_process(stream_state *st, stream_cursor_read *pr,
117
  stream_cursor_write *pw, bool last)
118
7.48M
{ register const byte *p = pr->ptr;
119
7.48M
        const byte *rlimit = pr->limit;
120
7.48M
        register byte *q = pw->ptr;
121
7.48M
        byte *wlimit = pw->limit;
122
7.48M
        int code = ss->prev_code;
123
7.48M
        lzw_encode_table *table = ss->table.encode;
124
7.48M
        ushort *table_end = &table->hashed[hash_size];
125
7.48M
        int status = 0;
126
7.48M
        int limit_code;
127
7.48M
#define set_limit_code()\
128
7.58M
  limit_code = (1 << ss->code_size) - ss->EarlyChange;\
129
7.58M
  if ( limit_code > encode_max ) limit_code = encode_max
130
7.48M
        set_limit_code();
131
7.48M
        if ( ss->first )
132
18.3k
        { /* Emit the initial reset code. */
133
18.3k
                if ( wlimit - q < 2 )
134
0
                        return 1;
135
18.3k
                q = lzw_put_code(ss, q, code_reset);
136
18.3k
                ss->first = false;
137
18.3k
        }
138
1.63G
        while ( p < rlimit )
139
1.63G
        { byte c = p[1];
140
1.63G
                ushort *tp;
141
1.63G
                for ( tp = &table->hashed[encode_hash(code, c)]; ; )
142
2.31G
                { lzw_encode *ep = &table->encode[*tp];
143
2.31G
                        if ( ep->prefix == code && ep->datum == c )
144
1.53G
                        { code = *tp;
145
1.53G
                                p++;
146
1.53G
                                break;
147
1.53G
                        }
148
783M
                        else if ( *tp != code_eod )
149
681M
                        { if ( ++tp == table_end )
150
288k
                                  tp = &table->hashed[0]; /* wrap around */
151
681M
                        }
152
101M
                        else
153
101M
                        { /* end of recognized sequence */
154
101M
                                if ( wlimit - q <= 4 )
155
1.10M
                                { status = 1;
156
1.10M
                                        goto out;
157
1.10M
                                }
158
100M
                                q = lzw_put_code(ss, q, code);
159
100M
                                if ( ss->next_code == limit_code )
160
106k
                                { /* Reached power of 2 or limit. */
161
                                        /* Determine which. */
162
106k
                                        if ( ss->next_code == encode_max )
163
23.8k
                                        { q = lzw_put_code(ss, q, code_reset);
164
23.8k
                                                lzw_reset_encode(ss);
165
23.8k
                                                set_limit_code();
166
23.8k
                                                goto cx;
167
23.8k
                                        }
168
82.2k
                                        ss->code_size++;
169
82.2k
                                        set_limit_code();
170
82.2k
                                }
171
100M
                                if_debug3m('W', ss->memory, "[W]encoding 0x%x=0x%x+%c\n",
172
100M
                                          ss->next_code, code, c);
173
100M
                                *tp = ss->next_code++;
174
100M
                                ep = &table->encode[*tp];
175
100M
                                ep->datum = c;
176
100M
                                ep->prefix = code;
177
100M
cx:       code = code_eod;
178
100M
                                break;
179
100M
                        }
180
2.31G
                }
181
1.63G
        }
182
6.37M
        if ( last && status == 0 )
183
18.3k
        { if ( wlimit - q < 4 )
184
0
                        status = 1;
185
18.3k
                else
186
18.3k
                  { if ( code != code_eod )
187
18.2k
                          { q = lzw_put_code(ss, q, code); /* put out final code */
188
18.2k
                                if (ss->next_code == limit_code && ss->next_code != encode_max)
189
0
                                    ss->code_size++;
190
18.2k
                          }
191
18.3k
                        q = lzw_put_code(ss, q, code_eod);
192
18.3k
                        if ( ss->bits_left < 8 )
193
18.2k
                          *++q = ss->bits << ss->bits_left;  /* final byte */
194
18.3k
                  }
195
18.3k
        }
196
7.48M
out:  ss->prev_code = code;
197
7.48M
        pr->ptr = p;
198
7.48M
        pw->ptr = q;
199
7.48M
        return status;
200
6.37M
}
201
202
#undef ss
203
204
/* Stream template */
205
const stream_template s_LZWE_template =
206
{ &st_LZW_state, s_LZWE_init, s_LZWE_process, 1, 4, s_LZW_release,
207
        s_LZW_set_defaults
208
};