Coverage Report

Created: 2024-09-08 06:16

/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(&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
  const UINT64 size = 4ull * entry3.width * entry3.height;
152
0
  if (size > UINT32_MAX)
153
0
    return -1;
154
0
  entry->size = size;
155
0
  entry->flags = 0;
156
157
0
  if (entry->size > persistent->bmpSize)
158
0
  {
159
0
    persistent->bmpSize = entry->size;
160
0
    BYTE* bmpData = (BYTE*)winpr_aligned_recalloc(persistent->bmpData, persistent->bmpSize,
161
0
                                                  sizeof(BYTE), 32);
162
163
0
    if (!bmpData)
164
0
      return -1;
165
166
0
    persistent->bmpData = bmpData;
167
0
  }
168
169
0
  entry->data = persistent->bmpData;
170
171
0
  if (fread((void*)entry->data, entry->size, 1, persistent->fp) != 1)
172
0
    return -1;
173
174
0
  return 1;
175
0
}
176
177
static int persistent_cache_write_entry_v3(rdpPersistentCache* persistent,
178
                                           const PERSISTENT_CACHE_ENTRY* entry)
179
0
{
180
0
  PERSISTENT_CACHE_ENTRY_V3 entry3 = { 0 };
181
182
0
  WINPR_ASSERT(persistent);
183
0
  WINPR_ASSERT(entry);
184
185
0
  entry3.key64 = entry->key64;
186
0
  entry3.width = entry->width;
187
0
  entry3.height = entry->height;
188
189
0
  if (fwrite((void*)&entry3, sizeof(entry3), 1, persistent->fp) != 1)
190
0
    return -1;
191
192
0
  if (fwrite((void*)entry->data, entry->size, 1, persistent->fp) != 1)
193
0
    return -1;
194
195
0
  persistent->count++;
196
197
0
  return 1;
198
0
}
199
200
static int persistent_cache_read_v3(rdpPersistentCache* persistent)
201
0
{
202
0
  WINPR_ASSERT(persistent);
203
0
  while (1)
204
0
  {
205
0
    PERSISTENT_CACHE_ENTRY_V3 entry = { 0 };
206
207
0
    if (fread((void*)&entry, sizeof(entry), 1, persistent->fp) != 1)
208
0
      break;
209
210
0
    if (_fseeki64(persistent->fp, (4LL * entry.width * entry.height), SEEK_CUR) != 0)
211
0
      break;
212
213
0
    persistent->count++;
214
0
  }
215
216
0
  return 1;
217
0
}
218
219
int persistent_cache_read_entry(rdpPersistentCache* persistent, PERSISTENT_CACHE_ENTRY* entry)
220
0
{
221
0
  WINPR_ASSERT(persistent);
222
0
  WINPR_ASSERT(entry);
223
224
0
  if (persistent->version == 3)
225
0
    return persistent_cache_read_entry_v3(persistent, entry);
226
0
  else if (persistent->version == 2)
227
0
    return persistent_cache_read_entry_v2(persistent, entry);
228
229
0
  return -1;
230
0
}
231
232
int persistent_cache_write_entry(rdpPersistentCache* persistent,
233
                                 const PERSISTENT_CACHE_ENTRY* entry)
234
0
{
235
0
  WINPR_ASSERT(persistent);
236
0
  WINPR_ASSERT(entry);
237
238
0
  if (persistent->version == 3)
239
0
    return persistent_cache_write_entry_v3(persistent, entry);
240
0
  else if (persistent->version == 2)
241
0
    return persistent_cache_write_entry_v2(persistent, entry);
242
243
0
  return -1;
244
0
}
245
246
static int persistent_cache_open_read(rdpPersistentCache* persistent)
247
0
{
248
0
  BYTE sig[8] = { 0 };
249
0
  int status = 1;
250
0
  long offset = 0;
251
252
0
  WINPR_ASSERT(persistent);
253
0
  persistent->fp = winpr_fopen(persistent->filename, "rb");
254
255
0
  if (!persistent->fp)
256
0
    return -1;
257
258
0
  if (fread(sig, 8, 1, persistent->fp) != 1)
259
0
    return -1;
260
261
0
  if (!strncmp((const char*)sig, "RDP8bmp", 8))
262
0
    persistent->version = 3;
263
0
  else
264
0
    persistent->version = 2;
265
266
0
  (void)fseek(persistent->fp, 0, SEEK_SET);
267
268
0
  if (persistent->version == 3)
269
0
  {
270
0
    PERSISTENT_CACHE_HEADER_V3 header;
271
272
0
    if (fread(&header, sizeof(header), 1, persistent->fp) != 1)
273
0
      return -1;
274
275
0
    status = persistent_cache_read_v3(persistent);
276
0
    offset = sizeof(header);
277
0
  }
278
0
  else
279
0
  {
280
0
    status = persistent_cache_read_v2(persistent);
281
0
    offset = 0;
282
0
  }
283
284
0
  (void)fseek(persistent->fp, offset, SEEK_SET);
285
286
0
  return status;
287
0
}
288
289
static int persistent_cache_open_write(rdpPersistentCache* persistent)
290
0
{
291
0
  WINPR_ASSERT(persistent);
292
293
0
  persistent->fp = winpr_fopen(persistent->filename, "w+b");
294
295
0
  if (!persistent->fp)
296
0
    return -1;
297
298
0
  if (persistent->version == 3)
299
0
  {
300
0
    PERSISTENT_CACHE_HEADER_V3 header = { 0 };
301
0
    strncpy((char*)header.sig, "RDP8bmp", 8);
302
0
    header.flags = 0x00000006;
303
304
0
    if (fwrite(&header, sizeof(header), 1, persistent->fp) != 1)
305
0
      return -1;
306
0
  }
307
308
0
  ZeroMemory(persistent->bmpData, persistent->bmpSize);
309
310
0
  return 1;
311
0
}
312
313
int persistent_cache_open(rdpPersistentCache* persistent, const char* filename, BOOL write,
314
                          UINT32 version)
315
0
{
316
0
  WINPR_ASSERT(persistent);
317
0
  WINPR_ASSERT(filename);
318
0
  persistent->write = write;
319
320
0
  persistent->filename = _strdup(filename);
321
322
0
  if (!persistent->filename)
323
0
    return -1;
324
325
0
  if (persistent->write)
326
0
  {
327
0
    persistent->version = version;
328
0
    return persistent_cache_open_write(persistent);
329
0
  }
330
331
0
  return persistent_cache_open_read(persistent);
332
0
}
333
334
int persistent_cache_close(rdpPersistentCache* persistent)
335
0
{
336
0
  WINPR_ASSERT(persistent);
337
0
  if (persistent->fp)
338
0
  {
339
0
    (void)fclose(persistent->fp);
340
0
    persistent->fp = NULL;
341
0
  }
342
343
0
  return 1;
344
0
}
345
346
rdpPersistentCache* persistent_cache_new(void)
347
0
{
348
0
  rdpPersistentCache* persistent = calloc(1, sizeof(rdpPersistentCache));
349
350
0
  if (!persistent)
351
0
    return NULL;
352
353
0
  persistent->bmpSize = 0x4000;
354
0
  persistent->bmpData = calloc(1, persistent->bmpSize);
355
356
0
  if (!persistent->bmpData)
357
0
  {
358
0
    free(persistent);
359
0
    return NULL;
360
0
  }
361
362
0
  return persistent;
363
0
}
364
365
void persistent_cache_free(rdpPersistentCache* persistent)
366
0
{
367
0
  if (!persistent)
368
0
    return;
369
370
0
  persistent_cache_close(persistent);
371
372
0
  free(persistent->filename);
373
374
0
  winpr_aligned_free(persistent->bmpData);
375
376
0
  free(persistent);
377
0
}