VirtualBox

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

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