20#include <freerdp/config.h>
23#include <winpr/stream.h>
24#include <winpr/assert.h>
26#include <freerdp/freerdp.h>
27#include <freerdp/constants.h>
29#include <freerdp/cache/persistent.h>
31struct rdp_persistent_cache
42static const size_t PERSIST_ALIGN = 32;
43static const char sig_str[] =
"RDP8bmp";
45int persistent_cache_get_version(rdpPersistentCache* persistent)
47 WINPR_ASSERT(persistent);
48 return persistent->version;
51int persistent_cache_get_count(rdpPersistentCache* persistent)
53 WINPR_ASSERT(persistent);
54 return persistent->count;
60 WINPR_ASSERT(persistent);
63 const UINT64 expected = 4ull * entry->width * entry->height;
64 const UINT64 allocated = MAX(0x4000, expected);
65 if (expected > UINT32_MAX)
68 if (allocated > persistent->bmpSize)
70 BYTE* bmpData = (BYTE*)winpr_aligned_recalloc(persistent->bmpData, allocated,
sizeof(BYTE),
75 persistent->bmpSize = allocated;
76 persistent->bmpData = bmpData;
78 entry->data = persistent->bmpData;
79 entry->size = WINPR_ASSERTING_INT_CAST(UINT32, expected);
84static int persistent_cache_read_entry_v2(rdpPersistentCache* persistent,
89 WINPR_ASSERT(persistent);
92 if (fread(&entry2,
sizeof(entry2), 1, persistent->fp) != 1)
95 entry->key64 = entry2.key64;
96 entry->width = entry2.width;
97 entry->height = entry2.height;
98 entry->flags = entry2.flags;
100 if (!persist_cache_get_data(persistent, entry))
103 if (fread(entry->data, 0x4000, 1, persistent->fp) != 1)
110static int persistent_cache_write_entry_v2(rdpPersistentCache* persistent,
115 WINPR_ASSERT(persistent);
117 entry2.key64 = entry->key64;
118 entry2.width = entry->width;
119 entry2.height = entry->height;
120 entry2.size = entry->size;
121 entry2.flags = entry->flags;
124 entry2.flags = 0x00000011;
126 if (fwrite(&entry2,
sizeof(entry2), 1, persistent->fp) != 1)
129 if (fwrite(entry->data, entry->size, 1, persistent->fp) != 1)
132 if (0x4000 > entry->size)
134 const size_t padding = 0x4000 - entry->size;
137 if (!persist_cache_get_data(persistent, &dummyentry))
140 if (fwrite(persistent->bmpData, padding, 1, persistent->fp) != 1)
150static int persistent_cache_read_v2(rdpPersistentCache* persistent)
152 WINPR_ASSERT(persistent);
157 if (fread(&entry,
sizeof(entry), 1, persistent->fp) != 1)
160 if (fseek(persistent->fp, 0x4000, SEEK_CUR) != 0)
170static int persistent_cache_read_entry_v3(rdpPersistentCache* persistent,
175 WINPR_ASSERT(persistent);
178 if (fread(&entry3,
sizeof(entry3), 1, persistent->fp) != 1)
181 entry->key64 = entry3.key64;
182 entry->width = entry3.width;
183 entry->height = entry3.height;
185 if (!persist_cache_get_data(persistent, entry))
188 if (fread(entry->data, entry->size, 1, persistent->fp) != 1)
195static int persistent_cache_write_entry_v3(rdpPersistentCache* persistent,
200 WINPR_ASSERT(persistent);
203 entry3.key64 = entry->key64;
204 entry3.width = entry->width;
205 entry3.height = entry->height;
207 if (fwrite((
void*)&entry3,
sizeof(entry3), 1, persistent->fp) != 1)
210 if (fwrite((
void*)entry->data, entry->size, 1, persistent->fp) != 1)
219static int persistent_cache_read_v3(rdpPersistentCache* persistent)
221 WINPR_ASSERT(persistent);
226 if (fread(&entry,
sizeof(entry), 1, persistent->fp) != 1)
229 if (_fseeki64(persistent->fp, (4LL * entry.width * entry.height), SEEK_CUR) != 0)
240 WINPR_ASSERT(persistent);
243 if (persistent->version == 3)
244 return persistent_cache_read_entry_v3(persistent, entry);
245 else if (persistent->version == 2)
246 return persistent_cache_read_entry_v2(persistent, entry);
251int persistent_cache_write_entry(rdpPersistentCache* persistent,
254 WINPR_ASSERT(persistent);
257 if (persistent->version == 3)
258 return persistent_cache_write_entry_v3(persistent, entry);
259 else if (persistent->version == 2)
260 return persistent_cache_write_entry_v2(persistent, entry);
266static int persistent_cache_open_read(rdpPersistentCache* persistent)
268 BYTE sig[8] = WINPR_C_ARRAY_INIT;
272 WINPR_ASSERT(persistent);
273 persistent->fp = winpr_fopen(persistent->filename,
"rb");
278 if (fread(sig,
sizeof(sig), 1, persistent->fp) != 1)
281 if (memcmp(sig, sig_str,
sizeof(sig_str)) == 0)
282 persistent->version = 3;
284 persistent->version = 2;
286 (void)fseek(persistent->fp, 0, SEEK_SET);
288 if (persistent->version == 3)
292 if (fread(&header,
sizeof(header), 1, persistent->fp) != 1)
295 status = persistent_cache_read_v3(persistent);
296 offset =
sizeof(header);
300 status = persistent_cache_read_v2(persistent);
304 (void)fseek(persistent->fp, offset, SEEK_SET);
310static int persistent_cache_open_write(rdpPersistentCache* persistent)
312 WINPR_ASSERT(persistent);
314 persistent->fp = winpr_fopen(persistent->filename,
"w+b");
319 if (persistent->version == 3)
322 memcpy(header.sig, sig_str, MIN(
sizeof(header.sig),
sizeof(sig_str)));
323 header.flags = 0x00000006;
325 if (fwrite(&header,
sizeof(header), 1, persistent->fp) != 1)
330 if (!persist_cache_get_data(persistent, &dummyentry))
336int persistent_cache_open(rdpPersistentCache* persistent,
const char* filename, BOOL write,
339 WINPR_ASSERT(persistent);
340 WINPR_ASSERT(filename);
341 persistent->write = write;
343 persistent->filename = _strdup(filename);
345 if (!persistent->filename)
348 if (persistent->write)
350 WINPR_ASSERT(version <= INT32_MAX);
351 persistent->version = (int)version;
352 return persistent_cache_open_write(persistent);
355 return persistent_cache_open_read(persistent);
358int persistent_cache_close(rdpPersistentCache* persistent)
360 WINPR_ASSERT(persistent);
363 (void)fclose(persistent->fp);
364 persistent->fp =
nullptr;
370rdpPersistentCache* persistent_cache_new(
void)
372 rdpPersistentCache* persistent = calloc(1,
sizeof(rdpPersistentCache));
380void persistent_cache_free(rdpPersistentCache* persistent)
385 persistent_cache_close(persistent);
387 free(persistent->filename);
389 winpr_aligned_free(persistent->bmpData);