VirtualBox

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

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