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;
57static int persistent_cache_read_entry_v2(rdpPersistentCache* persistent,
62 WINPR_ASSERT(persistent);
65 if (fread((
void*)&entry2,
sizeof(entry2), 1, persistent->fp) != 1)
68 entry->key64 = entry2.key64;
69 entry->width = entry2.width;
70 entry->height = entry2.height;
71 entry->size = entry2.width * entry2.height * 4;
72 entry->flags = entry2.flags;
74 entry->data = persistent->bmpData;
76 if (fread((
void*)entry->data, 0x4000, 1, persistent->fp) != 1)
82static int persistent_cache_write_entry_v2(rdpPersistentCache* persistent,
87 WINPR_ASSERT(persistent);
89 entry2.key64 = entry->key64;
90 entry2.width = entry->width;
91 entry2.height = entry->height;
92 entry2.size = entry->size;
93 entry2.flags = entry->flags;
96 entry2.flags = 0x00000011;
98 if (fwrite(&entry2,
sizeof(entry2), 1, persistent->fp) != 1)
101 if (fwrite(entry->data, entry->size, 1, persistent->fp) != 1)
104 if (0x4000 > entry->size)
106 const size_t padding = 0x4000 - entry->size;
108 if (fwrite(persistent->bmpData, padding, 1, persistent->fp) != 1)
117static int persistent_cache_read_v2(rdpPersistentCache* persistent)
119 WINPR_ASSERT(persistent);
124 if (fread((
void*)&entry,
sizeof(entry), 1, persistent->fp) != 1)
127 if (fseek(persistent->fp, 0x4000, SEEK_CUR) != 0)
136static int persistent_cache_read_entry_v3(rdpPersistentCache* persistent,
141 WINPR_ASSERT(persistent);
144 if (fread(&entry3,
sizeof(entry3), 1, persistent->fp) != 1)
147 entry->key64 = entry3.key64;
148 entry->width = entry3.width;
149 entry->height = entry3.height;
150 const UINT64 size = 4ull * entry3.width * entry3.height;
151 if (size > UINT32_MAX)
155 if (size > persistent->bmpSize)
157 persistent->bmpSize = size;
158 BYTE* bmpData = (BYTE*)winpr_aligned_recalloc(persistent->bmpData, persistent->bmpSize,
159 sizeof(BYTE), PERSIST_ALIGN);
164 persistent->bmpData = bmpData;
166 entry->size = WINPR_ASSERTING_INT_CAST(UINT32, size);
168 entry->data = persistent->bmpData;
170 if (fread((
void*)entry->data, entry->size, 1, persistent->fp) != 1)
176static int persistent_cache_write_entry_v3(rdpPersistentCache* persistent,
181 WINPR_ASSERT(persistent);
184 entry3.key64 = entry->key64;
185 entry3.width = entry->width;
186 entry3.height = entry->height;
188 if (fwrite((
void*)&entry3,
sizeof(entry3), 1, persistent->fp) != 1)
191 if (fwrite((
void*)entry->data, entry->size, 1, persistent->fp) != 1)
199static int persistent_cache_read_v3(rdpPersistentCache* persistent)
201 WINPR_ASSERT(persistent);
206 if (fread((
void*)&entry,
sizeof(entry), 1, persistent->fp) != 1)
209 if (_fseeki64(persistent->fp, (4LL * entry.width * entry.height), SEEK_CUR) != 0)
220 WINPR_ASSERT(persistent);
223 if (persistent->version == 3)
224 return persistent_cache_read_entry_v3(persistent, entry);
225 else if (persistent->version == 2)
226 return persistent_cache_read_entry_v2(persistent, entry);
231int persistent_cache_write_entry(rdpPersistentCache* persistent,
234 WINPR_ASSERT(persistent);
237 if (persistent->version == 3)
238 return persistent_cache_write_entry_v3(persistent, entry);
239 else if (persistent->version == 2)
240 return persistent_cache_write_entry_v2(persistent, entry);
245static int persistent_cache_open_read(rdpPersistentCache* persistent)
247 BYTE sig[8] = WINPR_C_ARRAY_INIT;
251 WINPR_ASSERT(persistent);
252 persistent->fp = winpr_fopen(persistent->filename,
"rb");
257 if (fread(sig, 8, 1, persistent->fp) != 1)
260 if (memcmp(sig, sig_str,
sizeof(sig_str)) == 0)
261 persistent->version = 3;
263 persistent->version = 2;
265 (void)fseek(persistent->fp, 0, SEEK_SET);
267 if (persistent->version == 3)
271 if (fread(&header,
sizeof(header), 1, persistent->fp) != 1)
274 status = persistent_cache_read_v3(persistent);
275 offset =
sizeof(header);
279 status = persistent_cache_read_v2(persistent);
283 (void)fseek(persistent->fp, offset, SEEK_SET);
288static int persistent_cache_open_write(rdpPersistentCache* persistent)
290 WINPR_ASSERT(persistent);
292 persistent->fp = winpr_fopen(persistent->filename,
"w+b");
297 if (persistent->version == 3)
300 memcpy(header.sig, sig_str, MIN(
sizeof(header.sig),
sizeof(sig_str)));
301 header.flags = 0x00000006;
303 if (fwrite(&header,
sizeof(header), 1, persistent->fp) != 1)
307 ZeroMemory(persistent->bmpData, persistent->bmpSize);
312int persistent_cache_open(rdpPersistentCache* persistent,
const char* filename, BOOL write,
315 WINPR_ASSERT(persistent);
316 WINPR_ASSERT(filename);
317 persistent->write = write;
319 persistent->filename = _strdup(filename);
321 if (!persistent->filename)
324 if (persistent->write)
326 WINPR_ASSERT(version <= INT32_MAX);
327 persistent->version = (int)version;
328 return persistent_cache_open_write(persistent);
331 return persistent_cache_open_read(persistent);
334int persistent_cache_close(rdpPersistentCache* persistent)
336 WINPR_ASSERT(persistent);
339 (void)fclose(persistent->fp);
340 persistent->fp =
nullptr;
346rdpPersistentCache* persistent_cache_new(
void)
348 rdpPersistentCache* persistent = calloc(1,
sizeof(rdpPersistentCache));
353 persistent->bmpSize = 0x4000;
354 persistent->bmpData = winpr_aligned_calloc(1, persistent->bmpSize, PERSIST_ALIGN);
356 if (!persistent->bmpData)
365void persistent_cache_free(rdpPersistentCache* persistent)
370 persistent_cache_close(persistent);
372 free(persistent->filename);
374 winpr_aligned_free(persistent->bmpData);