Coverage Report

Created: 2026-05-23 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libvncserver/src/libvncserver/zrleencodetemplate.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
3
 * Copyright (C) 2003 Sun Microsystems, Inc.
4
 *
5
 * This is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This software is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this software; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
18
 * USA.
19
 */
20
21
/*
22
 * Before including this file, you must define a number of CPP macros.
23
 *
24
 * BPP should be 8, 16 or 32 depending on the bits per pixel.
25
 * GET_IMAGE_INTO_BUF should be some code which gets a rectangle of pixel data
26
 * into the given buffer.  EXTRA_ARGS can be defined to pass any other
27
 * arguments needed by GET_IMAGE_INTO_BUF.
28
 *
29
 * Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel
30
 * bigger than the largest tile of pixel data, since the ZRLE encoding
31
 * algorithm writes to the position one past the end of the pixel data.
32
 */
33
34
#include "zrleoutstream.h"
35
#include "zrlepalettehelper.h"
36
#include <assert.h>
37
38
/* __RFB_CONCAT2 concatenates its two arguments.  __RFB_CONCAT2E does the same
39
   but also expands its arguments if they are macros */
40
41
#ifndef __RFB_CONCAT2E
42
0
#define __RFB_CONCAT2(a,b) a##b
43
0
#define __RFB_CONCAT2E(a,b) __RFB_CONCAT2(a,b)
44
#endif
45
46
#ifndef __RFB_CONCAT3E
47
0
#define __RFB_CONCAT3(a,b,c) a##b##c
48
0
#define __RFB_CONCAT3E(a,b,c) __RFB_CONCAT3(a,b,c)
49
#endif
50
51
#undef END_FIX
52
#if ZYWRLE_ENDIAN == ENDIAN_LITTLE
53
#  define END_FIX LE
54
#elif ZYWRLE_ENDIAN == ENDIAN_BIG
55
#  define END_FIX BE
56
#else
57
#  define END_FIX NE
58
#endif
59
60
#ifdef CPIXEL
61
0
#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
62
0
#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,CPIXEL)
63
#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,CPIXEL,END_FIX)
64
0
#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,CPIXEL,END_FIX)
65
0
#define BPPOUT 24
66
#elif BPP==15
67
0
#define PIXEL_T __RFB_CONCAT2E(zrle_U,16)
68
0
#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,16)
69
#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX)
70
0
#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX)
71
0
#define BPPOUT 16
72
#else
73
0
#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
74
0
#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,BPP)
75
#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX)
76
0
#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX)
77
0
#define BPPOUT BPP
78
#endif
79
80
#ifndef ZRLE_ONCE
81
#define ZRLE_ONCE
82
83
static const int bitsPerPackedPixel[] = {
84
  0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
85
};
86
87
#endif /* ZRLE_ONCE */
88
89
void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os,
90
    int zywrle_level, int *zywrleBuf, void *paletteHelper);
91
92
#if BPP!=8
93
#define ZYWRLE_ENCODE
94
#include "zywrletemplate.c"
95
#endif
96
97
static void ZRLE_ENCODE (int x, int y, int w, int h,
98
      zrleOutStream* os, void* buf
99
                  EXTRA_ARGS
100
                  )
101
0
{
102
0
  int ty;
103
0
  for (ty = y; ty < y+h; ty += rfbZRLETileHeight) {
104
0
    int tx, th = rfbZRLETileHeight;
105
0
    if (th > y+h-ty) th = y+h-ty;
106
0
    for (tx = x; tx < x+w; tx += rfbZRLETileWidth) {
107
0
      int tw = rfbZRLETileWidth;
108
0
      if (tw > x+w-tx) tw = x+w-tx;
109
110
0
      GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf);
111
112
0
      if (cl->paletteHelper == NULL) {
113
0
          cl->paletteHelper = (void *) calloc(sizeof(zrlePaletteHelper), 1);
114
0
      }
115
116
0
      ZRLE_ENCODE_TILE((PIXEL_T*)buf, tw, th, os,
117
0
          cl->zywrleLevel, cl->zywrleBuf, cl->paletteHelper);
118
0
    }
119
0
  }
120
0
  zrleOutStreamFlush(os);
121
0
}
Unexecuted instantiation: zrle.c:zrleEncode8NE
Unexecuted instantiation: zrle.c:zrleEncode16BE
Unexecuted instantiation: zrle.c:zrleEncode16LE
Unexecuted instantiation: zrle.c:zrleEncode15BE
Unexecuted instantiation: zrle.c:zrleEncode15LE
Unexecuted instantiation: zrle.c:zrleEncode24ABE
Unexecuted instantiation: zrle.c:zrleEncode24ALE
Unexecuted instantiation: zrle.c:zrleEncode24BBE
Unexecuted instantiation: zrle.c:zrleEncode24BLE
Unexecuted instantiation: zrle.c:zrleEncode32BE
Unexecuted instantiation: zrle.c:zrleEncode32LE
122
123
124
void ZRLE_ENCODE_TILE(PIXEL_T* data, int w, int h, zrleOutStream* os,
125
  int zywrle_level, int *zywrleBuf,  void *paletteHelper)
126
0
{
127
  /* First find the palette and the number of runs */
128
129
0
  zrlePaletteHelper *ph;
130
131
0
  int runs = 0;
132
0
  int singlePixels = 0;
133
134
0
  rfbBool useRle;
135
0
  rfbBool usePalette;
136
137
0
  int estimatedBytes;
138
0
  int plainRleBytes;
139
0
  int i;
140
141
0
  PIXEL_T* ptr = data;
142
0
  PIXEL_T* end = ptr + h * w;
143
0
  *end = ~*(end-1); /* one past the end is different so the while loop ends */
144
145
0
  ph = (zrlePaletteHelper *) paletteHelper;
146
0
  zrlePaletteHelperInit(ph);
147
148
0
  while (ptr < end) {
149
0
    PIXEL_T pix = *ptr;
150
0
    if (*++ptr != pix) {
151
0
      singlePixels++;
152
0
    } else {
153
0
      while (*++ptr == pix) ;
154
0
      runs++;
155
0
    }
156
0
    zrlePaletteHelperInsert(ph, pix);
157
0
  }
158
159
  /* Solid tile is a special case */
160
161
0
  if (ph->size == 1) {
162
0
    zrleOutStreamWriteU8(os, 1);
163
0
    zrleOutStreamWRITE_PIXEL(os, ph->palette[0]);
164
0
    return;
165
0
  }
166
167
  /* Try to work out whether to use RLE and/or a palette.  We do this by
168
     estimating the number of bytes which will be generated and picking the
169
     method which results in the fewest bytes.  Of course this may not result
170
     in the fewest bytes after compression... */
171
172
0
  useRle = FALSE;
173
0
  usePalette = FALSE;
174
175
0
  estimatedBytes = w * h * (BPPOUT/8); /* start assuming raw */
176
177
#if BPP!=8
178
0
  if (zywrle_level > 0 && !(zywrle_level & 0x80))
179
0
    estimatedBytes >>= zywrle_level;
180
#endif
181
182
0
  plainRleBytes = ((BPPOUT/8)+1) * (runs + singlePixels);
183
184
0
  if (plainRleBytes < estimatedBytes) {
185
0
    useRle = TRUE;
186
0
    estimatedBytes = plainRleBytes;
187
0
  }
188
189
0
  if (ph->size < 128) {
190
0
    int paletteRleBytes = (BPPOUT/8) * ph->size + 2 * runs + singlePixels;
191
192
0
    if (paletteRleBytes < estimatedBytes) {
193
0
      useRle = TRUE;
194
0
      usePalette = TRUE;
195
0
      estimatedBytes = paletteRleBytes;
196
0
    }
197
198
0
    if (ph->size < 17) {
199
0
      int packedBytes = ((BPPOUT/8) * ph->size +
200
0
                         w * h * bitsPerPackedPixel[ph->size-1] / 8);
201
202
0
      if (packedBytes < estimatedBytes) {
203
0
        useRle = FALSE;
204
0
        usePalette = TRUE;
205
0
        estimatedBytes = packedBytes;
206
0
      }
207
0
    }
208
0
  }
209
210
0
  if (!usePalette) ph->size = 0;
211
212
0
  zrleOutStreamWriteU8(os, (useRle ? 128 : 0) | ph->size);
213
214
0
  for (i = 0; i < ph->size; i++) {
215
0
    zrleOutStreamWRITE_PIXEL(os, ph->palette[i]);
216
0
  }
217
218
0
  if (useRle) {
219
220
0
    PIXEL_T* ptr = data;
221
0
    PIXEL_T* end = ptr + w * h;
222
0
    PIXEL_T* runStart;
223
0
    PIXEL_T pix;
224
0
    while (ptr < end) {
225
0
      int len;
226
0
      runStart = ptr;
227
0
      pix = *ptr++;
228
0
      while (*ptr == pix && ptr < end)
229
0
        ptr++;
230
0
      len = ptr - runStart;
231
0
      if (len <= 2 && usePalette) {
232
0
        int index = zrlePaletteHelperLookup(ph, pix);
233
0
        if (len == 2)
234
0
          zrleOutStreamWriteU8(os, index);
235
0
        zrleOutStreamWriteU8(os, index);
236
0
        continue;
237
0
      }
238
0
      if (usePalette) {
239
0
        int index = zrlePaletteHelperLookup(ph, pix);
240
0
        zrleOutStreamWriteU8(os, index | 128);
241
0
      } else {
242
0
        zrleOutStreamWRITE_PIXEL(os, pix);
243
0
      }
244
0
      len -= 1;
245
0
      while (len >= 255) {
246
0
        zrleOutStreamWriteU8(os, 255);
247
0
        len -= 255;
248
0
      }
249
0
      zrleOutStreamWriteU8(os, len);
250
0
    }
251
252
0
  } else {
253
254
    /* no RLE */
255
256
0
    if (usePalette) {
257
0
      int bppp;
258
0
      PIXEL_T* ptr = data;
259
260
      /* packed pixels */
261
262
0
      assert (ph->size < 17);
263
264
0
      bppp = bitsPerPackedPixel[ph->size-1];
265
266
0
      for (i = 0; i < h; i++) {
267
0
        zrle_U8 nbits = 0;
268
0
        zrle_U8 byte = 0;
269
270
0
        PIXEL_T* eol = ptr + w;
271
272
0
        while (ptr < eol) {
273
0
          PIXEL_T pix = *ptr++;
274
0
          zrle_U8 index = zrlePaletteHelperLookup(ph, pix);
275
0
          byte = (byte << bppp) | index;
276
0
          nbits += bppp;
277
0
          if (nbits >= 8) {
278
0
            zrleOutStreamWriteU8(os, byte);
279
0
            nbits = 0;
280
0
          }
281
0
        }
282
0
        if (nbits > 0) {
283
0
          byte <<= 8 - nbits;
284
0
          zrleOutStreamWriteU8(os, byte);
285
0
        }
286
0
      }
287
0
    } else {
288
289
      /* raw */
290
291
#if BPP!=8
292
0
      if (zywrle_level > 0 && !(zywrle_level & 0x80)) {
293
0
        ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, zywrleBuf);
294
0
  ZRLE_ENCODE_TILE(data, w, h, os, zywrle_level | 0x80, zywrleBuf, paletteHelper);
295
0
      }
296
0
      else
297
0
#endif
298
0
      {
299
#ifdef CPIXEL
300
0
        PIXEL_T *ptr;
301
0
        for (ptr = data; ptr < data+w*h; ptr++)
302
0
          zrleOutStreamWRITE_PIXEL(os, *ptr);
303
#else
304
0
        zrleOutStreamWriteBytes(os, (zrle_U8 *)data, w*h*(BPP/8));
305
#endif
306
0
      }
307
0
    }
308
0
  }
309
0
}
Unexecuted instantiation: zrleEncodeTile8NE
Unexecuted instantiation: zrleEncodeTile15LE
Unexecuted instantiation: zrleEncodeTile15BE
Unexecuted instantiation: zrleEncodeTile16LE
Unexecuted instantiation: zrleEncodeTile16BE
Unexecuted instantiation: zrleEncodeTile32LE
Unexecuted instantiation: zrleEncodeTile32BE
Unexecuted instantiation: zrleEncodeTile24ALE
Unexecuted instantiation: zrleEncodeTile24ABE
Unexecuted instantiation: zrleEncodeTile24BLE
Unexecuted instantiation: zrleEncodeTile24BBE
310
311
#undef PIXEL_T
312
#undef zrleOutStreamWRITE_PIXEL
313
#undef ZRLE_ENCODE
314
#undef ZRLE_ENCODE_TILE
315
#undef ZYWRLE_ENCODE_TILE
316
#undef BPPOUT