1 /**
2  * librfxcodec: A Remote Desktop Protocol client.
3  * RemoteFX Codec Library
4  *
5  * Copyright 2015-2017 Jay Sorg <jay.sorg@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #if defined(HAVE_CONFIG_H)
21 #include <config_ac.h>
22 #endif
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include <rfxcodec_encode.h>
29 
30 #include "rfxcommon.h"
31 #include "rfxencode.h"
32 #include "rfxconstants.h"
33 #include "rfxencode_tile.h"
34 
35 #define LLOG_LEVEL 1
36 #define LLOGLN(_level, _args) \
37     do { if (_level < LLOG_LEVEL) { printf _args ; printf("\n"); } } while (0)
38 
39 #if 1
40 /*****************************************************************************/
41 static int
fdelta(const char * in_plane,char * out_plane,int cx,int cy)42 fdelta(const char *in_plane, char *out_plane, int cx, int cy)
43 {
44     char delta;
45     const char *src8;
46     char *dst8;
47     int index;
48     int jndex;
49 
50     memcpy(out_plane, in_plane, cx);
51     src8 = in_plane;
52     dst8 = out_plane;
53     for (jndex = 1; jndex < cy; jndex++)
54     {
55         for (index = 0; index < cx; index++)
56         {
57             delta = src8[cx] - src8[0];
58             if (delta & 0x80)
59             {
60                 delta = (((~delta) + 1) << 1) - 1;
61             }
62             else
63             {
64                 delta = delta << 1;
65             }
66             dst8[cx] = delta;
67             src8++;
68             dst8++;
69         }
70     }
71     return 0;
72 }
73 #endif
74 
75 #if 0
76 /*****************************************************************************/
77 #define DELTA_ONE \
78 do { \
79     delta = src8[cx] - src8[0]; \
80     is_neg = (delta >> 7) & 1; \
81     dst8[cx] = (((delta ^ -is_neg) + is_neg) << 1) - is_neg; \
82     src8++; \
83     dst8++; \
84 } while (0)
85 
86 /*****************************************************************************/
87 static int
88 fdelta(char *in_plane, char *out_plane, int cx, int cy)
89 {
90     char delta;
91     char is_neg;
92     char *src8;
93     char *dst8;
94     char *src8_end;
95 
96     memcpy(out_plane, in_plane, cx);
97     src8 = in_plane;
98     dst8 = out_plane;
99     src8_end = src8 + (cx * cy - cx);
100     while (src8 + 8 <= src8_end)
101     {
102         DELTA_ONE;
103         DELTA_ONE;
104         DELTA_ONE;
105         DELTA_ONE;
106         DELTA_ONE;
107         DELTA_ONE;
108         DELTA_ONE;
109         DELTA_ONE;
110     }
111     while (src8 < src8_end)
112     {
113         DELTA_ONE;
114     }
115     return 0;
116 }
117 #endif
118 
119 /*****************************************************************************/
120 static int
fout(int collen,int replen,char * colptr,STREAM * s)121 fout(int collen, int replen, char *colptr, STREAM *s)
122 {
123     int code;
124     int lcollen;
125     int lreplen;
126     int cont;
127 
128     LLOGLN(10, ("fout: collen %d replen %d", collen, replen));
129     cont = collen > 13;
130     while (cont)
131     {
132         lcollen = collen;
133         if (lcollen > 15)
134         {
135             lcollen = 15;
136         }
137         code = lcollen << 4;
138         stream_write_uint8(s, code);
139         memcpy(s->p, colptr, lcollen);
140         s->p += lcollen;
141         colptr += lcollen;
142         collen -= lcollen;
143         cont = collen > 13;
144     }
145     cont = (collen > 0) || (replen > 0);
146     while (cont)
147     {
148         lreplen = replen;
149         if ((collen == 0) && (lreplen > 15))
150         {
151             /* big run */
152             if (lreplen > 47)
153             {
154                 lreplen = 47;
155             }
156             LLOGLN(10, ("fout: big run lreplen %d", lreplen));
157             replen -= lreplen;
158             code = ((lreplen & 0xF) << 4) | ((lreplen & 0xF0) >> 4);
159             stream_write_uint8(s, code);
160             colptr += lreplen;
161         }
162         else
163         {
164             if (lreplen > 15)
165             {
166                 lreplen = 15;
167             }
168             replen -= lreplen;
169             if (lreplen < 3)
170             {
171                 collen += lreplen;
172                 lreplen = 0;
173             }
174             code = (collen << 4) | lreplen;
175             stream_write_uint8(s, code);
176             memcpy(s->p, colptr, collen);
177             s->p += collen;
178             colptr += collen + lreplen;
179             collen = 0;
180         }
181         cont = replen > 0;
182     }
183     return 0;
184 }
185 
186 /*****************************************************************************/
187 static int
fpack(char * plane,int cx,int cy,STREAM * s)188 fpack(char *plane, int cx, int cy, STREAM *s)
189 {
190     char *ptr8;
191     char *colptr;
192     char *lend;
193     uint8 *holdp;
194     int jndex;
195     int collen;
196     int replen;
197 
198     LLOGLN(10, ("fpack:"));
199     holdp = s->p;
200     for (jndex = 0; jndex < cy; jndex++)
201     {
202         LLOGLN(10, ("line start line %d cx %d cy %d", jndex, cx, cy));
203         ptr8 = (char *) (plane + jndex * cx);
204         lend = ptr8 + (cx - 1);
205         colptr = ptr8;
206         if (colptr[0] == 0)
207         {
208             collen = 0;
209             replen = 1;
210         }
211         else
212         {
213             collen = 1;
214             replen = 0;
215         }
216         while (ptr8 < lend)
217         {
218             if (ptr8[0] == ptr8[1])
219             {
220                 replen++;
221             }
222             else
223             {
224                 if (replen > 0)
225                 {
226                     if (replen < 3)
227                     {
228                         collen += replen + 1;
229                         replen = 0;
230                     }
231                     else
232                     {
233                         fout(collen, replen, colptr, s);
234                         colptr = ptr8 + 1;
235                         replen = 0;
236                         collen = 1;
237                     }
238                 }
239                 else
240                 {
241                     collen++;
242                 }
243             }
244             ptr8++;
245         }
246         /* end of line */
247         fout(collen, replen, colptr, s);
248     }
249     return (int) (s->p - holdp);
250 }
251 
252 /*****************************************************************************/
253 int
rfx_encode_plane(struct rfxencode * enc,const uint8 * plane,int cx,int cy,STREAM * s)254 rfx_encode_plane(struct rfxencode *enc, const uint8 *plane, int cx, int cy,
255                  STREAM *s)
256 {
257     const char *org_plane;
258     char *delta_plane;
259     int bytes;
260     uint8 *holdp;
261 
262     org_plane = (const char *) plane;
263     delta_plane = (char *) (enc->dwt_buffer1);
264     fdelta(org_plane, delta_plane, cx, cy);
265     holdp = s->p;
266     stream_write_uint8(s, 0x10); /* flags, RLE */
267     bytes = fpack(delta_plane, cx, cy, s);
268     if (bytes > cx * cy)
269     {
270         LLOGLN(10, ("rfx_encode_plane: too big bytes %d", bytes));
271         s->p = holdp;
272         stream_write_uint8(s, 0); /* flags */
273         memcpy(s->p, plane, cx * cy);
274         s->p += cx * cy;
275         stream_write_uint8(s, 0); /* pad if not RLE */
276         bytes = cx * cy + 2;
277     }
278     else
279     {
280         LLOGLN(10, ("rfx_encode_plane: ok bytes %d", bytes));
281     }
282     return bytes;
283 }
284