1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements.  See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership.  The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License.  You may obtain a copy of the License at
10 *
11 *   http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied.  See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21 
22 
23 // MARKER(update_precomp.py): autogen include statement, do not remove
24 #include "precompiled_dtrans.hxx"
25 
26 #define INCL_DOSERRORS
27 
28 #include <stdio.h>
29 #include <string.h>
30 #include <unistd.h>
31 
32 #include <rtl/string.hxx>
33 
34 #include "OTransferable.hxx"
35 #include "globals.hxx"
36 
37 
OTransferable(HWND hwndTarget,PDRAGINFO dragInfo)38 OTransferable::OTransferable( HWND hwndTarget, PDRAGINFO dragInfo)
39     : m_aFlavorList( 1),
40       mHwndTarget( hwndTarget),
41       mDragInfo( dragInfo),
42       removeOnExit( false),
43       pDTShare( NULL),
44       renderDRM( DRM_NULL),
45       mimeType( MIMETYPE_NULL)
46 {
47     USHORT cItems;
48     PDRAGITEM dragItem;
49     PSZ pNativeRMF;
50 
51     strcpy( fullpath, "");
52 
53     cItems = DrgQueryDragitemCount(dragInfo);
54     if (cItems > 1) {
55         debug_printf("OTransferable::OTransferable multiple drop not supported");
56         return;
57     }
58 
59     ULONG ulLength;
60     PSZ pBuffer;
61 
62     // get 1st item
63     dragItem = DrgQueryDragitemPtr(dragInfo, 0);
64 
65     // dump true type
66     ulLength = DrgQueryTrueTypeLen( dragItem) + 1;
67     pBuffer = (PSZ) malloc( ulLength);
68     DrgQueryTrueType( dragItem, ulLength, pBuffer);
69     debug_printf("DrgQueryTrueType %s", pBuffer);
70     free( pBuffer);
71 
72     // get native RMF format
73     ulLength = DrgQueryNativeRMFLen( dragItem) + 1;
74     pNativeRMF = (PSZ) malloc( ulLength);
75     DrgQueryNativeRMF( dragItem, ulLength, pNativeRMF);
76     debug_printf("OTransferable::OTransferable DrgQueryNativeRMF %s", pNativeRMF);
77 
78     debug_printf("OTransferable::OTransferable DrgVerifyRMF DRM_ATOM %d", DrgVerifyRMF( dragItem, "DRM_ATOM", NULL));
79     debug_printf("OTransferable::OTransferable DrgVerifyRMF DRM_OS2FILE %d", DrgVerifyRMF( dragItem, "DRM_OS2FILE", NULL));
80     debug_printf("OTransferable::OTransferable DrgVerifyRMF DRM_PRINTOBJECT %d", DrgVerifyRMF( dragItem, "DRM_PRINTOBJECT", NULL));
81     debug_printf("OTransferable::OTransferable DrgVerifyRMF DRM_SHAREDMEM %d", DrgVerifyRMF( dragItem, "DRM_SHAREDMEM", NULL));
82     debug_printf("OTransferable::OTransferable DrgVerifyRMF DRM_DTSHARE %d", DrgVerifyRMF( dragItem, "DRM_DTSHARE", NULL));
83 
84     DataFlavor df;
85 
86     if (strstr( pNativeRMF, "<DRM_ATOM") != 0
87             || strstr( pNativeRMF, "<DRM_DTSHARE") != 0
88             || strstr( pNativeRMF, "<DRM_SHAREDMEM") != 0) {
89 
90         df.MimeType = OUString::createFromAscii( "text/plain;charset=utf-16" );
91         df.DataType = getCppuType( static_cast<rtl::OUString*>(0));
92         m_aFlavorList[0] = df;
93         mimeType = MIMETYPE_TEXT;
94 
95     } else if (strstr( pNativeRMF, "<DRM_OS2FILE") != 0) {
96 
97         df.MimeType = OUString::createFromAscii(
98                     "application/x-openoffice-file;windows_formatname=\"FileName\"");
99         df.DataType = getCppuType( static_cast<OUString*>(0));
100         m_aFlavorList[0] = df;
101         mimeType = MIMETYPE_FILE;
102 
103     } else {
104 
105         mimeType = MIMETYPE_NULL;
106         debug_printf("OTransferable::OTransferable UNKNOWN native RMF");
107 
108     }
109 
110     free( pNativeRMF);
111 
112 }
113 
~OTransferable()114 OTransferable::~OTransferable()
115 {
116     if (removeOnExit) {
117         int rc;
118         rc = unlink( fullpath);
119         debug_printf( "OTransferable::~OTransferable unlink rc=%d", rc);
120     }
121 }
122 
123 
124 //
125 // a generic request dispatcher
126 //
RequestFileRendering(PDRAGITEM pditem,HWND hwnd,PCSZ pRMF,PCSZ pName)127 bool OTransferable::RequestFileRendering( PDRAGITEM pditem, HWND hwnd,
128                                           PCSZ pRMF, PCSZ pName)
129 {
130     PDRAGTRANSFER pdxfer;
131 
132     pdxfer = DrgAllocDragtransfer( 1);
133     if (!pdxfer)
134         return true;
135 
136     pdxfer->cb = sizeof(DRAGTRANSFER);
137     pdxfer->hwndClient = hwnd;
138     pdxfer->pditem = pditem;
139     pdxfer->hstrSelectedRMF = DrgAddStrHandle( pRMF);
140     pdxfer->hstrRenderToName = 0;
141     pdxfer->ulTargetInfo = pditem->ulItemID;
142     pdxfer->usOperation = (USHORT)DO_COPY;
143     pdxfer->fsReply = 0;
144 
145     // send the msg before setting a render-to name
146     if (pditem->fsControl & DC_PREPAREITEM)
147         DrgSendTransferMsg( pditem->hwndItem, DM_RENDERPREPARE, (MPARAM)pdxfer, 0);
148 
149     if (pName)
150         pdxfer->hstrRenderToName = DrgAddStrHandle( pName);
151     else
152         pdxfer->hstrRenderToName = 0;
153 
154     // send the msg after setting a render-to name
155     if ((pditem->fsControl & (DC_PREPARE | DC_PREPAREITEM)) == DC_PREPARE)
156         DrgSendTransferMsg( pditem->hwndItem, DM_RENDERPREPARE, (MPARAM)pdxfer, 0);
157 
158     // ask the source to render the selected item
159     if (!DrgSendTransferMsg( pditem->hwndItem, DM_RENDER, (MPARAM)pdxfer, 0))
160         return true;
161 
162     return false;
163 }
164 
165 // currently, the same filename is used for every render request;
166 // it is deleted when the drag session ends
167 //
RenderToOS2File(PDRAGITEM pditem,HWND hwnd)168 bool OTransferable::RenderToOS2File( PDRAGITEM pditem, HWND hwnd)
169 {
170     bool rv = true;
171 
172     const char * pszRMF;
173     if (DrgVerifyRMF(pditem, "DRM_OS2FILE", "DRF_TEXT"))
174         pszRMF = OS2FILE_TXTRMF;
175     else
176         pszRMF = OS2FILE_UNKRMF;
177 
178     // create temp name
179     strcpy( fullpath, tempnam( NULL, "AOO"));
180     debug_printf("OTransferable::RenderToOS2File to %s", fullpath);
181 
182     rv = RequestFileRendering( pditem, hwnd, pszRMF, fullpath);
183 
184     return rv;
185 }
186 
187 // DTShare uses 1mb of uncommitted named-shared memory
188 // (next time I'll do it differently - rw)
189 //
RenderToDTShare(PDRAGITEM pditem,HWND hwnd)190 bool OTransferable::RenderToDTShare( PDRAGITEM pditem, HWND hwnd)
191 {
192     bool rv;
193 
194     APIRET rc = DosAllocSharedMem( &pDTShare, DTSHARE_NAME, 0x100000,
195                                    PAG_WRITE | PAG_READ | OBJ_ANY);
196     if (rc != NO_ERROR &&
197             rc != ERROR_ALREADY_EXISTS) { // Did the kernel handle OBJ_ANY?
198         // Try again without OBJ_ANY and if the first failure was not caused
199         // by OBJ_ANY then we will get the same failure, else we have taken
200         // care of pre-FP13 systems where the kernel couldn't handle it.
201         rc = DosAllocSharedMem( &pDTShare, DTSHARE_NAME, 0x100000,
202                                 PAG_WRITE | PAG_READ);
203     }
204 
205     if (rc == ERROR_ALREADY_EXISTS)
206         rc = DosGetNamedSharedMem( &pDTShare, DTSHARE_NAME,
207                                    PAG_WRITE | PAG_READ);
208     if (rc)
209         rv = true; // error
210     else
211         rv = RequestFileRendering( pditem, hwnd, DTSHARE_RMF, DTSHARE_NAME);
212 
213     return rv;
214 }
215 
216 // SharedMem rendering, memory is allocated by source window
217 //
RenderToSharedMem(PDRAGITEM pditem,HWND hwnd)218 bool OTransferable::RenderToSharedMem( PDRAGITEM pditem, HWND hwnd)
219 {
220     bool rv;
221 
222     rv = RequestFileRendering( pditem, hwnd, SHAREDMEM_RMF, NULL);
223 
224     return rv;
225 }
226 
requestRendering(void)227 bool OTransferable::requestRendering( void)
228 {
229     char path[CCHMAXPATH];
230     char file[CCHMAXPATH];
231     PDRAGITEM dragItem;
232 
233     // unknown rendering
234     renderDRM = DRM_NULL;
235 
236     // only 1st item supported
237     dragItem = DrgQueryDragitemPtr( mDragInfo, 0);
238 
239     // check if we already have all necessary fields or a rendering
240     // request must be sent to source window
241 
242     switch( mimeType) {
243     case MIMETYPE_NULL:
244         debug_printf("OTransferable::requestRendering INTERNAL ERROR, mimetype undef");
245         break;
246 
247     case MIMETYPE_FILE:
248         if (DrgVerifyRMF( dragItem, "DRM_OS2FILE", NULL)
249                 && dragItem->hstrSourceName == NULLHANDLE) {
250 
251             // if hstrSourceName is NULL we need to ask source for rendering
252             bool rv;
253             debug_printf("OTransferable::requestRendering request rendering");
254             rv = RenderToOS2File( dragItem, mHwndTarget);
255             debug_printf("OTransferable::requestRendering requested rendering rv=%d", rv);
256             renderDRM = DRM_OS2FILE;
257 
258             // notify rendering request ongoing
259             return true;
260 
261         } else if (DrgVerifyRMF( dragItem, "DRM_OS2FILE", NULL)) {
262 
263             // we have hstrSourceName, no need for rendering,
264             // we already have enough data for rendering path now
265 
266             // get full path
267             DrgQueryStrName(dragItem->hstrContainerName, sizeof(path), path);
268             debug_printf("OTransferable::getTransferData hstrSourceName %x", dragItem->hstrSourceName);
269             debug_printf("OTransferable::getTransferData hstrTargetName %x", dragItem->hstrTargetName);
270             DrgQueryStrName(dragItem->hstrSourceName, sizeof(file), file);
271             sprintf( fullpath, "%s%s", path, file);
272             debug_printf("OTransferable::getTransferData fullpath %s", fullpath);
273             renderDRM = DRM_OS2FILE;
274 
275         } else {
276             debug_printf("OTransferable::requestRendering UNKNOWN request for FILE mimetype");
277         }
278         break;
279 
280     case MIMETYPE_TEXT:
281         if (DrgVerifyRMF( dragItem, "DRM_ATOM", NULL)) {
282 
283             DrgQueryStrName(dragItem->ulItemID, sizeof(fullpath), fullpath);
284             debug_printf("OTransferable::requestRendering DRM_ATOM '%s'", fullpath);
285             renderDRM = DRM_ATOM;
286 
287             // no request rendering necessary
288             return false;
289 
290         } else if (DrgVerifyRMF( dragItem, "DRM_DTSHARE", NULL)) {
291 
292             bool rv;
293             debug_printf("OTransferable::requestRendering request DRM_DTSHARE rendering");
294             rv = RenderToDTShare( dragItem, mHwndTarget);
295             debug_printf("OTransferable::requestRendering requested DRM_DTSHARE rendering rv=%d", rv);
296             renderDRM = DRM_DTSHARE;
297 
298             // notify rendering request ongoing
299             return true;
300 
301         } else if (DrgVerifyRMF( dragItem, "DRM_SHAREDMEM", NULL)) {
302 
303             bool rv;
304             debug_printf("OTransferable::requestRendering request DRM_SHAREDMEM rendering");
305             rv = RenderToSharedMem( dragItem, mHwndTarget);
306             debug_printf("OTransferable::requestRendering requested DRM_SHAREDMEM rendering rv=%d", rv);
307             renderDRM = DRM_SHAREDMEM;
308 
309             // notify rendering request ongoing
310             return true;
311 
312         } else {
313             debug_printf("OTransferable::requestRendering UNKNOWN request for TEXT mimetype");
314         }
315         break;
316     }
317 
318     // request rendering not necessary
319     return false;
320 
321 }
322 
323 //
324 // AOO window received DM_RENDERCOMPLETE message
325 //
renderComplete(PDRAGTRANSFER pdxfer)326 bool OTransferable::renderComplete( PDRAGTRANSFER pdxfer)
327 {
328     switch( renderDRM) {
329     case DRM_NULL:
330         // already handled in requestRendering()
331         break;
332     case DRM_ATOM:
333         // set full path from source rendered name string
334         DrgQueryStrName( pdxfer->hstrRenderToName, sizeof(fullpath), fullpath);
335         debug_printf("OTransferable::setDragTransfer fullpath %s", fullpath);
336         break;
337     case DRM_DTSHARE:
338         // handled in getTransferData()
339         break;
340     case DRM_SHAREDMEM:
341         // save pointer
342         pSharedMem = (char *) pdxfer->hstrRenderToName;
343         // extraction handled in getTransferData()
344         break;
345     case DRM_OS2FILE:
346         // we already know the path, no need to use hstrRenderToName
347         debug_printf("OTransferable::setDragTransfer fullpath %s", fullpath);
348         // remove tmp file on destruction
349         removeOnExit = true;
350         break;
351     }
352 
353     // send success to source window
354     DrgSendTransferMsg( pdxfer->hwndClient, DM_ENDCONVERSATION,
355                         (MPARAM) pdxfer->ulTargetInfo,
356                         (MPARAM) DMFL_TARGETSUCCESSFUL);
357 
358     // free resources
359     DrgDeleteStrHandle( pdxfer->hstrSelectedRMF);
360     DrgDeleteStrHandle( pdxfer->hstrRenderToName);
361     DrgFreeDragtransfer( pdxfer);
362 
363     return false;
364 }
365 
getTransferData(const DataFlavor & df)366 Any SAL_CALL OTransferable::getTransferData( const DataFlavor& df)
367 throw(UnsupportedFlavorException, IOException, RuntimeException)
368 {
369     OUString m_aData;
370     char * pszText = 0;
371     int pszLen;
372     ULONG size = ~0;
373     ULONG flags = 0;
374     APIRET rc;
375     bool renderOk = false;
376 
377     debug_printf("OTransferable::getTransferData MimeType %s",
378                  ::rtl::OUStringToOString( df.MimeType, RTL_TEXTENCODING_UTF8 ).getStr());
379 
380     // handle shared memory cases
381     switch( renderDRM) {
382     case DRM_DTSHARE:
383 
384         pszLen = ((ULONG*)pDTShare)[0];
385         pszText = (char*) malloc( pszLen + 1);
386         if (pszText) {
387             strcpy(pszText, &((char*)pDTShare)[sizeof(ULONG)] );
388         }
389         // using DosGetNamedSharedMem() on memory we allocated appears
390         // to increment its usage ctr, so we have to free it 2x
391         DosFreeMem(pDTShare);
392         DosFreeMem(pDTShare);
393         // reset pointer
394         pDTShare = NULL;
395 
396         // prepare data for AOO
397         m_aData = OUString( pszText, pszLen, RTL_TEXTENCODING_UTF8);
398         break;
399 
400     case DRM_SHAREDMEM:
401         rc = DosQueryMem((PVOID) pSharedMem, &size, &flags);
402         renderOk = rc == 0;
403         if (renderOk) {
404             renderOk = (flags & (PAG_COMMIT | PAG_READ | PAG_BASE)) ==
405                        (PAG_COMMIT | PAG_READ | PAG_BASE);
406         }
407         if (renderOk) {
408             ULONG realSize = *(ULONG *) pSharedMem;
409             renderOk = realSize <= size;
410             if (renderOk) {
411                 // prepare data for AOO
412                 m_aData = OUString( pSharedMem + sizeof(ULONG), realSize, RTL_TEXTENCODING_UTF8);
413             }
414         }
415         // free memory only if it is given by another process,
416         // otherwise DefaultDragWorker will free it
417         if (flags & PAG_SHARED)
418             DosFreeMem((PVOID) pSharedMem);
419         break;
420 
421     case DRM_ATOM:
422     case DRM_OS2FILE:
423         // data is in fullpath string
424         // prepare data for AOO
425         m_aData = OUString( fullpath, strlen(fullpath), RTL_TEXTENCODING_UTF8);
426         break;
427 
428     default:
429         debug_printf( "OTransferable::getTransferData unsupported DRM_* type %d",
430                       renderDRM);
431         break;
432     }
433 
434     // return data
435     return makeAny( m_aData );
436 }
437 
438 // -----------------------------------------------------------------------
439 
getTransferDataFlavors()440 Sequence< DataFlavor > SAL_CALL OTransferable::getTransferDataFlavors(  )
441 throw(RuntimeException)
442 {
443     return m_aFlavorList;
444 }
445 
446 // -----------------------------------------------------------------------
447 
isDataFlavorSupported(const DataFlavor &)448 sal_Bool SAL_CALL OTransferable::isDataFlavorSupported( const DataFlavor& )
449 throw(RuntimeException)
450 {
451     return sal_True;
452 }
453