Coverage Report

Created: 2025-11-11 06:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libvncserver/src/libvncserver/ultra.c
Line
Count
Source
1
/*
2
 * ultra.c
3
 *
4
 * Routines to implement ultra based encoding (minilzo).
5
 * ultrazip supports packed rectangles if the rects are tiny...
6
 * This improves performance as lzo has more data to work with at once
7
 * This is 'UltraZip' and is currently not implemented.
8
 */
9
10
#include <rfb/rfb.h>
11
#ifdef LIBVNCSERVER_HAVE_LZO
12
#include <lzo/lzo1x.h>
13
#else
14
#include "minilzo.h"
15
#endif
16
17
/*
18
 * cl->beforeEncBuf contains pixel data in the client's format.
19
 * cl->afterEncBuf contains the lzo (deflated) encoding version.
20
 * If the lzo compressed/encoded version is
21
 * larger than the raw data or if it exceeds cl->afterEncBufSize then
22
 * raw encoding is used instead.
23
 */
24
25
26
/*
27
 * rfbSendOneRectEncodingZlib - send a given rectangle using one Zlib
28
 *                              rectangle encoding.
29
 */
30
31
#define MAX_WRKMEM ((LZO1X_1_MEM_COMPRESS) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t)
32
33
34
2.37k
void rfbFreeUltraData(rfbClientPtr cl) {
35
2.37k
  if (cl->compStreamInitedLZO) {
36
0
    free(cl->lzoWrkMem);
37
0
    cl->compStreamInitedLZO=FALSE;
38
0
  }
39
2.37k
}
40
41
42
static rfbBool
43
rfbSendOneRectEncodingUltra(rfbClientPtr cl,
44
                           int x,
45
                           int y,
46
                           int w,
47
                           int h)
48
0
{
49
0
    rfbFramebufferUpdateRectHeader rect;
50
0
    rfbZlibHeader hdr;
51
0
    int deflateResult;
52
0
    int i;
53
0
    char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y)
54
0
         + (x * (cl->scaledScreen->bitsPerPixel / 8)));
55
56
0
    int maxRawSize;
57
0
    lzo_uint maxCompSize;
58
59
0
    maxRawSize = (w * h * (cl->format.bitsPerPixel / 8));
60
61
0
    if (!cl->beforeEncBuf || cl->beforeEncBufSize < maxRawSize) {
62
0
        if (cl->beforeEncBuf == NULL)
63
0
            cl->beforeEncBuf = (char *)malloc(maxRawSize);
64
0
        else {
65
0
            char *reallocedBeforeEncBuf = (char *)realloc(cl->beforeEncBuf, maxRawSize);
66
0
            if (!reallocedBeforeEncBuf) return FALSE;
67
0
            cl->beforeEncBuf = reallocedBeforeEncBuf;
68
0
        }
69
0
        if(cl->beforeEncBuf)
70
0
            cl->beforeEncBufSize = maxRawSize;
71
0
    }
72
73
    /*
74
     * lzo requires output buffer to be slightly larger than the input
75
     * buffer, in the worst case.
76
     */
77
0
    maxCompSize = (maxRawSize + maxRawSize / 16 + 64 + 3);
78
79
0
    if (!cl->afterEncBuf || cl->afterEncBufSize < (int)maxCompSize) {
80
0
        if (cl->afterEncBuf == NULL)
81
0
            cl->afterEncBuf = (char *)malloc(maxCompSize);
82
0
        else {
83
0
            char *reallocedAfterEncBuf = (char *)realloc(cl->afterEncBuf, maxCompSize);
84
0
            if (!reallocedAfterEncBuf) return FALSE;
85
0
            cl->afterEncBuf = reallocedAfterEncBuf;
86
0
        }
87
0
        if(cl->afterEncBuf)
88
0
            cl->afterEncBufSize = maxCompSize;
89
0
    }
90
91
0
    if (!cl->beforeEncBuf || !cl->afterEncBuf)
92
0
    {
93
0
        rfbLog("rfbSendOneRectEncodingUltra: failed to allocate memory\n");
94
0
        return FALSE;
95
0
    }
96
97
    /* 
98
     * Convert pixel data to client format.
99
     */
100
0
    (*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,
101
0
           &cl->format, fbptr, cl->beforeEncBuf,
102
0
           cl->scaledScreen->paddedWidthInBytes, w, h);
103
104
0
    if ( cl->compStreamInitedLZO == FALSE ) {
105
0
        cl->compStreamInitedLZO = TRUE;
106
        /* Work-memory needed for compression. Allocate memory in units
107
         * of `lzo_align_t' (instead of `char') to make sure it is properly aligned.
108
         */  
109
0
        cl->lzoWrkMem = malloc(sizeof(lzo_align_t) * (((LZO1X_1_MEM_COMPRESS) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t)));
110
0
    }
111
112
    /* Perform the compression here. */
113
0
    deflateResult = lzo1x_1_compress((unsigned char *)cl->beforeEncBuf, (lzo_uint)w * h * (cl->format.bitsPerPixel / 8), (unsigned char *)cl->afterEncBuf, &maxCompSize, cl->lzoWrkMem);
114
    /* maxCompSize now contains the compressed size */
115
116
    /* Find the total size of the resulting compressed data. */
117
0
    cl->afterEncBufLen = maxCompSize;
118
119
0
    if ( deflateResult != LZO_E_OK ) {
120
0
        rfbErr("lzo deflation error: %d\n", deflateResult);
121
0
        return FALSE;
122
0
    }
123
124
    /* Update statics */
125
0
    rfbStatRecordEncodingSent(cl, rfbEncodingUltra, sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader + cl->afterEncBufLen, maxRawSize);
126
127
0
    if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader
128
0
  > UPDATE_BUF_SIZE)
129
0
    {
130
0
  if (!rfbSendUpdateBuf(cl))
131
0
      return FALSE;
132
0
    }
133
134
0
    rect.r.x = Swap16IfLE(x);
135
0
    rect.r.y = Swap16IfLE(y);
136
0
    rect.r.w = Swap16IfLE(w);
137
0
    rect.r.h = Swap16IfLE(h);
138
0
    rect.encoding = Swap32IfLE(rfbEncodingUltra);
139
140
0
    memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
141
0
     sz_rfbFramebufferUpdateRectHeader);
142
0
    cl->ublen += sz_rfbFramebufferUpdateRectHeader;
143
144
0
    hdr.nBytes = Swap32IfLE(cl->afterEncBufLen);
145
146
0
    memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbZlibHeader);
147
0
    cl->ublen += sz_rfbZlibHeader;
148
149
    /* We might want to try sending the data directly... */
150
0
    for (i = 0; i < cl->afterEncBufLen;) {
151
152
0
  int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
153
154
0
  if (i + bytesToCopy > cl->afterEncBufLen) {
155
0
      bytesToCopy = cl->afterEncBufLen - i;
156
0
  }
157
158
0
  memcpy(&cl->updateBuf[cl->ublen], &cl->afterEncBuf[i], bytesToCopy);
159
160
0
  cl->ublen += bytesToCopy;
161
0
  i += bytesToCopy;
162
163
0
  if (cl->ublen == UPDATE_BUF_SIZE) {
164
0
      if (!rfbSendUpdateBuf(cl))
165
0
    return FALSE;
166
0
  }
167
0
    }
168
169
0
    return TRUE;
170
171
0
}
172
173
/*
174
 * rfbSendRectEncodingUltra - send a given rectangle using one or more
175
 *                           LZO encoding rectangles.
176
 */
177
178
rfbBool
179
rfbSendRectEncodingUltra(rfbClientPtr cl,
180
                        int x,
181
                        int y,
182
                        int w,
183
                        int h)
184
0
{
185
0
    int  maxLines;
186
0
    int  linesRemaining;
187
0
    rfbRectangle partialRect;
188
189
0
    partialRect.x = x;
190
0
    partialRect.y = y;
191
0
    partialRect.w = w;
192
0
    partialRect.h = h;
193
194
    /* Determine maximum pixel/scan lines allowed per rectangle. */
195
0
    maxLines = ( ULTRA_MAX_SIZE(w) / w );
196
197
    /* Initialize number of scan lines left to do. */
198
0
    linesRemaining = h;
199
200
    /* Loop until all work is done. */
201
0
    while ( linesRemaining > 0 ) {
202
203
0
        int linesToComp;
204
205
0
        if ( maxLines < linesRemaining )
206
0
            linesToComp = maxLines;
207
0
        else
208
0
            linesToComp = linesRemaining;
209
210
0
        partialRect.h = linesToComp;
211
212
        /* Encode (compress) and send the next rectangle. */
213
0
        if ( ! rfbSendOneRectEncodingUltra( cl,
214
0
                                           partialRect.x,
215
0
                                           partialRect.y,
216
0
                                           partialRect.w,
217
0
                                           partialRect.h )) {
218
219
0
            return FALSE;
220
0
        }
221
222
        /* Technically, flushing the buffer here is not extremely
223
         * efficient.  However, this improves the overall throughput
224
         * of the system over very slow networks.  By flushing
225
         * the buffer with every maximum size lzo rectangle, we
226
         * improve the pipelining usage of the server CPU, network,
227
         * and viewer CPU components.  Insuring that these components
228
         * are working in parallel actually improves the performance
229
         * seen by the user.
230
         * Since, lzo is most useful for slow networks, this flush
231
         * is appropriate for the desired behavior of the lzo encoding.
232
         */
233
0
        if (( cl->ublen > 0 ) &&
234
0
            ( linesToComp == maxLines )) {
235
0
            if (!rfbSendUpdateBuf(cl)) {
236
237
0
                return FALSE;
238
0
            }
239
0
        }
240
241
        /* Update remaining and incremental rectangle location. */
242
0
        linesRemaining -= linesToComp;
243
0
        partialRect.y += linesToComp;
244
245
0
    }
246
247
0
    return TRUE;
248
249
0
}