[CLIPBRD]
[reactos.git] / reactos / base / applications / clipbrd / fileutils.c
index dd0cc96..3be9acb 100644 (file)
@@ -4,6 +4,7 @@
  * FILE:            base/applications/clipbrd/fileutils.c
  * PURPOSE:         Clipboard file format helper functions.
  * PROGRAMMERS:     Ricardo Hanke
+ *                  Hermes Belusca-Maito
  */
 
 #include "precomp.h"
@@ -16,9 +17,7 @@ static HGLOBAL ClipboardReadMemoryBlock(HANDLE hFile, DWORD dwOffset, DWORD dwLe
 
     hData = GlobalAlloc(GHND, dwLength);
     if (!hData)
-    {
         return NULL;
-    }
 
     lpData = GlobalLock(hData);
     if (!lpData)
@@ -46,20 +45,22 @@ static HGLOBAL ClipboardReadMemoryBlock(HANDLE hFile, DWORD dwOffset, DWORD dwLe
     return hData;
 }
 
-static BOOL ClipboardReadMemory(HANDLE hFile, DWORD dwFormat, DWORD dwOffset, DWORD dwLength, LPCWSTR lpFormatName)
+static BOOL ClipboardReadMemory(HANDLE hFile, DWORD dwFormat, DWORD dwOffset, DWORD dwLength, WORD FileIdentifier, PVOID lpFormatName)
 {
     HGLOBAL hData;
-    DWORD dwTemp;
+    DWORD dwTemp = 0;
 
     hData = ClipboardReadMemoryBlock(hFile, dwOffset, dwLength);
     if (!hData)
-    {
         return FALSE;
-    }
 
     if ((dwFormat >= 0xC000) && (dwFormat <= 0xFFFF))
     {
-        dwTemp = RegisterClipboardFormatW(lpFormatName);
+        if (FileIdentifier == CLIP_FMT_31)
+            dwTemp = RegisterClipboardFormatA((LPCSTR)lpFormatName);
+        else if ((FileIdentifier == CLIP_FMT_NT) || (FileIdentifier == CLIP_FMT_BK))
+            dwTemp = RegisterClipboardFormatW((LPCWSTR)lpFormatName);
+
         if (!dwTemp)
         {
             GlobalFree(hData);
@@ -80,6 +81,39 @@ static BOOL ClipboardReadMemory(HANDLE hFile, DWORD dwFormat, DWORD dwOffset, DW
     return TRUE;
 }
 
+static BOOL ClipboardWriteMemory(HANDLE hFile, DWORD dwFormat, DWORD dwOffset, PDWORD pdwLength)
+{
+    HGLOBAL hData;
+    LPVOID lpData;
+    DWORD dwBytesWritten;
+
+    hData = GetClipboardData(dwFormat);
+    if (!hData)
+        return FALSE;
+
+    lpData = GlobalLock(hData);
+    if (!lpData)
+        return FALSE;
+
+    *pdwLength = GlobalSize(hData);
+
+    if (SetFilePointer(hFile, dwOffset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
+    {
+        GlobalUnlock(hData);
+        return FALSE;
+    }
+
+    if (!WriteFile(hFile, lpData, *pdwLength, &dwBytesWritten, NULL))
+    {
+        GlobalUnlock(hData);
+        return FALSE;
+    }
+
+    GlobalUnlock(hData);
+
+    return TRUE;
+}
+
 static BOOL ClipboardReadPalette(HANDLE hFile, DWORD dwOffset, DWORD dwLength)
 {
     LPLOGPALETTE lpPalette;
@@ -120,6 +154,45 @@ static BOOL ClipboardReadPalette(HANDLE hFile, DWORD dwOffset, DWORD dwLength)
     return TRUE;
 }
 
+static BOOL ClipboardReadMetafile(HANDLE hFile, DWORD dwOffset, DWORD dwLength)
+{
+    HMETAFILE hMf;
+    HGLOBAL hData;
+    LPVOID lpData;
+
+    hData = ClipboardReadMemoryBlock(hFile, dwOffset, dwLength);
+    if (!hData)
+    {
+        return FALSE;
+    }
+
+    lpData = GlobalLock(hData);
+    if (!lpData)
+    {
+        GlobalFree(hData);
+        return FALSE;
+    }
+
+    hMf = SetMetaFileBitsEx(dwLength, lpData);
+
+    GlobalUnlock(hData);
+    GlobalFree(hData);
+
+    if (!hMf)
+    {
+        SetLastError(ERROR_OUTOFMEMORY);
+        return FALSE;
+    }
+
+    if (!SetClipboardData(CF_METAFILEPICT, hMf))
+    {
+        DeleteMetaFile(hMf);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
 static BOOL ClipboardReadEnhMetafile(HANDLE hFile, DWORD dwOffset, DWORD dwLength)
 {
     HENHMETAFILE hEmf;
@@ -202,53 +275,126 @@ static BOOL ClipboardReadBitmap(HANDLE hFile, DWORD dwOffset, DWORD dwLength)
 
 void ReadClipboardFile(LPCWSTR lpFileName)
 {
-    CLIPBOARDFILEHEADER cfhFileHeader;
-    CLIPBOARDFORMATHEADER *cfhFormatArray = NULL;
+    CLIPFILEHEADER ClipFileHeader;
+    CLIPFORMATHEADER ClipFormatArray;
+    NTCLIPFILEHEADER NtClipFileHeader;
+    NTCLIPFORMATHEADER NtClipFormatArray;
+    PVOID pClipFileHeader;
+    PVOID pClipFormatArray;
+    DWORD SizeOfFileHeader, SizeOfFormatHeader;
+
+    WORD wFileIdentifier;
+    WORD wFormatCount;
+    DWORD dwFormatID;
+    DWORD dwLenData;
+    DWORD dwOffData;
+    PVOID szName;
+
     HANDLE hFile;
     DWORD dwBytesRead;
     BOOL bResult;
     int i;
 
-    hFile = CreateFileW(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    /* Open the file for read access */
+    hFile = CreateFileW(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
+                        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
     if (hFile == INVALID_HANDLE_VALUE)
     {
         ShowLastWin32Error(Globals.hMainWnd);
         goto done;
     }
 
-    if (!ReadFile(hFile, &cfhFileHeader, sizeof(cfhFileHeader), &dwBytesRead, NULL))
+    /* Just read enough bytes to get the clipboard file format ID */
+    if (!ReadFile(hFile, &wFileIdentifier, sizeof(wFileIdentifier), &dwBytesRead, NULL))
     {
         ShowLastWin32Error(Globals.hMainWnd);
         goto done;
     }
 
-    if ((cfhFileHeader.wFileIdentifier != CLIPBOARD_FORMAT_NT) && (cfhFileHeader.wFileIdentifier != CLIPBOARD_FORMAT_BK))
+    /* Set data according to the clipboard file format ID */
+    switch (wFileIdentifier)
     {
-        MessageBoxRes(Globals.hMainWnd, Globals.hInstance, ERROR_INVALID_FILE_FORMAT, 0, MB_ICONSTOP | MB_OK);
-        goto done;
+        case CLIP_FMT_31:
+            SizeOfFileHeader   = sizeof(CLIPFILEHEADER);
+            SizeOfFormatHeader = sizeof(CLIPFORMATHEADER);
+            pClipFileHeader    = &ClipFileHeader;
+            pClipFormatArray   = &ClipFormatArray;
+            break;
+
+        case CLIP_FMT_NT:
+        case CLIP_FMT_BK:
+            SizeOfFileHeader   = sizeof(NTCLIPFILEHEADER);
+            SizeOfFormatHeader = sizeof(NTCLIPFORMATHEADER);
+            pClipFileHeader    = &NtClipFileHeader;
+            pClipFormatArray   = &NtClipFormatArray;
+            break;
+
+        default:
+            MessageBoxRes(Globals.hMainWnd, Globals.hInstance, ERROR_INVALID_FILE_FORMAT, 0, MB_ICONSTOP | MB_OK);
+            goto done;
     }
 
-    cfhFormatArray = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cfhFileHeader.wFormatCount * sizeof(CLIPBOARDFORMATHEADER));
-    if (!cfhFormatArray)
+    /* Completely read the header */
+    SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
+    if (!ReadFile(hFile, pClipFileHeader, SizeOfFileHeader, &dwBytesRead, NULL) ||
+        dwBytesRead != SizeOfFileHeader)
     {
-        SetLastError(ERROR_OUTOFMEMORY);
         ShowLastWin32Error(Globals.hMainWnd);
         goto done;
     }
 
-    if (!ReadFile(hFile, cfhFormatArray, cfhFileHeader.wFormatCount * sizeof(CLIPBOARDFORMATHEADER), &dwBytesRead, NULL))
+    /* Get header data */
+    switch (wFileIdentifier)
     {
-        ShowLastWin32Error(Globals.hMainWnd);
-        goto done;
+        case CLIP_FMT_31:
+            assert(wFileIdentifier == ((CLIPFILEHEADER*)pClipFileHeader)->wFileIdentifier);
+            wFormatCount = ((CLIPFILEHEADER*)pClipFileHeader)->wFormatCount;
+            break;
+
+        case CLIP_FMT_NT:
+        case CLIP_FMT_BK:
+            assert(wFileIdentifier == ((NTCLIPFILEHEADER*)pClipFileHeader)->wFileIdentifier);
+            wFormatCount = ((NTCLIPFILEHEADER*)pClipFileHeader)->wFormatCount;
+            break;
     }
 
-    for (i = 0; i < cfhFileHeader.wFormatCount; i++)
+    /* Loop through the format data array */
+    for (i = 0; i < wFormatCount; i++)
     {
-        switch (cfhFormatArray[i].dwFormatID)
+        if (SetFilePointer(hFile, SizeOfFileHeader + i * SizeOfFormatHeader, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
+        {
+            ShowLastWin32Error(Globals.hMainWnd);
+            goto done;
+        }
+
+        if (!ReadFile(hFile, pClipFormatArray, SizeOfFormatHeader, &dwBytesRead, NULL))
+        {
+            ShowLastWin32Error(Globals.hMainWnd);
+            goto done;
+        }
+
+        /* Get format data */
+        switch (wFileIdentifier)
+        {
+            case CLIP_FMT_31:
+                dwFormatID = ((CLIPFORMATHEADER*)pClipFormatArray)->dwFormatID;
+                dwLenData  = ((CLIPFORMATHEADER*)pClipFormatArray)->dwLenData;
+                dwOffData  = ((CLIPFORMATHEADER*)pClipFormatArray)->dwOffData;
+                szName     = ((CLIPFORMATHEADER*)pClipFormatArray)->szName;
+                break;
+
+            case CLIP_FMT_NT:
+            case CLIP_FMT_BK:
+                dwFormatID = ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwFormatID;
+                dwLenData  = ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwLenData;
+                dwOffData  = ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwOffData;
+                szName     = ((NTCLIPFORMATHEADER*)pClipFormatArray)->szName;
+                break;
+        }
+
+        switch (dwFormatID)
         {
             case CF_OWNERDISPLAY:
-            case CF_DSPMETAFILEPICT:
-            case CF_METAFILEPICT:
             {
                 break;
             }
@@ -256,55 +402,191 @@ void ReadClipboardFile(LPCWSTR lpFileName)
             case CF_BITMAP:
             case CF_DSPBITMAP:
             {
-                bResult = ClipboardReadBitmap(hFile, cfhFormatArray[i].dwOffData, cfhFormatArray[i].dwLenData);
+                bResult = ClipboardReadBitmap(hFile, dwOffData, dwLenData);
+                break;
+            }
+
+            case CF_METAFILEPICT:
+            case CF_DSPMETAFILEPICT:
+            {
+                bResult = ClipboardReadMetafile(hFile, dwOffData, dwLenData);
                 break;
             }
 
-            case CF_DSPENHMETAFILE:
             case CF_ENHMETAFILE:
+            case CF_DSPENHMETAFILE:
             {
-                bResult = ClipboardReadEnhMetafile(hFile, cfhFormatArray[i].dwOffData, cfhFormatArray[i].dwLenData);
+                bResult = ClipboardReadEnhMetafile(hFile, dwOffData, dwLenData);
                 break;
             }
 
             case CF_PALETTE:
             {
-                bResult = ClipboardReadPalette(hFile, cfhFormatArray[i].dwOffData, cfhFormatArray[i].dwLenData);
+                bResult = ClipboardReadPalette(hFile, dwOffData, dwLenData);
                 break;
             }
 
             default:
             {
-                if ((cfhFormatArray[i].dwFormatID < CF_PRIVATEFIRST) || (cfhFormatArray[i].dwFormatID > CF_PRIVATELAST))
+                if ((dwFormatID < CF_PRIVATEFIRST) || (dwFormatID > CF_PRIVATELAST))
                 {
-                    bResult = ClipboardReadMemory(hFile, cfhFormatArray[i].dwFormatID, cfhFormatArray[i].dwOffData, cfhFormatArray[i].dwLenData, cfhFormatArray[i].szName);
+                    bResult = ClipboardReadMemory(hFile, dwFormatID, dwOffData, dwLenData, wFileIdentifier, szName);
                 }
                 break;
             }
         }
 
         if (!bResult)
-        {
             ShowLastWin32Error(Globals.hMainWnd);
-        }
     }
 
 done:
     if (hFile != INVALID_HANDLE_VALUE)
-    {
         CloseHandle(hFile);
+
+    return;
+}
+
+void WriteClipboardFile(LPCWSTR lpFileName, WORD wFileIdentifier)
+{
+    CLIPFILEHEADER ClipFileHeader;
+    CLIPFORMATHEADER ClipFormatArray;
+    NTCLIPFILEHEADER NtClipFileHeader;
+    NTCLIPFORMATHEADER NtClipFormatArray;
+    PVOID pClipFileHeader;
+    PVOID pClipFormatArray;
+    DWORD SizeOfFileHeader, SizeOfFormatHeader;
+
+    WORD wFormatCount;
+    DWORD dwFormatID;
+    DWORD dwLenData;
+    DWORD dwOffData;
+    // PVOID szName;
+
+    HANDLE hFile;
+    DWORD dwBytesWritten;
+    int i;
+
+    /* Create the file for write access */
+    hFile = CreateFileW(lpFileName, GENERIC_WRITE, 0, NULL,
+                        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (hFile == INVALID_HANDLE_VALUE)
+    {
+        ShowLastWin32Error(Globals.hMainWnd);
+        goto done;
     }
 
-    if (cfhFormatArray)
+    wFormatCount = CountClipboardFormats();
+
+    /* Select the file format and setup the header according to the clipboard file format ID */
+    switch (wFileIdentifier)
     {
-        HeapFree(GetProcessHeap(), 0, cfhFormatArray);
+        case CLIP_FMT_31:
+            SizeOfFileHeader   = sizeof(CLIPFILEHEADER);
+            SizeOfFormatHeader = sizeof(CLIPFORMATHEADER);
+            pClipFileHeader    = &ClipFileHeader;
+            pClipFormatArray   = &ClipFormatArray;
+
+            ClipFileHeader.wFileIdentifier = CLIP_FMT_31; // wFileIdentifier
+            ClipFileHeader.wFormatCount    = wFormatCount;
+            break;
+
+        case CLIP_FMT_NT:
+        case CLIP_FMT_BK:
+            SizeOfFileHeader   = sizeof(NTCLIPFILEHEADER);
+            SizeOfFormatHeader = sizeof(NTCLIPFORMATHEADER);
+            pClipFileHeader    = &NtClipFileHeader;
+            pClipFormatArray   = &NtClipFormatArray;
+
+            NtClipFileHeader.wFileIdentifier = CLIP_FMT_NT; // wFileIdentifier
+            NtClipFileHeader.wFormatCount    = wFormatCount;
+            break;
+
+        default:
+            MessageBoxRes(Globals.hMainWnd, Globals.hInstance, ERROR_INVALID_FILE_FORMAT, 0, MB_ICONSTOP | MB_OK);
+            goto done;
     }
 
-    return;
-}
+    /* Write the header */
+    SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
+    if (!WriteFile(hFile, pClipFileHeader, SizeOfFileHeader, &dwBytesWritten, NULL) ||
+        dwBytesWritten != SizeOfFileHeader)
+    {
+        ShowLastWin32Error(Globals.hMainWnd);
+        goto done;
+    }
+
+    /* Compute where the data should start (after the file header and the format array) */
+    dwOffData = SizeOfFileHeader + wFormatCount * SizeOfFormatHeader;
+
+    /* Loop through each format and save the data */
+    i = 0;
+    dwFormatID = EnumClipboardFormats(0);
+    while (dwFormatID)
+    {
+        if (i >= wFormatCount)
+        {
+            /* Must never happen! */
+            assert(FALSE);
+            break;
+        }
+
+        /* Write the clipboard data at the specified offset, and retrieve its length */
+        if (!ClipboardWriteMemory(hFile, dwFormatID, dwOffData, &dwLenData))
+            goto Cont;
+
+        /* Write the format data header */
+        switch (wFileIdentifier)
+        {
+            case CLIP_FMT_31:
+                ZeroMemory(pClipFormatArray, sizeof(CLIPFORMATHEADER));
+                ((CLIPFORMATHEADER*)pClipFormatArray)->dwFormatID = dwFormatID;
+                ((CLIPFORMATHEADER*)pClipFormatArray)->dwLenData  = dwLenData;
+                ((CLIPFORMATHEADER*)pClipFormatArray)->dwOffData  = dwOffData;
+                RetrieveClipboardFormatName(Globals.hInstance,
+                                            dwFormatID,
+                                            FALSE,
+                                            ((CLIPFORMATHEADER*)pClipFormatArray)->szName,
+                                            ARRAYSIZE(((CLIPFORMATHEADER*)pClipFormatArray)->szName));
+                break;
+
+            case CLIP_FMT_NT:
+            case CLIP_FMT_BK:
+                ZeroMemory(pClipFormatArray, sizeof(NTCLIPFORMATHEADER));
+                ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwFormatID = dwFormatID;
+                ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwLenData  = dwLenData;
+                ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwOffData  = dwOffData;
+                RetrieveClipboardFormatName(Globals.hInstance,
+                                            dwFormatID,
+                                            TRUE,
+                                            ((NTCLIPFORMATHEADER*)pClipFormatArray)->szName,
+                                            ARRAYSIZE(((NTCLIPFORMATHEADER*)pClipFormatArray)->szName));
+                break;
+        }
+
+        if (SetFilePointer(hFile, SizeOfFileHeader + i * SizeOfFormatHeader, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
+        {
+            ShowLastWin32Error(Globals.hMainWnd);
+            goto done;
+        }
+
+        if (!WriteFile(hFile, pClipFormatArray, SizeOfFormatHeader, &dwBytesWritten, NULL))
+        {
+            ShowLastWin32Error(Globals.hMainWnd);
+            goto done;
+        }
+
+        /* Adjust the offset for the next data stream */
+        dwOffData += dwLenData;
+
+Cont:
+        i++;
+        dwFormatID = EnumClipboardFormats(dwFormatID);
+    }
+
+done:
+    if (hFile != INVALID_HANDLE_VALUE)
+        CloseHandle(hFile);
 
-void WriteClipboardFile(LPCWSTR lpFileName)
-{
-    MessageBoxW(Globals.hMainWnd, L"This function is currently not implemented.", L"Clipboard", MB_OK | MB_ICONINFORMATION);
     return;
 }