VirtualBox

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

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