VirtualBox

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

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