VirtualBox

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

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

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