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