20 #include <freerdp/config.h>
22 #include <winpr/crt.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>
31 struct rdp_persistent_cache
42 static const char sig_str[] =
"RDP8bmp";
44 int persistent_cache_get_version(rdpPersistentCache* persistent)
46 WINPR_ASSERT(persistent);
47 return persistent->version;
50 int persistent_cache_get_count(rdpPersistentCache* persistent)
52 WINPR_ASSERT(persistent);
53 return persistent->count;
56 static int persistent_cache_read_entry_v2(rdpPersistentCache* persistent,
61 WINPR_ASSERT(persistent);
64 if (fread((
void*)&entry2,
sizeof(entry2), 1, persistent->fp) != 1)
67 entry->key64 = entry2.key64;
68 entry->width = entry2.width;
69 entry->height = entry2.height;
70 entry->size = entry2.width * entry2.height * 4;
71 entry->flags = entry2.flags;
73 entry->data = persistent->bmpData;
75 if (fread((
void*)entry->data, 0x4000, 1, persistent->fp) != 1)
81 static int persistent_cache_write_entry_v2(rdpPersistentCache* persistent,
86 WINPR_ASSERT(persistent);
88 entry2.key64 = entry->key64;
89 entry2.width = entry->width;
90 entry2.height = entry->height;
91 entry2.size = entry->size;
92 entry2.flags = entry->flags;
95 entry2.flags = 0x00000011;
97 if (fwrite(&entry2,
sizeof(entry2), 1, persistent->fp) != 1)
100 if (fwrite(entry->data, entry->size, 1, persistent->fp) != 1)
103 if (0x4000 > entry->size)
105 const size_t padding = 0x4000 - entry->size;
107 if (fwrite(persistent->bmpData, padding, 1, persistent->fp) != 1)
116 static int persistent_cache_read_v2(rdpPersistentCache* persistent)
118 WINPR_ASSERT(persistent);
123 if (fread((
void*)&entry,
sizeof(entry), 1, persistent->fp) != 1)
126 if (fseek(persistent->fp, 0x4000, SEEK_CUR) != 0)
135 static int persistent_cache_read_entry_v3(rdpPersistentCache* persistent,
140 WINPR_ASSERT(persistent);
143 if (fread(&entry3,
sizeof(entry3), 1, persistent->fp) != 1)
146 entry->key64 = entry3.key64;
147 entry->width = entry3.width;
148 entry->height = entry3.height;
149 const UINT64 size = 4ull * entry3.width * entry3.height;
150 if (size > UINT32_MAX)
152 entry->size = (UINT32)size;
155 if (entry->size > persistent->bmpSize)
157 persistent->bmpSize = entry->size;
158 BYTE* bmpData = (BYTE*)winpr_aligned_recalloc(persistent->bmpData, persistent->bmpSize,
164 persistent->bmpData = bmpData;
167 entry->data = persistent->bmpData;
169 if (fread((
void*)entry->data, entry->size, 1, persistent->fp) != 1)
175 static int persistent_cache_write_entry_v3(rdpPersistentCache* persistent,
180 WINPR_ASSERT(persistent);
183 entry3.key64 = entry->key64;
184 entry3.width = entry->width;
185 entry3.height = entry->height;
187 if (fwrite((
void*)&entry3,
sizeof(entry3), 1, persistent->fp) != 1)
190 if (fwrite((
void*)entry->data, entry->size, 1, persistent->fp) != 1)
198 static int persistent_cache_read_v3(rdpPersistentCache* persistent)
200 WINPR_ASSERT(persistent);
205 if (fread((
void*)&entry,
sizeof(entry), 1, persistent->fp) != 1)
208 if (_fseeki64(persistent->fp, (4LL * entry.width * entry.height), SEEK_CUR) != 0)
219 WINPR_ASSERT(persistent);
222 if (persistent->version == 3)
223 return persistent_cache_read_entry_v3(persistent, entry);
224 else if (persistent->version == 2)
225 return persistent_cache_read_entry_v2(persistent, entry);
230 int persistent_cache_write_entry(rdpPersistentCache* persistent,
233 WINPR_ASSERT(persistent);
236 if (persistent->version == 3)
237 return persistent_cache_write_entry_v3(persistent, entry);
238 else if (persistent->version == 2)
239 return persistent_cache_write_entry_v2(persistent, entry);
244 static int persistent_cache_open_read(rdpPersistentCache* persistent)
250 WINPR_ASSERT(persistent);
251 persistent->fp = winpr_fopen(persistent->filename,
"rb");
256 if (fread(sig, 8, 1, persistent->fp) != 1)
259 if (memcmp(sig, sig_str,
sizeof(sig_str)) == 0)
260 persistent->version = 3;
262 persistent->version = 2;
264 (void)fseek(persistent->fp, 0, SEEK_SET);
266 if (persistent->version == 3)
270 if (fread(&header,
sizeof(header), 1, persistent->fp) != 1)
273 status = persistent_cache_read_v3(persistent);
274 offset =
sizeof(header);
278 status = persistent_cache_read_v2(persistent);
282 (void)fseek(persistent->fp, offset, SEEK_SET);
287 static int persistent_cache_open_write(rdpPersistentCache* persistent)
289 WINPR_ASSERT(persistent);
291 persistent->fp = winpr_fopen(persistent->filename,
"w+b");
296 if (persistent->version == 3)
299 memcpy(header.sig, sig_str, MIN(
sizeof(header.sig),
sizeof(sig_str)));
300 header.flags = 0x00000006;
302 if (fwrite(&header,
sizeof(header), 1, persistent->fp) != 1)
306 ZeroMemory(persistent->bmpData, persistent->bmpSize);
311 int persistent_cache_open(rdpPersistentCache* persistent,
const char* filename, BOOL write,
314 WINPR_ASSERT(persistent);
315 WINPR_ASSERT(filename);
316 persistent->write = write;
318 persistent->filename = _strdup(filename);
320 if (!persistent->filename)
323 if (persistent->write)
325 WINPR_ASSERT(version <= INT32_MAX);
326 persistent->version = (int)version;
327 return persistent_cache_open_write(persistent);
330 return persistent_cache_open_read(persistent);
333 int persistent_cache_close(rdpPersistentCache* persistent)
335 WINPR_ASSERT(persistent);
338 (void)fclose(persistent->fp);
339 persistent->fp = NULL;
345 rdpPersistentCache* persistent_cache_new(
void)
347 rdpPersistentCache* persistent = calloc(1,
sizeof(rdpPersistentCache));
352 persistent->bmpSize = 0x4000;
353 persistent->bmpData = calloc(1, persistent->bmpSize);
355 if (!persistent->bmpData)
364 void persistent_cache_free(rdpPersistentCache* persistent)
369 persistent_cache_close(persistent);
371 free(persistent->filename);
373 winpr_aligned_free(persistent->bmpData);