VirtualBox

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

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