Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/libfreerdp/cache/persistent.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Persistent Bitmap Cache
4
 *
5
 * Copyright 2016 Marc-Andre Moreau <marcandre.moreau@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
#include <freerdp/config.h>
21
22
#include <winpr/crt.h>
23
#include <winpr/stream.h>
24
#include <winpr/assert.h>
25
26
#include <freerdp/freerdp.h>
27
#include <freerdp/constants.h>
28
29
#include <freerdp/log.h>
30
#include <freerdp/cache/persistent.h>
31
32
#define TAG FREERDP_TAG("cache.persistent")
33
34
struct rdp_persistent_cache
35
{
36
  FILE* fp;
37
  BOOL write;
38
  UINT32 version;
39
  int count;
40
  char* filename;
41
  BYTE* bmpData;
42
  UINT32 bmpSize;
43
};
44
45
int persistent_cache_get_version(rdpPersistentCache* persistent)
46
0
{
47
0
  WINPR_ASSERT(persistent);
48
0
  return persistent->version;
49
0
}
50
51
int persistent_cache_get_count(rdpPersistentCache* persistent)
52
0
{
53
0
  WINPR_ASSERT(persistent);
54
0
  return persistent->count;
55
0
}
56
57
static int persistent_cache_read_entry_v2(rdpPersistentCache* persistent,
58
                                          PERSISTENT_CACHE_ENTRY* entry)
59
0
{
60
0
  PERSISTENT_CACHE_ENTRY_V2 entry2 = { 0 };
61
62
0
  WINPR_ASSERT(persistent);
63
0
  WINPR_ASSERT(entry);
64
65
0
  if (fread((void*)&entry2, sizeof(entry2), 1, persistent->fp) != 1)
66
0
    return -1;
67
68
0
  entry->key64 = entry2.key64;
69
0
  entry->width = entry2.width;
70
0
  entry->height = entry2.height;
71
0
  entry->size = entry2.width * entry2.height * 4;
72
0
  entry->flags = entry2.flags;
73
74
0
  entry->data = persistent->bmpData;
75
76
0
  if (fread((void*)entry->data, 0x4000, 1, persistent->fp) != 1)
77
0
    return -1;
78
79
0
  return 1;
80
0
}
81
82
static int persistent_cache_write_entry_v2(rdpPersistentCache* persistent,
83
                                           const PERSISTENT_CACHE_ENTRY* entry)
84
0
{
85
0
  int padding = 0;
86
0
  PERSISTENT_CACHE_ENTRY_V2 entry2 = { 0 };
87
88
0
  WINPR_ASSERT(persistent);
89
0
  WINPR_ASSERT(entry);
90
0
  entry2.key64 = entry->key64;
91
0
  entry2.width = entry->width;
92
0
  entry2.height = entry->height;
93
0
  entry2.size = entry->size;
94
0
  entry2.flags = entry->flags;
95
96
0
  if (!entry2.flags)
97
0
    entry2.flags = 0x00000011;
98
99
0
  if (fwrite((void*)&entry2, sizeof(entry2), 1, persistent->fp) != 1)
100
0
    return -1;
101
102
0
  if (fwrite((void*)entry->data, entry->size, 1, persistent->fp) != 1)
103
0
    return -1;
104
105
0
  if (0x4000 > entry->size)
106
0
  {
107
0
    padding = 0x4000 - entry->size;
108
109
0
    if (fwrite((void*)persistent->bmpData, padding, 1, persistent->fp) != 1)
110
0
      return -1;
111
0
  }
112
113
0
  persistent->count++;
114
115
0
  return 1;
116
0
}
117
118
static int persistent_cache_read_v2(rdpPersistentCache* persistent)
119
0
{
120
0
  WINPR_ASSERT(persistent);
121
0
  while (1)
122
0
  {
123
0
    PERSISTENT_CACHE_ENTRY_V2 entry = { 0 };
124
125
0
    if (fread((void*)&entry, sizeof(entry), 1, persistent->fp) != 1)
126
0
      break;
127
128
0
    if (fseek(persistent->fp, 0x4000, SEEK_CUR) != 0)
129
0
      break;
130
131
0
    persistent->count++;
132
0
  }
133
134
0
  return 1;
135
0
}
136
137
static int persistent_cache_read_entry_v3(rdpPersistentCache* persistent,
138
                                          PERSISTENT_CACHE_ENTRY* entry)
139
0
{
140
0
  PERSISTENT_CACHE_ENTRY_V3 entry3 = { 0 };
141
142
0
  WINPR_ASSERT(persistent);
143
0
  WINPR_ASSERT(entry);
144
145
0
  if (fread((void*)&entry3, sizeof(entry3), 1, persistent->fp) != 1)
146
0
    return -1;
147
148
0
  entry->key64 = entry3.key64;
149
0
  entry->width = entry3.width;
150
0
  entry->height = entry3.height;
151
0
  entry->size = entry3.width * entry3.height * 4;
152
0
  entry->flags = 0;
153
154
0
  if (entry->size > persistent->bmpSize)
155
0
  {
156
0
    persistent->bmpSize = entry->size;
157
0
    BYTE* bmpData = (BYTE*)winpr_aligned_recalloc(persistent->bmpData, persistent->bmpSize,
158
0
                                                  sizeof(BYTE), 32);
159
160
0
    if (!bmpData)
161
0
      return -1;
162
163
0
    persistent->bmpData = bmpData;
164
0
  }
165
166
0
  entry->data = persistent->bmpData;
167
168
0
  if (fread((void*)entry->data, entry->size, 1, persistent->fp) != 1)
169
0
    return -1;
170
171
0
  return 1;
172
0
}
173
174
static int persistent_cache_write_entry_v3(rdpPersistentCache* persistent,
175
                                           const PERSISTENT_CACHE_ENTRY* entry)
176
0
{
177
0
  PERSISTENT_CACHE_ENTRY_V3 entry3 = { 0 };
178
179
0
  WINPR_ASSERT(persistent);
180
0
  WINPR_ASSERT(entry);
181
182
0
  entry3.key64 = entry->key64;
183
0
  entry3.width = entry->width;
184
0
  entry3.height = entry->height;
185
186
0
  if (fwrite((void*)&entry3, sizeof(entry3), 1, persistent->fp) != 1)
187
0
    return -1;
188
189
0
  if (fwrite((void*)entry->data, entry->size, 1, persistent->fp) != 1)
190
0
    return -1;
191
192
0
  persistent->count++;
193
194
0
  return 1;
195
0
}
196
197
static int persistent_cache_read_v3(rdpPersistentCache* persistent)
198
0
{
199
0
  WINPR_ASSERT(persistent);
200
0
  while (1)
201
0
  {
202
0
    PERSISTENT_CACHE_ENTRY_V3 entry = { 0 };
203
204
0
    if (fread((void*)&entry, sizeof(entry), 1, persistent->fp) != 1)
205
0
      break;
206
207
0
    if (fseek(persistent->fp, (entry.width * entry.height * 4), SEEK_CUR) != 0)
208
0
      break;
209
210
0
    persistent->count++;
211
0
  }
212
213
0
  return 1;
214
0
}
215
216
int persistent_cache_read_entry(rdpPersistentCache* persistent, PERSISTENT_CACHE_ENTRY* entry)
217
0
{
218
0
  WINPR_ASSERT(persistent);
219
0
  WINPR_ASSERT(entry);
220
221
0
  if (persistent->version == 3)
222
0
    return persistent_cache_read_entry_v3(persistent, entry);
223
0
  else if (persistent->version == 2)
224
0
    return persistent_cache_read_entry_v2(persistent, entry);
225
226
0
  return -1;
227
0
}
228
229
int persistent_cache_write_entry(rdpPersistentCache* persistent,
230
                                 const PERSISTENT_CACHE_ENTRY* entry)
231
0
{
232
0
  WINPR_ASSERT(persistent);
233
0
  WINPR_ASSERT(entry);
234
235
0
  if (persistent->version == 3)
236
0
    return persistent_cache_write_entry_v3(persistent, entry);
237
0
  else if (persistent->version == 2)
238
0
    return persistent_cache_write_entry_v2(persistent, entry);
239
240
0
  return -1;
241
0
}
242
243
static int persistent_cache_open_read(rdpPersistentCache* persistent)
244
0
{
245
0
  BYTE sig[8] = { 0 };
246
0
  int status = 1;
247
0
  long offset = 0;
248
249
0
  WINPR_ASSERT(persistent);
250
0
  persistent->fp = winpr_fopen(persistent->filename, "rb");
251
252
0
  if (!persistent->fp)
253
0
    return -1;
254
255
0
  if (fread(sig, 8, 1, persistent->fp) != 1)
256
0
    return -1;
257
258
0
  if (!strncmp((const char*)sig, "RDP8bmp", 8))
259
0
    persistent->version = 3;
260
0
  else
261
0
    persistent->version = 2;
262
263
0
  fseek(persistent->fp, 0, SEEK_SET);
264
265
0
  if (persistent->version == 3)
266
0
  {
267
0
    PERSISTENT_CACHE_HEADER_V3 header;
268
269
0
    if (fread(&header, sizeof(header), 1, persistent->fp) != 1)
270
0
      return -1;
271
272
0
    status = persistent_cache_read_v3(persistent);
273
0
    offset = sizeof(header);
274
0
  }
275
0
  else
276
0
  {
277
0
    status = persistent_cache_read_v2(persistent);
278
0
    offset = 0;
279
0
  }
280
281
0
  fseek(persistent->fp, offset, SEEK_SET);
282
283
0
  return status;
284
0
}
285
286
static int persistent_cache_open_write(rdpPersistentCache* persistent)
287
0
{
288
0
  WINPR_ASSERT(persistent);
289
290
0
  persistent->fp = winpr_fopen(persistent->filename, "w+b");
291
292
0
  if (!persistent->fp)
293
0
    return -1;
294
295
0
  if (persistent->version == 3)
296
0
  {
297
0
    PERSISTENT_CACHE_HEADER_V3 header = { 0 };
298
0
    strncpy((char*)header.sig, "RDP8bmp", 8);
299
0
    header.flags = 0x00000006;
300
301
0
    if (fwrite(&header, sizeof(header), 1, persistent->fp) != 1)
302
0
      return -1;
303
0
  }
304
305
0
  ZeroMemory(persistent->bmpData, persistent->bmpSize);
306
307
0
  return 1;
308
0
}
309
310
int persistent_cache_open(rdpPersistentCache* persistent, const char* filename, BOOL write,
311
                          UINT32 version)
312
0
{
313
0
  WINPR_ASSERT(persistent);
314
0
  WINPR_ASSERT(filename);
315
0
  persistent->write = write;
316
317
0
  persistent->filename = _strdup(filename);
318
319
0
  if (!persistent->filename)
320
0
    return -1;
321
322
0
  if (persistent->write)
323
0
  {
324
0
    persistent->version = version;
325
0
    return persistent_cache_open_write(persistent);
326
0
  }
327
328
0
  return persistent_cache_open_read(persistent);
329
0
}
330
331
int persistent_cache_close(rdpPersistentCache* persistent)
332
0
{
333
0
  WINPR_ASSERT(persistent);
334
0
  if (persistent->fp)
335
0
  {
336
0
    fclose(persistent->fp);
337
0
    persistent->fp = NULL;
338
0
  }
339
340
0
  return 1;
341
0
}
342
343
rdpPersistentCache* persistent_cache_new(void)
344
0
{
345
0
  rdpPersistentCache* persistent = calloc(1, sizeof(rdpPersistentCache));
346
347
0
  if (!persistent)
348
0
    return NULL;
349
350
0
  persistent->bmpSize = 0x4000;
351
0
  persistent->bmpData = calloc(1, persistent->bmpSize);
352
353
0
  if (!persistent->bmpData)
354
0
  {
355
0
    free(persistent);
356
0
    return NULL;
357
0
  }
358
359
0
  return persistent;
360
0
}
361
362
void persistent_cache_free(rdpPersistentCache* persistent)
363
0
{
364
0
  if (!persistent)
365
0
    return;
366
367
0
  persistent_cache_close(persistent);
368
369
0
  free(persistent->filename);
370
371
0
  winpr_aligned_free(persistent->bmpData);
372
373
0
  free(persistent);
374
0
}