Changeset 78307 in vbox for trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp
- Timestamp:
- Apr 26, 2019 6:41:46 AM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp
r76553 r78307 29 29 * Header Files * 30 30 *********************************************************************************************************************************/ 31 #include <VBox/GuestHost/SharedClipboard.h> 32 #ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST 33 # include <VBox/GuestHost/SharedClipboard-uri.h> 34 #endif 31 35 #include <VBox/HostServices/VBoxClipboardSvc.h> 32 36 #include <VBox/err.h> 33 37 #include <iprt/assert.h> 34 38 #include <iprt/string.h> 39 #include <iprt/cpp/ministring.h> 35 40 #include "VBoxGuestR3LibInternal.h" 41 42 43 /********************************************************************************************************************************* 44 * Prototypes * 45 *********************************************************************************************************************************/ 46 #ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST 47 static int vbglR3ClipboardSendErrorInternal(HGCMCLIENTID idClient, int rcErr); 48 static int vbglR3ClipboardSendURIData(HGCMCLIENTID idClient, const void *pvData, size_t cbData); 49 #endif 36 50 37 51 … … 140 154 141 155 /** 142 * Advertisesguest clipboard formats to the host.156 * Writes (advertises) guest clipboard formats to the host. 143 157 * 144 158 * @returns VBox status code. … … 146 160 * @param fFormats The formats to advertise. 147 161 */ 148 VBGLR3DECL(int) VbglR3Clipboard ReportFormats(HGCMCLIENTID idClient, uint32_t fFormats)149 { 150 VBoxClipboard Formats Msg;151 152 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_ FORMATS, 1);162 VBGLR3DECL(int) VbglR3ClipboardWriteFormats(HGCMCLIENTID idClient, uint32_t fFormats) 163 { 164 VBoxClipboardWriteFormats Msg; 165 166 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_FORMATS, 1); 153 167 VbglHGCMParmUInt32Set(&Msg.formats, fFormats); 154 168 … … 156 170 } 157 171 158 159 /** 160 * Send guest clipboard data to the host. 172 /** 173 * Sends guest clipboard data to the host. 161 174 * 162 175 * This is usually called in reply to a VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA message … … 169 182 * @param cb The size of the data. 170 183 */ 171 VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)184 static int vbglR3ClipboardWriteDataRaw(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb) 172 185 { 173 186 VBoxClipboardWriteData Msg; … … 179 192 } 180 193 194 /** 195 * Send guest clipboard data to the host. 196 * 197 * This is usually called in reply to a VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA message 198 * from the host. 199 * 200 * @returns VBox status code. 201 * @param idClient The client id returned by VbglR3ClipboardConnect(). 202 * @param fFormat The format of the data. 203 * @param pv The data. 204 * @param cb The size of the data. 205 */ 206 VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb) 207 { 208 int rc; 209 #ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST 210 if (fFormat == VBOX_SHARED_CLIPBOARD_FMT_URI_LIST) 211 { 212 rc = vbglR3ClipboardSendURIData(idClient, pv, cb); 213 } 214 else 215 #else 216 RT_NOREF(fFormat); 217 #endif 218 rc = vbglR3ClipboardWriteDataRaw(idClient, fFormat, pv, cb); 219 220 if (RT_FAILURE(rc)) 221 { 222 int rc2 = vbglR3ClipboardSendErrorInternal(idClient, rc); 223 if (RT_FAILURE(rc2)) 224 LogFlowFunc(("Unable to send error (%Rrc) to host, rc=%Rrc\n", rc, rc2)); 225 } 226 227 return rc; 228 } 229 230 #ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST 231 /** 232 * Guest -> Host 233 * Utility function to send clipboard data from guest to the host. 234 * 235 * @returns IPRT status code. 236 * @param idClient The client id returned by VbglR3ClipboardConnect(). 237 * @param pvData Data block to send. 238 * @param cbData Size (in bytes) of data block to send. 239 * @param pDataHdr Data header to use -- needed for accounting. 240 */ 241 static int vbglR3ClipboardSendDataInternal(HGCMCLIENTID idClient, 242 void *pvData, uint64_t cbData, PVBOXCLIPBOARDDATAHDR pDataHdr) 243 { 244 AssertPtrReturn(pvData, VERR_INVALID_POINTER); 245 AssertReturn(cbData, VERR_INVALID_PARAMETER); 246 AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER); 247 248 VBoxClipboardWriteDataHdrMsg MsgHdr; 249 RT_ZERO(MsgHdr); 250 251 VBGL_HGCM_HDR_INIT(&MsgHdr.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA_HDR, 12); 252 MsgHdr.uContext.SetUInt32(0); /** @todo Not used yet. */ 253 MsgHdr.uFlags.SetUInt32(0); /** @todo Not used yet. */ 254 MsgHdr.uScreenId.SetUInt32(0); /** @todo Not used for guest->host (yet). */ 255 MsgHdr.cbTotal.SetUInt64(pDataHdr->cbTotal); 256 MsgHdr.cbMeta.SetUInt32(pDataHdr->cbMeta); 257 MsgHdr.pvMetaFmt.SetPtr(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt); 258 MsgHdr.cbMetaFmt.SetUInt32(pDataHdr->cbMetaFmt); 259 MsgHdr.cObjects.SetUInt64(pDataHdr->cObjects); 260 MsgHdr.enmCompression.SetUInt32(0); /** @todo Not used yet. */ 261 MsgHdr.enmChecksumType.SetUInt32(RTDIGESTTYPE_INVALID); /** @todo Not used yet. */ 262 MsgHdr.pvChecksum.SetPtr(NULL, 0); /** @todo Not used yet. */ 263 MsgHdr.cbChecksum.SetUInt32(0); /** @todo Not used yet. */ 264 265 int rc = VbglR3HGCMCall(&MsgHdr.hdr, sizeof(MsgHdr)); 266 267 LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU32, cObjects=%RU64, rc=%Rrc\n", 268 pDataHdr->cbTotal, pDataHdr->cbMeta, pDataHdr->cObjects, rc)); 269 270 if (RT_SUCCESS(rc)) 271 { 272 VBoxClipboardWriteDataChunkMsg MsgData; 273 RT_ZERO(MsgData); 274 275 VBGL_HGCM_HDR_INIT(&MsgData.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA_CHUNK, 5); 276 MsgData.uContext.SetUInt32(0); /** @todo Not used yet. */ 277 MsgData.pvChecksum.SetPtr(NULL, 0); /** @todo Not used yet. */ 278 MsgData.cbChecksum.SetUInt32(0); /** @todo Not used yet. */ 279 280 uint32_t cbCurChunk; 281 const uint32_t cbMaxChunk = VBOX_SHARED_CLIPBOARD_MAX_CHUNK_SIZE; 282 uint32_t cbSent = 0; 283 284 HGCMFunctionParameter *pParm = &MsgData.pvData; 285 286 while (cbSent < cbData) 287 { 288 cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk); 289 pParm->SetPtr(static_cast<uint8_t *>(pvData) + cbSent, cbCurChunk); 290 291 MsgData.cbData.SetUInt32(cbCurChunk); 292 293 rc = VbglR3HGCMCall(&MsgData.hdr, sizeof(MsgData)); 294 if (RT_FAILURE(rc)) 295 break; 296 297 cbSent += cbCurChunk; 298 } 299 300 LogFlowFunc(("cbMaxChunk=%RU32, cbData=%RU64, cbSent=%RU32, rc=%Rrc\n", 301 cbMaxChunk, cbData, cbSent, rc)); 302 303 if (RT_SUCCESS(rc)) 304 Assert(cbSent == cbData); 305 } 306 307 LogFlowFuncLeaveRC(rc); 308 return rc; 309 } 310 311 /** 312 * Guest -> Host 313 * Utility function to send a guest directory to the host. 314 * 315 * @returns IPRT status code. 316 * @param idClient The client id returned by VbglR3ClipboardConnect(). 317 * @param pObj URI object containing the directory to send. 318 */ 319 static int vbglR3ClipboardSendDir(HGCMCLIENTID idClient, SharedClipboardURIObject *pObj) 320 { 321 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 322 AssertReturn(pObj->GetType() == SharedClipboardURIObject::Type_Directory, VERR_INVALID_PARAMETER); 323 324 RTCString strPath = pObj->GetDestPathAbs(); 325 LogFlowFunc(("strDir=%s (%zu), fMode=0x%x\n", 326 strPath.c_str(), strPath.length(), pObj->GetMode())); 327 328 if (strPath.length() > RTPATH_MAX) 329 return VERR_INVALID_PARAMETER; 330 331 const uint32_t cbPath = (uint32_t)strPath.length() + 1; /* Include termination. */ 332 333 VBoxClipboardWriteDirMsg Msg; 334 RT_ZERO(Msg); 335 336 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_DIR, 4); 337 /** @todo Context ID not used yet. */ 338 Msg.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)cbPath); 339 Msg.cbName.SetUInt32((uint32_t)cbPath); 340 Msg.fMode.SetUInt32(pObj->GetMode()); 341 342 return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); 343 } 344 345 /** 346 * Guest -> Host 347 * Utility function to send a file from the guest to the host. 348 * 349 * @returns IPRT status code. 350 * @param idClient The client id returned by VbglR3ClipboardConnect(). 351 * @param pObj URI object containing the file to send. 352 */ 353 static int vbglR3ClipboardSendFile(HGCMCLIENTID idClient, SharedClipboardURIObject *pObj) 354 { 355 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 356 AssertReturn(pObj->GetType() == SharedClipboardURIObject::Type_File, VERR_INVALID_PARAMETER); 357 AssertReturn(pObj->IsOpen(), VERR_INVALID_STATE); 358 359 uint32_t cbBuf = _64K; /** @todo Make this configurable? */ 360 void *pvBuf = RTMemAlloc(cbBuf); 361 if (!pvBuf) 362 return VERR_NO_MEMORY; 363 364 RTCString strPath = pObj->GetDestPathAbs(); 365 366 LogFlowFunc(("strFile=%s (%zu), cbSize=%RU64, fMode=0x%x\n", strPath.c_str(), strPath.length(), 367 pObj->GetSize(), pObj->GetMode())); 368 369 VBoxClipboardWriteFileHdrMsg MsgHdr; 370 RT_ZERO(MsgHdr); 371 372 VBGL_HGCM_HDR_INIT(&MsgHdr.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_FILE_HDR, 6); 373 MsgHdr.uContext.SetUInt32(0); /* Context ID; unused at the moment. */ 374 MsgHdr.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1)); 375 MsgHdr.cbName.SetUInt32((uint32_t)(strPath.length() + 1)); 376 MsgHdr.uFlags.SetUInt32(0); /* Flags; unused at the moment. */ 377 MsgHdr.fMode.SetUInt32(pObj->GetMode()); /* File mode */ 378 MsgHdr.cbTotal.SetUInt64(pObj->GetSize()); /* File size (in bytes). */ 379 380 int rc = VbglR3HGCMCall(&MsgHdr.hdr, sizeof(MsgHdr)); 381 382 LogFlowFunc(("Sending file header resulted in %Rrc\n", rc)); 383 384 if (RT_SUCCESS(rc)) 385 { 386 /* 387 * Send the actual file data, chunk by chunk. 388 */ 389 VBoxClipboardWriteFileDataMsg Msg; 390 RT_ZERO(Msg); 391 392 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_FILE_DATA, 5); 393 Msg.uContext.SetUInt32(0); 394 Msg.pvChecksum.SetPtr(NULL, 0); 395 Msg.cbChecksum.SetUInt32(0); 396 397 uint64_t cbToReadTotal = pObj->GetSize(); 398 uint64_t cbWrittenTotal = 0; 399 while (cbToReadTotal) 400 { 401 uint32_t cbToRead = RT_MIN(cbToReadTotal, cbBuf); 402 uint32_t cbRead = 0; 403 if (cbToRead) 404 rc = pObj->Read(pvBuf, cbToRead, &cbRead); 405 406 LogFlowFunc(("cbToReadTotal=%RU64, cbToRead=%RU32, cbRead=%RU32, rc=%Rrc\n", 407 cbToReadTotal, cbToRead, cbRead, rc)); 408 409 if ( RT_SUCCESS(rc) 410 && cbRead) 411 { 412 Msg.pvData.SetPtr(pvBuf, cbRead); 413 Msg.cbData.SetUInt32(cbRead); 414 /** @todo Calculate + set checksums. */ 415 416 rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); 417 } 418 419 if (RT_FAILURE(rc)) 420 { 421 LogFlowFunc(("Reading failed with rc=%Rrc\n", rc)); 422 break; 423 } 424 425 Assert(cbRead <= cbToReadTotal); 426 cbToReadTotal -= cbRead; 427 cbWrittenTotal += cbRead; 428 429 LogFlowFunc(("%RU64/%RU64 -- %RU8%%\n", cbWrittenTotal, pObj->GetSize(), cbWrittenTotal * 100 / pObj->GetSize())); 430 }; 431 } 432 433 RTMemFree(pvBuf); 434 435 LogFlowFuncLeaveRC(rc); 436 return rc; 437 } 438 439 /** 440 * Guest -> Host 441 * Utility function to send an URI object from guest to the host. 442 * 443 * @returns IPRT status code. 444 * @param idClient The client id returned by VbglR3ClipboardConnect(). 445 * @param pObj URI object to send from guest to the host. 446 */ 447 static int vbglR3ClipboardSendURIObject(HGCMCLIENTID idClient, SharedClipboardURIObject *pObj) 448 { 449 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 450 451 int rc; 452 453 switch (pObj->GetType()) 454 { 455 case SharedClipboardURIObject::Type_Directory: 456 rc = vbglR3ClipboardSendDir(idClient, pObj); 457 break; 458 459 case SharedClipboardURIObject::Type_File: 460 rc = vbglR3ClipboardSendFile(idClient, pObj); 461 break; 462 463 default: 464 AssertMsgFailed(("Object type %ld not implemented\n", pObj->GetType())); 465 rc = VERR_NOT_IMPLEMENTED; 466 break; 467 } 468 469 return rc; 470 } 471 472 /** 473 * Guest -> Host 474 * Utility function to send URI data from guest to the host. 475 * 476 * @returns IPRT status code. 477 * @param idClient The client id returned by VbglR3ClipboardConnect(). 478 * @param pvData Block to URI data to send. 479 * @param cbData Size (in bytes) of URI data to send. 480 */ 481 static int vbglR3ClipboardSendURIData(HGCMCLIENTID idClient, const void *pvData, size_t cbData) 482 { 483 AssertPtrReturn(pvData, VERR_INVALID_POINTER); 484 AssertReturn(cbData, VERR_INVALID_PARAMETER); 485 486 RTCList<RTCString> lstPaths = 487 RTCString((const char *)pvData, cbData).split("\r\n"); 488 489 /** @todo Add symlink support (SHAREDCLIPBOARDURILIST_FLAGS_RESOLVE_SYMLINKS) here. */ 490 /** @todo Add lazy loading (SHAREDCLIPBOARDURILIST_FLAGS_LAZY) here. */ 491 uint32_t fFlags = SHAREDCLIPBOARDURILIST_FLAGS_KEEP_OPEN; 492 493 SharedClipboardURIList lstURI; 494 int rc = lstURI.AppendURIPathsFromList(lstPaths, fFlags); 495 if (RT_SUCCESS(rc)) 496 { 497 /* 498 * Send the (meta) data; in case of URIs it's the (non-recursive) file/directory 499 * URI list the host needs to know upfront to set up the drag'n drop operation. 500 */ 501 RTCString strRootDest = lstURI.GetRootEntries(); 502 if (strRootDest.isNotEmpty()) 503 { 504 void *pvURIList = (void *)strRootDest.c_str(); /* URI root list. */ 505 uint32_t cbURLIist = (uint32_t)strRootDest.length() + 1; /* Include string termination. */ 506 507 /* The total size also contains the size of the meta data. */ 508 uint64_t cbTotal = cbURLIist; 509 cbTotal += lstURI.GetTotalBytes(); 510 511 /* We're going to send an URI list in text format. */ 512 const char szMetaFmt[] = "text/uri-list"; 513 const uint32_t cbMetaFmt = (uint32_t)strlen(szMetaFmt) + 1; /* Include termination. */ 514 515 VBOXCLIPBOARDDATAHDR dataHdr; 516 dataHdr.uFlags = 0; /* Flags not used yet. */ 517 dataHdr.cbTotal = cbTotal; 518 dataHdr.cbMeta = cbURLIist; 519 dataHdr.pvMetaFmt = (void *)szMetaFmt; 520 dataHdr.cbMetaFmt = cbMetaFmt; 521 dataHdr.cObjects = lstURI.GetTotalCount(); 522 523 rc = vbglR3ClipboardSendDataInternal(idClient, 524 pvURIList, cbURLIist, &dataHdr); 525 } 526 else 527 rc = VERR_INVALID_PARAMETER; 528 } 529 530 if (RT_SUCCESS(rc)) 531 { 532 while (!lstURI.IsEmpty()) 533 { 534 SharedClipboardURIObject *pNextObj = lstURI.First(); 535 536 rc = vbglR3ClipboardSendURIObject(idClient, pNextObj); 537 if (RT_FAILURE(rc)) 538 break; 539 540 lstURI.RemoveFirst(); 541 } 542 } 543 544 return rc; 545 } 546 547 /** 548 * Guest -> Host 549 * Sends an error back to the host. 550 * 551 * @returns IPRT status code. 552 * @param idClient The client id returned by VbglR3ClipboardConnect(). 553 * @param rcErr Error (IPRT-style) to send. 554 */ 555 static int vbglR3ClipboardSendErrorInternal(HGCMCLIENTID idClient, int rcErr) 556 { 557 VBoxClipboardWriteErrorMsg Msg; 558 RT_ZERO(Msg); 559 560 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_ERROR, 2); 561 /** @todo Context ID not used yet. */ 562 Msg.uContext.SetUInt32(0); 563 Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */ 564 565 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); 566 567 /* 568 * Never return an error if the host did not accept the error at the current 569 * time. This can be due to the host not having any appropriate callbacks 570 * set which would handle that error. 571 * 572 * bird: Looks like VERR_NOT_SUPPORTED is what the host will return if it 573 * doesn't an appropriate callback. The code used to ignore ALL errors 574 * the host would return, also relevant ones. 575 */ 576 if (RT_FAILURE(rc)) 577 LogFlowFunc(("Sending error %Rrc failed with rc=%Rrc\n", rcErr, rc)); 578 if (rc == VERR_NOT_SUPPORTED) 579 rc = VINF_SUCCESS; 580 581 return rc; 582 } 583 584 /** 585 * Guest -> Host 586 * Send an error back to the host. 587 * 588 * @returns IPRT status code. 589 * @param idClient The client id returned by VbglR3ClipboardConnect(). 590 * @param rcErr Error (IPRT-style) to send. 591 */ 592 VBGLR3DECL(int) VbglR3ClipboardSendError(HGCMCLIENTID idClient, int rcErr) 593 { 594 return vbglR3ClipboardSendErrorInternal(idClient, rcErr); 595 } 596 #endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */ 597
Note:
See TracChangeset
for help on using the changeset viewer.