VirtualBox

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

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