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