VirtualBox

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

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

build fix

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