1 /*
2 Copyright (C) 2009 Red Hat, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 */
17 #include <config.h>
18
19 #include <glib.h>
20 #include <pthread.h>
21 #include <stdio.h>
22 #include "glz-encoder.h"
23 #include "glz-encoder-priv.h"
24
25
26 /* Holds a specific data for one encoder, and data that is relevant for the current image encoded */
27 typedef struct Encoder {
28 GlzEncoderUsrContext *usr;
29 uint8_t id;
30 SharedDictionary *dict;
31
32 struct {
33 LzImageType type;
34 uint32_t id;
35 uint32_t first_win_seg;
36 } cur_image;
37
38 struct {
39 uint8_t *start;
40 uint8_t *now;
41 uint8_t *end;
42 size_t bytes_count;
43 uint8_t *last_copy; // pointer to the last byte in which copy count was written
44 } io;
45 } Encoder;
46
47
48 /**************************************************************************
49 * Handling writing the encoded image to the output buffer
50 ***************************************************************************/
more_io_bytes(Encoder * encoder)51 static inline int more_io_bytes(Encoder *encoder)
52 {
53 uint8_t *io_ptr;
54 int num_io_bytes = encoder->usr->more_space(encoder->usr, &io_ptr);
55 encoder->io.bytes_count += num_io_bytes;
56 encoder->io.now = io_ptr;
57 encoder->io.end = encoder->io.now + num_io_bytes;
58 return num_io_bytes;
59 }
60
encode(Encoder * encoder,uint8_t byte)61 static inline void encode(Encoder *encoder, uint8_t byte)
62 {
63 if (encoder->io.now == encoder->io.end) {
64 if (more_io_bytes(encoder) <= 0) {
65 encoder->usr->error(encoder->usr, "%s: no more bytes\n", __FUNCTION__);
66 }
67 GLZ_ASSERT(encoder->usr, encoder->io.now);
68 }
69
70 GLZ_ASSERT(encoder->usr, encoder->io.now < encoder->io.end);
71 *(encoder->io.now++) = byte;
72 }
73
encode_32(Encoder * encoder,unsigned int word)74 static inline void encode_32(Encoder *encoder, unsigned int word)
75 {
76 encode(encoder, (uint8_t)(word >> 24));
77 encode(encoder, (uint8_t)(word >> 16) & 0x0000ff);
78 encode(encoder, (uint8_t)(word >> 8) & 0x0000ff);
79 encode(encoder, (uint8_t)(word & 0x0000ff));
80 }
81
encode_64(Encoder * encoder,uint64_t word)82 static inline void encode_64(Encoder *encoder, uint64_t word)
83 {
84 encode_32(encoder, (uint32_t)(word >> 32));
85 encode_32(encoder, (uint32_t)(word & 0xffffffffu));
86 }
87
encode_copy_count(Encoder * encoder,uint8_t copy_count)88 static inline void encode_copy_count(Encoder *encoder, uint8_t copy_count)
89 {
90 encode(encoder, copy_count);
91 encoder->io.last_copy = encoder->io.now - 1; // io_now cannot be the first byte of the buffer
92 }
93
update_copy_count(Encoder * encoder,uint8_t copy_count)94 static inline void update_copy_count(Encoder *encoder, uint8_t copy_count)
95 {
96 GLZ_ASSERT(encoder->usr, encoder->io.last_copy);
97 *(encoder->io.last_copy) = copy_count;
98 }
99
100 // decrease the io ptr by 1
compress_output_prev(Encoder * encoder)101 static inline void compress_output_prev(Encoder *encoder)
102 {
103 // io_now cannot be the first byte of the buffer
104 encoder->io.now--;
105 // the function should be called only when copy count is written unnecessarily by glz_compress
106 GLZ_ASSERT(encoder->usr, encoder->io.now == encoder->io.last_copy)
107 }
108
encoder_reset(Encoder * encoder,uint8_t * io_ptr,uint8_t * io_ptr_end)109 static bool encoder_reset(Encoder *encoder, uint8_t *io_ptr, uint8_t *io_ptr_end)
110 {
111 GLZ_ASSERT(encoder->usr, io_ptr <= io_ptr_end);
112 encoder->io.bytes_count = io_ptr_end - io_ptr;
113 encoder->io.start = io_ptr;
114 encoder->io.now = io_ptr;
115 encoder->io.end = io_ptr_end;
116 encoder->io.last_copy = NULL;
117
118 return TRUE;
119 }
120
121 /**********************************************************
122 * Encoding
123 ***********************************************************/
124
glz_encoder_create(uint8_t id,GlzEncDictContext * dictionary,GlzEncoderUsrContext * usr)125 GlzEncoderContext *glz_encoder_create(uint8_t id, GlzEncDictContext *dictionary,
126 GlzEncoderUsrContext *usr)
127 {
128 Encoder *encoder;
129
130 if (!usr || !usr->error || !usr->warn || !usr->info || !usr->malloc ||
131 !usr->free || !usr->more_space) {
132 return NULL;
133 }
134
135 if (!(encoder = (Encoder *)usr->malloc(usr, sizeof(Encoder)))) {
136 return NULL;
137 }
138
139 encoder->id = id;
140 encoder->usr = usr;
141 encoder->dict = (SharedDictionary *)dictionary;
142
143 return (GlzEncoderContext *)encoder;
144 }
145
glz_encoder_destroy(GlzEncoderContext * opaque_encoder)146 void glz_encoder_destroy(GlzEncoderContext *opaque_encoder)
147 {
148 Encoder *encoder = (Encoder *)opaque_encoder;
149
150 if (!opaque_encoder) {
151 return;
152 }
153
154 encoder->usr->free(encoder->usr, encoder);
155 }
156
157 /*
158 * Give hints to the compiler for branch prediction optimization.
159 */
160 #if defined(__GNUC__) && (__GNUC__ > 2)
161 #define LZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1))
162 #define LZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0))
163 #else
164 #define LZ_EXPECT_CONDITIONAL(c) (c)
165 #define LZ_UNEXPECT_CONDITIONAL(c) (c)
166 #endif
167
168
169 typedef uint8_t BYTE;
170
171 typedef struct one_byte_pixel_t {
172 BYTE a;
173 } one_byte_pixel_t;
174
175 typedef struct rgb32_pixel_t {
176 BYTE b;
177 BYTE g;
178 BYTE r;
179 BYTE pad;
180 } rgb32_pixel_t;
181
182 typedef struct rgb24_pixel_t {
183 BYTE b;
184 BYTE g;
185 BYTE r;
186 } rgb24_pixel_t;
187
188 typedef uint16_t rgb16_pixel_t;
189
190 #define BOUND_OFFSET 2
191 #define LIMIT_OFFSET 6
192 #define MIN_FILE_SIZE 4
193
194 #define MAX_PIXEL_SHORT_DISTANCE 4096 // (1 << 12)
195 #define MAX_PIXEL_MEDIUM_DISTANCE 131072 // (1 << 17) 2 ^ (12 + 5)
196 #define MAX_PIXEL_LONG_DISTANCE 33554432 // (1 << 25) 2 ^ (12 + 5 + 8)
197 #define MAX_IMAGE_DIST 16777215 // (1 << 24 - 1)
198
199
200 //#define DEBUG_ENCODE
201
202
203 #define GLZ_ENCODE_SIZE
204 #include "glz-encode-match.tmpl.c"
205 #define GLZ_ENCODE_MATCH
206 #include "glz-encode-match.tmpl.c"
207
208 #define LZ_PLT
209 #include "glz-encode.tmpl.c"
210
211 #define LZ_RGB16
212 #include "glz-encode.tmpl.c"
213
214 #define LZ_RGB24
215 #include "glz-encode.tmpl.c"
216
217 #define LZ_RGB32
218 #include "glz-encode.tmpl.c"
219
220 #define LZ_RGB_ALPHA
221 #include "glz-encode.tmpl.c"
222
223
glz_encode(GlzEncoderContext * opaque_encoder,LzImageType type,int width,int height,int top_down,uint8_t * lines,unsigned int num_lines,int stride,uint8_t * io_ptr,unsigned int num_io_bytes,GlzUsrImageContext * usr_context,GlzEncDictImageContext ** o_enc_dict_context)224 int glz_encode(GlzEncoderContext *opaque_encoder,
225 LzImageType type, int width, int height, int top_down,
226 uint8_t *lines, unsigned int num_lines, int stride,
227 uint8_t *io_ptr, unsigned int num_io_bytes,
228 GlzUsrImageContext *usr_context, GlzEncDictImageContext **o_enc_dict_context)
229 {
230 Encoder *encoder = (Encoder *)opaque_encoder;
231 WindowImage *dict_image;
232 uint8_t *io_ptr_end = io_ptr + num_io_bytes;
233 uint32_t win_head_image_dist;
234
235 if (IS_IMAGE_TYPE_PLT[type]) {
236 if (stride > (width / PLT_PIXELS_PER_BYTE[type])) {
237 if (((width % PLT_PIXELS_PER_BYTE[type]) == 0) || (
238 (stride - (width / PLT_PIXELS_PER_BYTE[type])) > 1)) {
239 encoder->usr->error(encoder->usr, "stride overflows (plt)\n");
240 }
241 }
242 } else {
243 if (stride != width * RGB_BYTES_PER_PIXEL[type]) {
244 encoder->usr->error(encoder->usr, "stride != width*bytes_per_pixel (rgb)\n");
245 }
246 }
247
248 // assign the output buffer
249 if (!encoder_reset(encoder, io_ptr, io_ptr_end)) {
250 encoder->usr->error(encoder->usr, "lz encoder io reset failed\n");
251 }
252
253 // first read the list of the image segments into the dictionary window
254 dict_image = glz_dictionary_pre_encode(encoder->id, encoder->usr,
255 encoder->dict, type, width, height, stride,
256 lines, num_lines, usr_context, &win_head_image_dist);
257 *o_enc_dict_context = (GlzEncDictImageContext *)dict_image;
258
259 encoder->cur_image.type = type;
260 encoder->cur_image.id = dict_image->id;
261 encoder->cur_image.first_win_seg = dict_image->first_seg;
262
263 encode_32(encoder, LZ_MAGIC);
264 encode_32(encoder, LZ_VERSION);
265 if (top_down) {
266 encode(encoder, (type & LZ_IMAGE_TYPE_MASK) | (1 << LZ_IMAGE_TYPE_LOG));
267 } else {
268 encode(encoder, (type & LZ_IMAGE_TYPE_MASK));
269 }
270
271 encode_32(encoder, width);
272 encode_32(encoder, height);
273 encode_32(encoder, stride);
274 encode_64(encoder, dict_image->id);
275 encode_32(encoder, win_head_image_dist);
276
277 switch (encoder->cur_image.type) {
278 case LZ_IMAGE_TYPE_PLT1_BE:
279 case LZ_IMAGE_TYPE_PLT1_LE:
280 case LZ_IMAGE_TYPE_PLT4_BE:
281 case LZ_IMAGE_TYPE_PLT4_LE:
282 case LZ_IMAGE_TYPE_PLT8:
283 glz_plt_compress(encoder);
284 break;
285 case LZ_IMAGE_TYPE_RGB16:
286 glz_rgb16_compress(encoder);
287 break;
288 case LZ_IMAGE_TYPE_RGB24:
289 glz_rgb24_compress(encoder);
290 break;
291 case LZ_IMAGE_TYPE_RGB32:
292 glz_rgb32_compress(encoder);
293 break;
294 case LZ_IMAGE_TYPE_RGBA:
295 glz_rgb32_compress(encoder);
296 glz_rgb_alpha_compress(encoder);
297 break;
298 case LZ_IMAGE_TYPE_INVALID:
299 default:
300 encoder->usr->error(encoder->usr, "bad image type\n");
301 }
302
303 glz_dictionary_post_encode(encoder->id, encoder->usr, encoder->dict);
304
305 // move all the used segments to the free ones
306 encoder->io.bytes_count -= (encoder->io.end - encoder->io.now);
307
308 return encoder->io.bytes_count;
309 }
310