17ffa3e4724cd0d6f008bc3965287ccda7fde7ae
[reactos.git] / reactos / base / applications / clipbrd / fileutils.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Clipboard Viewer
4 * FILE: base/applications/clipbrd/fileutils.c
5 * PURPOSE: Clipboard file format helper functions.
6 * PROGRAMMERS: Ricardo Hanke
7 * Hermes Belusca-Maito
8 */
9
10 #include "precomp.h"
11
12 static HGLOBAL ClipboardReadMemoryBlock(HANDLE hFile, DWORD dwOffset, DWORD dwLength)
13 {
14 HGLOBAL hData;
15 LPVOID lpData;
16 DWORD dwBytesRead;
17
18 hData = GlobalAlloc(GHND, dwLength);
19 if (!hData)
20 return NULL;
21
22 lpData = GlobalLock(hData);
23 if (!lpData)
24 {
25 GlobalFree(hData);
26 return NULL;
27 }
28
29 if (SetFilePointer(hFile, dwOffset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
30 {
31 GlobalUnlock(hData);
32 GlobalFree(hData);
33 return NULL;
34 }
35
36 if (!ReadFile(hFile, lpData, dwLength, &dwBytesRead, NULL))
37 {
38 GlobalUnlock(hData);
39 GlobalFree(hData);
40 return NULL;
41 }
42
43 GlobalUnlock(hData);
44
45 return hData;
46 }
47
48 static BOOL ClipboardReadMemory(HANDLE hFile, DWORD dwFormat, DWORD dwOffset, DWORD dwLength, WORD FileIdentifier, PVOID lpFormatName)
49 {
50 HGLOBAL hData;
51 DWORD dwTemp;
52
53 hData = ClipboardReadMemoryBlock(hFile, dwOffset, dwLength);
54 if (!hData)
55 return FALSE;
56
57 if ((dwFormat >= 0xC000) && (dwFormat <= 0xFFFF))
58 {
59 if (FileIdentifier == CLIP_FMT_31)
60 dwTemp = RegisterClipboardFormatA((LPCSTR)lpFormatName);
61 else if ((FileIdentifier == CLIP_FMT_NT) || (FileIdentifier == CLIP_FMT_BK))
62 dwTemp = RegisterClipboardFormatW((LPCWSTR)lpFormatName);
63
64 if (!dwTemp)
65 {
66 GlobalFree(hData);
67 return FALSE;
68 }
69 }
70 else
71 {
72 dwTemp = dwFormat;
73 }
74
75 if (!SetClipboardData(dwTemp, hData))
76 {
77 GlobalFree(hData);
78 return FALSE;
79 }
80
81 return TRUE;
82 }
83
84 static BOOL ClipboardWriteMemory(HANDLE hFile, DWORD dwFormat, DWORD dwOffset, PDWORD pdwLength)
85 {
86 HGLOBAL hData;
87 LPVOID lpData;
88 DWORD dwBytesWritten;
89
90 hData = GetClipboardData(dwFormat);
91 if (!hData)
92 return FALSE;
93
94 lpData = GlobalLock(hData);
95 if (!lpData)
96 return FALSE;
97
98 *pdwLength = GlobalSize(hData);
99
100 if (SetFilePointer(hFile, dwOffset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
101 {
102 GlobalUnlock(hData);
103 return FALSE;
104 }
105
106 if (!WriteFile(hFile, lpData, *pdwLength, &dwBytesWritten, NULL))
107 {
108 GlobalUnlock(hData);
109 return FALSE;
110 }
111
112 GlobalUnlock(hData);
113
114 return TRUE;
115 }
116
117 static BOOL ClipboardReadPalette(HANDLE hFile, DWORD dwOffset, DWORD dwLength)
118 {
119 LPLOGPALETTE lpPalette;
120 HPALETTE hPalette;
121 HGLOBAL hData;
122
123 hData = ClipboardReadMemoryBlock(hFile, dwOffset, dwLength);
124 if (!hData)
125 {
126 return FALSE;
127 }
128
129 lpPalette = GlobalLock(hData);
130 if (!lpPalette)
131 {
132 GlobalFree(hData);
133 return FALSE;
134 }
135
136 hPalette = CreatePalette(lpPalette);
137 if (!hPalette)
138 {
139 GlobalUnlock(hData);
140 GlobalFree(hData);
141 SetLastError(ERROR_OUTOFMEMORY);
142 return FALSE;
143 }
144
145 GlobalUnlock(hData);
146 GlobalFree(hData);
147
148 if (!SetClipboardData(CF_PALETTE, hPalette))
149 {
150 DeleteObject(hPalette);
151 return FALSE;
152 }
153
154 return TRUE;
155 }
156
157 static BOOL ClipboardReadMetafile(HANDLE hFile, DWORD dwOffset, DWORD dwLength)
158 {
159 HMETAFILE hMf;
160 HGLOBAL hData;
161 LPVOID lpData;
162
163 hData = ClipboardReadMemoryBlock(hFile, dwOffset, dwLength);
164 if (!hData)
165 {
166 return FALSE;
167 }
168
169 lpData = GlobalLock(hData);
170 if (!lpData)
171 {
172 GlobalFree(hData);
173 return FALSE;
174 }
175
176 hMf = SetMetaFileBitsEx(dwLength, lpData);
177
178 GlobalUnlock(hData);
179 GlobalFree(hData);
180
181 if (!hMf)
182 {
183 SetLastError(ERROR_OUTOFMEMORY);
184 return FALSE;
185 }
186
187 if (!SetClipboardData(CF_METAFILEPICT, hMf))
188 {
189 DeleteMetaFile(hMf);
190 return FALSE;
191 }
192
193 return TRUE;
194 }
195
196 static BOOL ClipboardReadEnhMetafile(HANDLE hFile, DWORD dwOffset, DWORD dwLength)
197 {
198 HENHMETAFILE hEmf;
199 HGLOBAL hData;
200 LPVOID lpData;
201
202 hData = ClipboardReadMemoryBlock(hFile, dwOffset, dwLength);
203 if (!hData)
204 {
205 return FALSE;
206 }
207
208 lpData = GlobalLock(hData);
209 if (!lpData)
210 {
211 GlobalFree(hData);
212 return FALSE;
213 }
214
215 hEmf = SetEnhMetaFileBits(dwLength, lpData);
216
217 GlobalUnlock(hData);
218 GlobalFree(hData);
219
220 if (!hEmf)
221 {
222 SetLastError(ERROR_OUTOFMEMORY);
223 return FALSE;
224 }
225
226 if (!SetClipboardData(CF_ENHMETAFILE, hEmf))
227 {
228 DeleteEnhMetaFile(hEmf);
229 return FALSE;
230 }
231
232 return TRUE;
233 }
234
235 static BOOL ClipboardReadBitmap(HANDLE hFile, DWORD dwOffset, DWORD dwLength)
236 {
237 HGLOBAL hData;
238 HBITMAP hBitmap;
239 LPBITMAP lpBitmap;
240
241 hData = ClipboardReadMemoryBlock(hFile, dwOffset, dwLength);
242 if (!hData)
243 {
244 return FALSE;
245 }
246
247 lpBitmap = GlobalLock(hData);
248 if (!lpBitmap)
249 {
250 GlobalFree(hData);
251 return FALSE;
252 }
253
254 lpBitmap->bmBits = lpBitmap + sizeof(BITMAP) + 1;
255
256 hBitmap = CreateBitmapIndirect(lpBitmap);
257
258 GlobalUnlock(hData);
259 GlobalFree(hData);
260
261 if (!hBitmap)
262 {
263 SetLastError(ERROR_OUTOFMEMORY);
264 return FALSE;
265 }
266
267 if (!SetClipboardData(CF_BITMAP, hBitmap))
268 {
269 DeleteObject(hBitmap);
270 return FALSE;
271 }
272
273 return TRUE;
274 }
275
276 void ReadClipboardFile(LPCWSTR lpFileName)
277 {
278 CLIPFILEHEADER ClipFileHeader;
279 CLIPFORMATHEADER ClipFormatArray;
280 NTCLIPFILEHEADER NtClipFileHeader;
281 NTCLIPFORMATHEADER NtClipFormatArray;
282 PVOID pClipFileHeader;
283 PVOID pClipFormatArray;
284 DWORD SizeOfFileHeader, SizeOfFormatHeader;
285
286 WORD wFileIdentifier;
287 WORD wFormatCount;
288 DWORD dwFormatID;
289 DWORD dwLenData;
290 DWORD dwOffData;
291 PVOID szName;
292
293 HANDLE hFile;
294 DWORD dwBytesRead;
295 BOOL bResult;
296 int i;
297
298 /* Open the file for read access */
299 hFile = CreateFileW(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
300 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
301 if (hFile == INVALID_HANDLE_VALUE)
302 {
303 ShowLastWin32Error(Globals.hMainWnd);
304 goto done;
305 }
306
307 /* Just read enough bytes to get the clipboard file format ID */
308 if (!ReadFile(hFile, &wFileIdentifier, sizeof(wFileIdentifier), &dwBytesRead, NULL))
309 {
310 ShowLastWin32Error(Globals.hMainWnd);
311 goto done;
312 }
313
314 /* Set data according to the clipboard file format ID */
315 switch (wFileIdentifier)
316 {
317 case CLIP_FMT_31:
318 SizeOfFileHeader = sizeof(CLIPFILEHEADER);
319 SizeOfFormatHeader = sizeof(CLIPFORMATHEADER);
320 pClipFileHeader = &ClipFileHeader;
321 pClipFormatArray = &ClipFormatArray;
322 break;
323
324 case CLIP_FMT_NT:
325 case CLIP_FMT_BK:
326 SizeOfFileHeader = sizeof(NTCLIPFILEHEADER);
327 SizeOfFormatHeader = sizeof(NTCLIPFORMATHEADER);
328 pClipFileHeader = &NtClipFileHeader;
329 pClipFormatArray = &NtClipFormatArray;
330 break;
331
332 default:
333 MessageBoxRes(Globals.hMainWnd, Globals.hInstance, ERROR_INVALID_FILE_FORMAT, 0, MB_ICONSTOP | MB_OK);
334 goto done;
335 }
336
337 /* Completely read the header */
338 SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
339 if (!ReadFile(hFile, pClipFileHeader, SizeOfFileHeader, &dwBytesRead, NULL) ||
340 dwBytesRead != SizeOfFileHeader)
341 {
342 ShowLastWin32Error(Globals.hMainWnd);
343 goto done;
344 }
345
346 /* Get header data */
347 switch (wFileIdentifier)
348 {
349 case CLIP_FMT_31:
350 assert(wFileIdentifier == ((CLIPFILEHEADER*)pClipFileHeader)->wFileIdentifier);
351 wFormatCount = ((CLIPFILEHEADER*)pClipFileHeader)->wFormatCount;
352 break;
353
354 case CLIP_FMT_NT:
355 case CLIP_FMT_BK:
356 assert(wFileIdentifier == ((NTCLIPFILEHEADER*)pClipFileHeader)->wFileIdentifier);
357 wFormatCount = ((NTCLIPFILEHEADER*)pClipFileHeader)->wFormatCount;
358 break;
359 }
360
361 /* Loop through the format data array */
362 for (i = 0; i < wFormatCount; i++)
363 {
364 if (SetFilePointer(hFile, SizeOfFileHeader + i * SizeOfFormatHeader, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
365 {
366 ShowLastWin32Error(Globals.hMainWnd);
367 goto done;
368 }
369
370 if (!ReadFile(hFile, pClipFormatArray, SizeOfFormatHeader, &dwBytesRead, NULL))
371 {
372 ShowLastWin32Error(Globals.hMainWnd);
373 goto done;
374 }
375
376 /* Get format data */
377 switch (wFileIdentifier)
378 {
379 case CLIP_FMT_31:
380 dwFormatID = ((CLIPFORMATHEADER*)pClipFormatArray)->dwFormatID;
381 dwLenData = ((CLIPFORMATHEADER*)pClipFormatArray)->dwLenData;
382 dwOffData = ((CLIPFORMATHEADER*)pClipFormatArray)->dwOffData;
383 szName = ((CLIPFORMATHEADER*)pClipFormatArray)->szName;
384 break;
385
386 case CLIP_FMT_NT:
387 case CLIP_FMT_BK:
388 dwFormatID = ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwFormatID;
389 dwLenData = ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwLenData;
390 dwOffData = ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwOffData;
391 szName = ((NTCLIPFORMATHEADER*)pClipFormatArray)->szName;
392 break;
393 }
394
395 switch (dwFormatID)
396 {
397 case CF_OWNERDISPLAY:
398 {
399 break;
400 }
401
402 case CF_BITMAP:
403 case CF_DSPBITMAP:
404 {
405 bResult = ClipboardReadBitmap(hFile, dwOffData, dwLenData);
406 break;
407 }
408
409 case CF_METAFILEPICT:
410 case CF_DSPMETAFILEPICT:
411 {
412 bResult = ClipboardReadMetafile(hFile, dwOffData, dwLenData);
413 break;
414 }
415
416 case CF_ENHMETAFILE:
417 case CF_DSPENHMETAFILE:
418 {
419 bResult = ClipboardReadEnhMetafile(hFile, dwOffData, dwLenData);
420 break;
421 }
422
423 case CF_PALETTE:
424 {
425 bResult = ClipboardReadPalette(hFile, dwOffData, dwLenData);
426 break;
427 }
428
429 default:
430 {
431 if ((dwFormatID < CF_PRIVATEFIRST) || (dwFormatID > CF_PRIVATELAST))
432 {
433 bResult = ClipboardReadMemory(hFile, dwFormatID, dwOffData, dwLenData, wFileIdentifier, szName);
434 }
435 break;
436 }
437 }
438
439 if (!bResult)
440 ShowLastWin32Error(Globals.hMainWnd);
441 }
442
443 done:
444 if (hFile != INVALID_HANDLE_VALUE)
445 CloseHandle(hFile);
446
447 return;
448 }
449
450 void WriteClipboardFile(LPCWSTR lpFileName, WORD wFileIdentifier)
451 {
452 CLIPFILEHEADER ClipFileHeader;
453 CLIPFORMATHEADER ClipFormatArray;
454 NTCLIPFILEHEADER NtClipFileHeader;
455 NTCLIPFORMATHEADER NtClipFormatArray;
456 PVOID pClipFileHeader;
457 PVOID pClipFormatArray;
458 DWORD SizeOfFileHeader, SizeOfFormatHeader;
459
460 WORD wFormatCount;
461 DWORD dwFormatID;
462 DWORD dwLenData;
463 DWORD dwOffData;
464 // PVOID szName;
465
466 HANDLE hFile;
467 DWORD dwBytesWritten;
468 int i;
469
470 /* Create the file for write access */
471 hFile = CreateFileW(lpFileName, GENERIC_WRITE, 0, NULL,
472 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
473 if (hFile == INVALID_HANDLE_VALUE)
474 {
475 ShowLastWin32Error(Globals.hMainWnd);
476 goto done;
477 }
478
479 wFormatCount = CountClipboardFormats();
480
481 /* Select the file format and setup the header according to the clipboard file format ID */
482 switch (wFileIdentifier)
483 {
484 case CLIP_FMT_31:
485 SizeOfFileHeader = sizeof(CLIPFILEHEADER);
486 SizeOfFormatHeader = sizeof(CLIPFORMATHEADER);
487 pClipFileHeader = &ClipFileHeader;
488 pClipFormatArray = &ClipFormatArray;
489
490 ClipFileHeader.wFileIdentifier = CLIP_FMT_31; // wFileIdentifier
491 ClipFileHeader.wFormatCount = wFormatCount;
492 break;
493
494 case CLIP_FMT_NT:
495 case CLIP_FMT_BK:
496 SizeOfFileHeader = sizeof(NTCLIPFILEHEADER);
497 SizeOfFormatHeader = sizeof(NTCLIPFORMATHEADER);
498 pClipFileHeader = &NtClipFileHeader;
499 pClipFormatArray = &NtClipFormatArray;
500
501 NtClipFileHeader.wFileIdentifier = CLIP_FMT_NT; // wFileIdentifier
502 NtClipFileHeader.wFormatCount = wFormatCount;
503 break;
504
505 default:
506 MessageBoxRes(Globals.hMainWnd, Globals.hInstance, ERROR_INVALID_FILE_FORMAT, 0, MB_ICONSTOP | MB_OK);
507 goto done;
508 }
509
510 /* Write the header */
511 SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
512 if (!WriteFile(hFile, pClipFileHeader, SizeOfFileHeader, &dwBytesWritten, NULL) ||
513 dwBytesWritten != SizeOfFileHeader)
514 {
515 ShowLastWin32Error(Globals.hMainWnd);
516 goto done;
517 }
518
519 /* Compute where the data should start (after the file header and the format array) */
520 dwOffData = SizeOfFileHeader + wFormatCount * SizeOfFormatHeader;
521
522 /* Loop through each format and save the data */
523 i = 0;
524 dwFormatID = EnumClipboardFormats(0);
525 while (dwFormatID)
526 {
527 if (i >= wFormatCount)
528 {
529 /* Must never happen! */
530 assert(FALSE);
531 break;
532 }
533
534 /* Write the clipboard data at the specified offset, and retrieve its length */
535 if (!ClipboardWriteMemory(hFile, dwFormatID, dwOffData, &dwLenData))
536 goto Cont;
537
538 /* Write the format data header */
539 switch (wFileIdentifier)
540 {
541 case CLIP_FMT_31:
542 ZeroMemory(pClipFormatArray, sizeof(CLIPFORMATHEADER));
543 ((CLIPFORMATHEADER*)pClipFormatArray)->dwFormatID = dwFormatID;
544 ((CLIPFORMATHEADER*)pClipFormatArray)->dwLenData = dwLenData;
545 ((CLIPFORMATHEADER*)pClipFormatArray)->dwOffData = dwOffData;
546 RetrieveClipboardFormatName(Globals.hInstance,
547 dwFormatID,
548 FALSE,
549 ((CLIPFORMATHEADER*)pClipFormatArray)->szName,
550 ARRAYSIZE(((CLIPFORMATHEADER*)pClipFormatArray)->szName));
551 break;
552
553 case CLIP_FMT_NT:
554 case CLIP_FMT_BK:
555 ZeroMemory(pClipFormatArray, sizeof(NTCLIPFORMATHEADER));
556 ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwFormatID = dwFormatID;
557 ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwLenData = dwLenData;
558 ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwOffData = dwOffData;
559 RetrieveClipboardFormatName(Globals.hInstance,
560 dwFormatID,
561 TRUE,
562 ((NTCLIPFORMATHEADER*)pClipFormatArray)->szName,
563 ARRAYSIZE(((NTCLIPFORMATHEADER*)pClipFormatArray)->szName));
564 break;
565 }
566
567 if (SetFilePointer(hFile, SizeOfFileHeader + i * SizeOfFormatHeader, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
568 {
569 ShowLastWin32Error(Globals.hMainWnd);
570 goto done;
571 }
572
573 if (!WriteFile(hFile, pClipFormatArray, SizeOfFormatHeader, &dwBytesWritten, NULL))
574 {
575 ShowLastWin32Error(Globals.hMainWnd);
576 goto done;
577 }
578
579 /* Adjust the offset for the next data stream */
580 dwOffData += dwLenData;
581
582 Cont:
583 i++;
584 dwFormatID = EnumClipboardFormats(dwFormatID);
585 }
586
587 done:
588 if (hFile != INVALID_HANDLE_VALUE)
589 CloseHandle(hFile);
590
591 return;
592 }