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