VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp@ 42507

Last change on this file since 42507 was 42507, checked in by vboxsync, 13 years ago

Guest Control 2.0: Update.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.7 KB
Line 
1/* $Id: GuestCtrlPrivate.cpp 42507 2012-08-01 12:40:05Z vboxsync $ */
2/** @file
3 *
4 * Internal helpers/structures for guest control functionality.
5 */
6
7/*
8 * Copyright (C) 2011-2012 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19/******************************************************************************
20 * Header Files *
21 ******************************************************************************/
22#include "GuestCtrlImplPrivate.h"
23
24#include <iprt/asm.h>
25#include <iprt/ctype.h>
26#ifdef DEBUG
27# include <iprt/file.h>
28#endif /* DEBUG */
29
30/******************************************************************************
31 * Structures and Typedefs *
32 ******************************************************************************/
33
34GuestCtrlEvent::GuestCtrlEvent(void)
35 : fCanceled(false),
36 fCompleted(false),
37 hEventSem(NIL_RTSEMEVENT),
38 mRC(VINF_SUCCESS)
39{
40}
41
42GuestCtrlEvent::~GuestCtrlEvent(void)
43{
44 Destroy();
45}
46
47int GuestCtrlEvent::Cancel(void)
48{
49 LogFlowThisFuncEnter();
50
51 int rc = VINF_SUCCESS;
52 if (!ASMAtomicReadBool(&fCompleted))
53 {
54 if (!ASMAtomicReadBool(&fCanceled))
55 {
56 ASMAtomicXchgBool(&fCanceled, true);
57
58 LogFlowThisFunc(("Cancelling ...\n"));
59 rc = hEventSem != NIL_RTSEMEVENT
60 ? RTSemEventSignal(hEventSem) : VINF_SUCCESS;
61 }
62 }
63
64 LogFlowFuncLeaveRC(rc);
65 return rc;
66}
67
68bool GuestCtrlEvent::Canceled(void)
69{
70 return ASMAtomicReadBool(&fCanceled);
71}
72
73void GuestCtrlEvent::Destroy(void)
74{
75 int rc = Cancel();
76 AssertRC(rc);
77
78 if (hEventSem != NIL_RTSEMEVENT)
79 {
80 RTSemEventDestroy(hEventSem);
81 hEventSem = NIL_RTSEMEVENT;
82 }
83}
84
85int GuestCtrlEvent::Init(void)
86{
87 return RTSemEventCreate(&hEventSem);
88}
89
90int GuestCtrlEvent::Signal(int rc /*= VINF_SUCCESS*/)
91{
92 AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
93
94 mRC = rc;
95
96 return RTSemEventSignal(hEventSem);
97}
98
99int GuestCtrlEvent::Wait(ULONG uTimeoutMS)
100{
101 LogFlowFuncEnter();
102
103 AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
104
105 RTMSINTERVAL msInterval = uTimeoutMS;
106 if (!uTimeoutMS)
107 msInterval = RT_INDEFINITE_WAIT;
108 int rc = RTSemEventWait(hEventSem, msInterval);
109 if (RT_SUCCESS(rc))
110 ASMAtomicWriteBool(&fCompleted, true);
111
112 LogFlowFuncLeaveRC(rc);
113 return rc;
114}
115
116///////////////////////////////////////////////////////////////////////////////
117
118GuestCtrlCallback::GuestCtrlCallback(void)
119 : pvData(NULL),
120 cbData(0),
121 mType(VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN),
122 uFlags(0),
123 pvPayload(NULL),
124 cbPayload(0)
125{
126}
127
128GuestCtrlCallback::GuestCtrlCallback(eVBoxGuestCtrlCallbackType enmType)
129 : pvData(NULL),
130 cbData(0),
131 mType(VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN),
132 uFlags(0),
133 pvPayload(NULL),
134 cbPayload(0)
135{
136 int rc = Init(enmType);
137 AssertRC(rc);
138}
139
140GuestCtrlCallback::~GuestCtrlCallback(void)
141{
142 Destroy();
143}
144
145int GuestCtrlCallback::Init(eVBoxGuestCtrlCallbackType enmType)
146{
147 LogFlowFuncEnter();
148
149 AssertReturn(enmType > VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN, VERR_INVALID_PARAMETER);
150 Assert((pvData == NULL) && !cbData);
151
152 switch (enmType)
153 {
154 case VBOXGUESTCTRLCALLBACKTYPE_EXEC_START:
155 {
156 pvData = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS));
157 AssertPtrReturn(pvData, VERR_NO_MEMORY);
158 RT_BZERO(pvData, sizeof(CALLBACKDATAEXECSTATUS));
159 cbData = sizeof(CALLBACKDATAEXECSTATUS);
160 break;
161 }
162
163 case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT:
164 {
165 pvData = (PCALLBACKDATAEXECOUT)RTMemAlloc(sizeof(CALLBACKDATAEXECOUT));
166 AssertPtrReturn(pvData, VERR_NO_MEMORY);
167 RT_BZERO(pvData, sizeof(CALLBACKDATAEXECOUT));
168 cbData = sizeof(CALLBACKDATAEXECOUT);
169 break;
170 }
171
172 case VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS:
173 {
174 PCALLBACKDATAEXECINSTATUS pData = (PCALLBACKDATAEXECINSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECINSTATUS));
175 AssertPtrReturn(pData, VERR_NO_MEMORY);
176 RT_BZERO(pData, sizeof(CALLBACKDATAEXECINSTATUS));
177 cbData = sizeof(CALLBACKDATAEXECINSTATUS);
178 break;
179 }
180
181 default:
182 AssertMsgFailed(("Unknown callback type specified (%d)\n", enmType));
183 break;
184 }
185
186 int rc = GuestCtrlEvent::Init();
187 if (RT_SUCCESS(rc))
188 mType = enmType;
189
190 LogFlowFuncLeaveRC(rc);
191 return rc;
192}
193
194void GuestCtrlCallback::Destroy(void)
195{
196 GuestCtrlEvent::Destroy();
197
198 switch (mType)
199 {
200 case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT:
201 {
202 PCALLBACKDATAEXECOUT pThis = (PCALLBACKDATAEXECOUT)pvData;
203 AssertPtr(pThis);
204 if (pThis->pvData)
205 RTMemFree(pThis->pvData);
206 }
207
208 default:
209 break;
210 }
211
212 mType = VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN;
213 if (pvData)
214 {
215 RTMemFree(pvData);
216 pvData = NULL;
217 }
218 cbData = 0;
219
220 if (pvPayload)
221 {
222 RTMemFree(pvPayload);
223 pvPayload = NULL;
224 }
225 cbPayload = 0;
226}
227
228int GuestCtrlCallback::SetData(const void *pvCallback, size_t cbCallback)
229{
230 if (!cbCallback)
231 return VINF_SUCCESS;
232 AssertPtr(pvCallback);
233
234 switch (mType)
235 {
236 case VBOXGUESTCTRLCALLBACKTYPE_EXEC_START:
237 {
238 PCALLBACKDATAEXECSTATUS pThis = (PCALLBACKDATAEXECSTATUS)pvData;
239 PCALLBACKDATAEXECSTATUS pCB = (PCALLBACKDATAEXECSTATUS)pvCallback;
240 Assert(cbCallback == sizeof(CALLBACKDATAEXECSTATUS));
241
242 pThis->u32Flags = pCB->u32Flags;
243 pThis->u32PID = pCB->u32PID;
244 pThis->u32Status = pCB->u32Status;
245 break;
246 }
247
248 case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT:
249 {
250 PCALLBACKDATAEXECOUT pThis = (PCALLBACKDATAEXECOUT)pvData;
251 PCALLBACKDATAEXECOUT pCB = (PCALLBACKDATAEXECOUT)pvCallback;
252 Assert(cbCallback == sizeof(CALLBACKDATAEXECOUT));
253
254 pThis->cbData = pCB->cbData;
255 if (pThis->cbData)
256 {
257 pThis->pvData = RTMemAlloc(pCB->cbData);
258 AssertPtrReturn(pThis->pvData, VERR_NO_MEMORY);
259 memcpy(pThis->pvData, pCB->pvData, pCB->cbData);
260 }
261 pThis->u32Flags = pCB->u32Flags;
262 pThis->u32PID = pCB->u32PID;
263 break;
264 }
265
266 case VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS:
267 {
268 PCALLBACKDATAEXECINSTATUS pThis = (PCALLBACKDATAEXECINSTATUS)pvData;
269 PCALLBACKDATAEXECINSTATUS pCB = (PCALLBACKDATAEXECINSTATUS)pvCallback;
270 Assert(cbCallback == sizeof(CALLBACKDATAEXECINSTATUS));
271
272 pThis->cbProcessed = pCB->cbProcessed;
273 pThis->u32Flags = pCB->u32Flags;
274 pThis->u32PID = pCB->u32PID;
275 pThis->u32Status = pCB->u32Status;
276 }
277
278 default:
279 AssertMsgFailed(("Callback type not handled (%d)\n", mType));
280 break;
281 }
282
283 return VINF_SUCCESS;
284}
285
286int GuestCtrlCallback::SetPayload(const void *pvToWrite, size_t cbToWrite)
287{
288 if (!cbToWrite)
289 return VINF_SUCCESS;
290 AssertPtr(pvToWrite);
291
292 Assert(pvPayload == NULL); /* Can't reuse callbacks! */
293 pvPayload = RTMemAlloc(cbToWrite);
294 if (!pvPayload)
295 return VERR_NO_MEMORY;
296
297 memcpy(pvPayload, pvToWrite, cbToWrite);
298 cbPayload = cbToWrite;
299
300 return VINF_SUCCESS;
301}
302
303///////////////////////////////////////////////////////////////////////////////
304
305GuestProcessEvent::GuestProcessEvent(void)
306 : mWaitFlags(0)
307{
308}
309
310GuestProcessEvent::GuestProcessEvent(uint32_t uWaitFlags)
311 : mWaitFlags(uWaitFlags)
312{
313 int rc = GuestCtrlEvent::Init();
314 AssertRC(rc);
315}
316
317GuestProcessEvent::~GuestProcessEvent(void)
318{
319 Destroy();
320}
321
322void GuestProcessEvent::Destroy(void)
323{
324 GuestCtrlEvent::Destroy();
325
326 mWaitFlags = ProcessWaitForFlag_None;
327}
328
329int GuestProcessEvent::Signal(ProcessWaitResult_T enmResult, int rc /*= VINF_SUCCESS*/)
330{
331 mWaitResult.mRC = rc;
332 mWaitResult.mResult = enmResult;
333
334 return GuestCtrlEvent::Signal(rc);
335}
336
337///////////////////////////////////////////////////////////////////////////////
338
339int GuestEnvironment::BuildEnvironmentBlock(void **ppvEnv, size_t *pcbEnv, uint32_t *pcEnvVars)
340{
341 AssertPtrReturn(ppvEnv, VERR_INVALID_POINTER);
342 /* Rest is optional. */
343
344 size_t cbEnv = 0;
345 uint32_t cEnvVars = 0;
346
347 int rc = VINF_SUCCESS;
348
349 size_t cEnv = mEnvironment.size();
350 if (cEnv)
351 {
352 std::map<Utf8Str, Utf8Str>::const_iterator itEnv = mEnvironment.begin();
353 for (; itEnv != mEnvironment.end() && RT_SUCCESS(rc); itEnv++)
354 {
355 char *pszEnv;
356 if (!RTStrAPrintf(&pszEnv, "%s=%s", itEnv->first.c_str(), itEnv->second.c_str()))
357 {
358 rc = VERR_NO_MEMORY;
359 break;
360 }
361 AssertPtr(pszEnv);
362 rc = appendToEnvBlock(pszEnv, ppvEnv, &cbEnv, &cEnvVars);
363 RTStrFree(pszEnv);
364 }
365 Assert(cEnv == cEnvVars);
366 }
367
368 if (pcbEnv)
369 *pcbEnv = cbEnv;
370 if (pcEnvVars)
371 *pcEnvVars = cEnvVars;
372
373 return rc;
374}
375
376void GuestEnvironment::Clear(void)
377{
378 mEnvironment.clear();
379}
380
381int GuestEnvironment::CopyFrom(const GuestEnvironmentArray &environment)
382{
383 int rc = VINF_SUCCESS;
384
385 for (GuestEnvironmentArray::const_iterator it = environment.begin();
386 it != environment.end() && RT_SUCCESS(rc);
387 ++it)
388 {
389 rc = Set((*it));
390 }
391
392 return rc;
393}
394
395int GuestEnvironment::CopyTo(GuestEnvironmentArray &environment)
396{
397 size_t s = 0;
398 for (std::map<Utf8Str, Utf8Str>::const_iterator it = mEnvironment.begin();
399 it != mEnvironment.end();
400 ++it, ++s)
401 {
402 environment[s] = Bstr(it->first + "=" + it->second).raw();
403 }
404
405 return VINF_SUCCESS;
406}
407
408/* static */
409void GuestEnvironment::FreeEnvironmentBlock(void *pvEnv)
410{
411 if (pvEnv)
412 RTMemFree(pvEnv);
413}
414
415Utf8Str GuestEnvironment::Get(size_t nPos)
416{
417 size_t curPos = 0;
418 std::map<Utf8Str, Utf8Str>::const_iterator it = mEnvironment.begin();
419 for (; it != mEnvironment.end() && curPos < nPos;
420 ++it, ++curPos) { }
421
422 if (it != mEnvironment.end())
423 return Utf8Str(it->first + "=" + it->second);
424
425 return Utf8Str("");
426}
427
428Utf8Str GuestEnvironment::Get(const Utf8Str &strKey)
429{
430 std::map <Utf8Str, Utf8Str>::const_iterator itEnv = mEnvironment.find(strKey);
431 Utf8Str strRet;
432 if (itEnv != mEnvironment.end())
433 strRet = itEnv->second;
434 return strRet;
435}
436
437bool GuestEnvironment::Has(const Utf8Str &strKey)
438{
439 std::map <Utf8Str, Utf8Str>::const_iterator itEnv = mEnvironment.find(strKey);
440 return (itEnv != mEnvironment.end());
441}
442
443int GuestEnvironment::Set(const Utf8Str &strKey, const Utf8Str &strValue)
444{
445 /** @todo Do some validation using regex. */
446 if (strKey.isEmpty())
447 return VERR_INVALID_PARAMETER;
448
449 int rc = VINF_SUCCESS;
450 const char *pszString = strKey.c_str();
451 while (*pszString != '\0' && RT_SUCCESS(rc))
452 {
453 if ( !RT_C_IS_ALNUM(*pszString)
454 && !RT_C_IS_GRAPH(*pszString))
455 rc = VERR_INVALID_PARAMETER;
456 *pszString++;
457 }
458
459 if (RT_SUCCESS(rc))
460 mEnvironment[strKey] = strValue;
461
462 return rc;
463}
464
465int GuestEnvironment::Set(const Utf8Str &strPair)
466{
467 RTCList<RTCString> listPair = strPair.split("=", RTCString::KeepEmptyParts);
468 /* Skip completely empty pairs. Note that we still need pairs with a valid
469 * (set) key and an empty value. */
470 if (listPair.size() <= 1)
471 return VINF_SUCCESS;
472
473 int rc = VINF_SUCCESS;
474 size_t p = 0;
475 while(p < listPair.size() && RT_SUCCESS(rc))
476 {
477 Utf8Str strKey = listPair.at(p++);
478 if ( strKey.isEmpty()
479 || strKey.equals("=")) /* Skip pairs with empty keys (e.g. "=FOO"). */
480 {
481 break;
482 }
483 Utf8Str strValue;
484 if (p < listPair.size()) /* Does the list also contain a value? */
485 strValue = listPair.at(p++);
486
487#ifdef DEBUG
488 LogFlowFunc(("strKey=%s, strValue=%s\n",
489 strKey.c_str(), strValue.c_str()));
490#endif
491 rc = Set(strKey, strValue);
492 }
493
494 return rc;
495}
496
497size_t GuestEnvironment::Size(void)
498{
499 return mEnvironment.size();
500}
501
502int GuestEnvironment::Unset(const Utf8Str &strKey)
503{
504 std::map <Utf8Str, Utf8Str>::iterator itEnv = mEnvironment.find(strKey);
505 if (itEnv != mEnvironment.end())
506 {
507 mEnvironment.erase(itEnv);
508 return VINF_SUCCESS;
509 }
510
511 return VERR_NOT_FOUND;
512}
513
514GuestEnvironment& GuestEnvironment::operator=(const GuestEnvironmentArray &that)
515{
516 CopyFrom(that);
517 return *this;
518}
519
520GuestEnvironment& GuestEnvironment::operator=(const GuestEnvironment &that)
521{
522 for (std::map<Utf8Str, Utf8Str>::const_iterator it = that.mEnvironment.begin();
523 it != that.mEnvironment.end();
524 ++it)
525 {
526 mEnvironment[it->first] = it->second;
527 }
528
529 return *this;
530}
531
532/**
533 * Appends environment variables to the environment block.
534 *
535 * Each var=value pair is separated by the null character ('\\0'). The whole
536 * block will be stored in one blob and disassembled on the guest side later to
537 * fit into the HGCM param structure.
538 *
539 * @returns VBox status code.
540 *
541 * @param pszEnvVar The environment variable=value to append to the
542 * environment block.
543 * @param ppvList This is actually a pointer to a char pointer
544 * variable which keeps track of the environment block
545 * that we're constructing.
546 * @param pcbList Pointer to the variable holding the current size of
547 * the environment block. (List is a misnomer, go
548 * ahead a be confused.)
549 * @param pcEnvVars Pointer to the variable holding count of variables
550 * stored in the environment block.
551 */
552int GuestEnvironment::appendToEnvBlock(const char *pszEnv, void **ppvList, size_t *pcbList, uint32_t *pcEnvVars)
553{
554 int rc = VINF_SUCCESS;
555 size_t cchEnv = strlen(pszEnv); Assert(cchEnv >= 2);
556 if (*ppvList)
557 {
558 size_t cbNewLen = *pcbList + cchEnv + 1; /* Include zero termination. */
559 char *pvTmp = (char *)RTMemRealloc(*ppvList, cbNewLen);
560 if (pvTmp == NULL)
561 rc = VERR_NO_MEMORY;
562 else
563 {
564 memcpy(pvTmp + *pcbList, pszEnv, cchEnv);
565 pvTmp[cbNewLen - 1] = '\0'; /* Add zero termination. */
566 *ppvList = (void **)pvTmp;
567 }
568 }
569 else
570 {
571 char *pszTmp;
572 if (RTStrAPrintf(&pszTmp, "%s", pszEnv) >= 0)
573 {
574 *ppvList = (void **)pszTmp;
575 /* Reset counters. */
576 *pcEnvVars = 0;
577 *pcbList = 0;
578 }
579 }
580 if (RT_SUCCESS(rc))
581 {
582 *pcbList += cchEnv + 1; /* Include zero termination. */
583 *pcEnvVars += 1; /* Increase env variable count. */
584 }
585 return rc;
586}
587
588///////////////////////////////////////////////////////////////////////////////
589
590/** @todo *NOT* thread safe yet! */
591/** @todo Add exception handling for STL stuff! */
592
593GuestProcessStreamBlock::GuestProcessStreamBlock(void)
594{
595
596}
597
598/*
599GuestProcessStreamBlock::GuestProcessStreamBlock(const GuestProcessStreamBlock &otherBlock)
600{
601 for (GuestCtrlStreamPairsIter it = otherBlock.m_mapPairs.begin();
602 it != otherBlock.end(); it++)
603 {
604 m_mapPairs[it->first] = new
605 if (it->second.pszValue)
606 {
607 RTMemFree(it->second.pszValue);
608 it->second.pszValue = NULL;
609 }
610 }
611}*/
612
613GuestProcessStreamBlock::~GuestProcessStreamBlock()
614{
615 Clear();
616}
617
618/**
619 * Destroys the currently stored stream pairs.
620 *
621 * @return IPRT status code.
622 */
623void GuestProcessStreamBlock::Clear()
624{
625 m_mapPairs.clear();
626}
627
628#ifdef DEBUG
629void GuestProcessStreamBlock::Dump()
630{
631 LogFlowFunc(("Dumping contents of stream block=0x%p (%ld items):\n",
632 this, m_mapPairs.size()));
633
634 for (GuestCtrlStreamPairMapIterConst it = m_mapPairs.begin();
635 it != m_mapPairs.end(); it++)
636 {
637 LogFlowFunc(("\t%s=%s\n", it->first.c_str(), it->second.mValue.c_str()));
638 }
639}
640#endif
641
642/**
643 * Returns a 64-bit signed integer of a specified key.
644 *
645 * @return IPRT status code. VERR_NOT_FOUND if key was not found.
646 * @param pszKey Name of key to get the value for.
647 * @param piVal Pointer to value to return.
648 */
649int GuestProcessStreamBlock::GetInt64Ex(const char *pszKey, int64_t *piVal)
650{
651 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
652 AssertPtrReturn(piVal, VERR_INVALID_POINTER);
653 const char *pszValue = GetString(pszKey);
654 if (pszValue)
655 {
656 *piVal = RTStrToInt64(pszValue);
657 return VINF_SUCCESS;
658 }
659 return VERR_NOT_FOUND;
660}
661
662/**
663 * Returns a 64-bit integer of a specified key.
664 *
665 * @return int64_t Value to return, 0 if not found / on failure.
666 * @param pszKey Name of key to get the value for.
667 */
668int64_t GuestProcessStreamBlock::GetInt64(const char *pszKey)
669{
670 int64_t iVal;
671 if (RT_SUCCESS(GetInt64Ex(pszKey, &iVal)))
672 return iVal;
673 return 0;
674}
675
676/**
677 * Returns the current number of stream pairs.
678 *
679 * @return uint32_t Current number of stream pairs.
680 */
681size_t GuestProcessStreamBlock::GetCount()
682{
683 return m_mapPairs.size();
684}
685
686/**
687 * Returns a string value of a specified key.
688 *
689 * @return uint32_t Pointer to string to return, NULL if not found / on failure.
690 * @param pszKey Name of key to get the value for.
691 */
692const char* GuestProcessStreamBlock::GetString(const char *pszKey)
693{
694 AssertPtrReturn(pszKey, NULL);
695
696 try
697 {
698 GuestCtrlStreamPairMapIterConst itPairs = m_mapPairs.find(Utf8Str(pszKey));
699 if (itPairs != m_mapPairs.end())
700 return itPairs->second.mValue.c_str();
701 }
702 catch (const std::exception &ex)
703 {
704 NOREF(ex);
705 }
706 return NULL;
707}
708
709/**
710 * Returns a 32-bit unsigned integer of a specified key.
711 *
712 * @return IPRT status code. VERR_NOT_FOUND if key was not found.
713 * @param pszKey Name of key to get the value for.
714 * @param puVal Pointer to value to return.
715 */
716int GuestProcessStreamBlock::GetUInt32Ex(const char *pszKey, uint32_t *puVal)
717{
718 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
719 AssertPtrReturn(puVal, VERR_INVALID_POINTER);
720 const char *pszValue = GetString(pszKey);
721 if (pszValue)
722 {
723 *puVal = RTStrToUInt32(pszValue);
724 return VINF_SUCCESS;
725 }
726 return VERR_NOT_FOUND;
727}
728
729/**
730 * Returns a 32-bit unsigned integer of a specified key.
731 *
732 * @return uint32_t Value to return, 0 if not found / on failure.
733 * @param pszKey Name of key to get the value for.
734 */
735uint32_t GuestProcessStreamBlock::GetUInt32(const char *pszKey)
736{
737 uint32_t uVal;
738 if (RT_SUCCESS(GetUInt32Ex(pszKey, &uVal)))
739 return uVal;
740 return 0;
741}
742
743/**
744 * Sets a value to a key or deletes a key by setting a NULL value.
745 *
746 * @return IPRT status code.
747 * @param pszKey Key name to process.
748 * @param pszValue Value to set. Set NULL for deleting the key.
749 */
750int GuestProcessStreamBlock::SetValue(const char *pszKey, const char *pszValue)
751{
752 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
753
754 int rc = VINF_SUCCESS;
755 try
756 {
757 Utf8Str Utf8Key(pszKey);
758
759 /* Take a shortcut and prevent crashes on some funny versions
760 * of STL if map is empty initially. */
761 if (!m_mapPairs.empty())
762 {
763 GuestCtrlStreamPairMapIter it = m_mapPairs.find(Utf8Key);
764 if (it != m_mapPairs.end())
765 m_mapPairs.erase(it);
766 }
767
768 if (pszValue)
769 {
770 GuestProcessStreamValue val(pszValue);
771 m_mapPairs[Utf8Key] = val;
772 }
773 }
774 catch (const std::exception &ex)
775 {
776 NOREF(ex);
777 }
778 return rc;
779}
780
781///////////////////////////////////////////////////////////////////////////////
782
783GuestProcessStream::GuestProcessStream(void)
784 : m_cbAllocated(0),
785 m_cbSize(0),
786 m_cbOffset(0),
787 m_pbBuffer(NULL)
788{
789
790}
791
792GuestProcessStream::~GuestProcessStream(void)
793{
794 Destroy();
795}
796
797/**
798 * Adds data to the internal parser buffer. Useful if there
799 * are multiple rounds of adding data needed.
800 *
801 * @return IPRT status code.
802 * @param pbData Pointer to data to add.
803 * @param cbData Size (in bytes) of data to add.
804 */
805int GuestProcessStream::AddData(const BYTE *pbData, size_t cbData)
806{
807 AssertPtrReturn(pbData, VERR_INVALID_POINTER);
808 AssertReturn(cbData, VERR_INVALID_PARAMETER);
809
810 int rc = VINF_SUCCESS;
811
812 /* Rewind the buffer if it's empty. */
813 size_t cbInBuf = m_cbSize - m_cbOffset;
814 bool const fAddToSet = cbInBuf == 0;
815 if (fAddToSet)
816 m_cbSize = m_cbOffset = 0;
817
818 /* Try and see if we can simply append the data. */
819 if (cbData + m_cbSize <= m_cbAllocated)
820 {
821 memcpy(&m_pbBuffer[m_cbSize], pbData, cbData);
822 m_cbSize += cbData;
823 }
824 else
825 {
826 /* Move any buffered data to the front. */
827 cbInBuf = m_cbSize - m_cbOffset;
828 if (cbInBuf == 0)
829 m_cbSize = m_cbOffset = 0;
830 else if (m_cbOffset) /* Do we have something to move? */
831 {
832 memmove(m_pbBuffer, &m_pbBuffer[m_cbOffset], cbInBuf);
833 m_cbSize = cbInBuf;
834 m_cbOffset = 0;
835 }
836
837 /* Do we need to grow the buffer? */
838 if (cbData + m_cbSize > m_cbAllocated)
839 {
840 size_t cbAlloc = m_cbSize + cbData;
841 cbAlloc = RT_ALIGN_Z(cbAlloc, _64K);
842 void *pvNew = RTMemRealloc(m_pbBuffer, cbAlloc);
843 if (pvNew)
844 {
845 m_pbBuffer = (uint8_t *)pvNew;
846 m_cbAllocated = cbAlloc;
847 }
848 else
849 rc = VERR_NO_MEMORY;
850 }
851
852 /* Finally, copy the data. */
853 if (RT_SUCCESS(rc))
854 {
855 if (cbData + m_cbSize <= m_cbAllocated)
856 {
857 memcpy(&m_pbBuffer[m_cbSize], pbData, cbData);
858 m_cbSize += cbData;
859 }
860 else
861 rc = VERR_BUFFER_OVERFLOW;
862 }
863 }
864
865 return rc;
866}
867
868/**
869 * Destroys the internal data buffer.
870 */
871void GuestProcessStream::Destroy(void)
872{
873 if (m_pbBuffer)
874 {
875 RTMemFree(m_pbBuffer);
876 m_pbBuffer = NULL;
877 }
878
879 m_cbAllocated = 0;
880 m_cbSize = 0;
881 m_cbOffset = 0;
882}
883
884#ifdef DEBUG
885void GuestProcessStream::Dump(const char *pszFile)
886{
887 LogFlowFunc(("Dumping contents of stream=0x%p (cbAlloc=%u, cbSize=%u, cbOff=%u) to %s\n",
888 m_pbBuffer, m_cbAllocated, m_cbSize, m_cbOffset, pszFile));
889
890 RTFILE hFile;
891 int rc = RTFileOpen(&hFile, pszFile, RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
892 if (RT_SUCCESS(rc))
893 {
894 rc = RTFileWrite(hFile, m_pbBuffer, m_cbSize, NULL /* pcbWritten */);
895 RTFileClose(hFile);
896 }
897}
898#endif
899
900/**
901 * Returns the current offset of the parser within
902 * the internal data buffer.
903 *
904 * @return uint32_t Parser offset.
905 */
906uint32_t GuestProcessStream::GetOffset()
907{
908 return m_cbOffset;
909}
910
911uint32_t GuestProcessStream::GetSize()
912{
913 return m_cbSize;
914}
915
916/**
917 * Tries to parse the next upcoming pair block within the internal
918 * buffer.
919 *
920 * Returns VERR_NO_DATA is no data is in internal buffer or buffer has been
921 * completely parsed already.
922 *
923 * Returns VERR_MORE_DATA if current block was parsed (with zero or more pairs
924 * stored in stream block) but still contains incomplete (unterminated)
925 * data.
926 *
927 * Returns VINF_SUCCESS if current block was parsed until the next upcoming
928 * block (with zero or more pairs stored in stream block).
929 *
930 * @return IPRT status code.
931 * @param streamBlock Reference to guest stream block to fill.
932 *
933 */
934int GuestProcessStream::ParseBlock(GuestProcessStreamBlock &streamBlock)
935{
936 if ( !m_pbBuffer
937 || !m_cbSize)
938 {
939 return VERR_NO_DATA;
940 }
941
942 AssertReturn(m_cbOffset <= m_cbSize, VERR_INVALID_PARAMETER);
943 if (m_cbOffset == m_cbSize)
944 return VERR_NO_DATA;
945
946 int rc = VINF_SUCCESS;
947
948 char *pszOff = (char*)&m_pbBuffer[m_cbOffset];
949 char *pszStart = pszOff;
950 uint32_t uDistance;
951 while (*pszStart)
952 {
953 size_t pairLen = strlen(pszStart);
954 uDistance = (pszStart - pszOff);
955 if (m_cbOffset + uDistance + pairLen + 1 >= m_cbSize)
956 {
957 rc = VERR_MORE_DATA;
958 break;
959 }
960 else
961 {
962 char *pszSep = strchr(pszStart, '=');
963 char *pszVal = NULL;
964 if (pszSep)
965 pszVal = pszSep + 1;
966 if (!pszSep || !pszVal)
967 {
968 rc = VERR_MORE_DATA;
969 break;
970 }
971
972 /* Terminate the separator so that we can
973 * use pszStart as our key from now on. */
974 *pszSep = '\0';
975
976 rc = streamBlock.SetValue(pszStart, pszVal);
977 if (RT_FAILURE(rc))
978 return rc;
979 }
980
981 /* Next pair. */
982 pszStart += pairLen + 1;
983 }
984
985 /* If we did not do any movement but we have stuff left
986 * in our buffer just skip the current termination so that
987 * we can try next time. */
988 uDistance = (pszStart - pszOff);
989 if ( !uDistance
990 && *pszStart == '\0'
991 && m_cbOffset < m_cbSize)
992 {
993 uDistance++;
994 }
995 m_cbOffset += uDistance;
996
997 return rc;
998}
999
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette