VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/sg.cpp@ 80204

Last change on this file since 80204 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.1 KB
Line 
1/* $Id: sg.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * IPRT - S/G buffer handling.
4 */
5
6/*
7 * Copyright (C) 2010-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/sg.h>
32#include <iprt/string.h>
33#include <iprt/assert.h>
34#include <iprt/asm.h>
35
36
37static void *rtSgBufGet(PRTSGBUF pSgBuf, size_t *pcbData)
38{
39 size_t cbData;
40 void *pvBuf;
41
42 /* Check that the S/G buffer has memory left. */
43 if (RT_UNLIKELY( pSgBuf->idxSeg == pSgBuf->cSegs
44 && !pSgBuf->cbSegLeft))
45 {
46 *pcbData = 0;
47 return NULL;
48 }
49
50#ifndef RDESKTOP
51 AssertMsg( pSgBuf->cbSegLeft <= 128 * _1M
52 && (uintptr_t)pSgBuf->pvSegCur >= (uintptr_t)pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg
53 && (uintptr_t)pSgBuf->pvSegCur + pSgBuf->cbSegLeft <= (uintptr_t)pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg + pSgBuf->paSegs[pSgBuf->idxSeg].cbSeg,
54 ("pSgBuf->idxSeg=%d pSgBuf->cSegs=%d pSgBuf->pvSegCur=%p pSgBuf->cbSegLeft=%zd pSgBuf->paSegs[%d].pvSeg=%p pSgBuf->paSegs[%d].cbSeg=%zd\n",
55 pSgBuf->idxSeg, pSgBuf->cSegs, pSgBuf->pvSegCur, pSgBuf->cbSegLeft, pSgBuf->idxSeg, pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg, pSgBuf->idxSeg,
56 pSgBuf->paSegs[pSgBuf->idxSeg].cbSeg));
57#endif
58
59 cbData = RT_MIN(*pcbData, pSgBuf->cbSegLeft);
60 pvBuf = pSgBuf->pvSegCur;
61 pSgBuf->cbSegLeft -= cbData;
62
63 /* Advance to the next segment if required. */
64 if (!pSgBuf->cbSegLeft)
65 {
66 pSgBuf->idxSeg++;
67
68 if (pSgBuf->idxSeg < pSgBuf->cSegs)
69 {
70 pSgBuf->pvSegCur = pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg;
71 pSgBuf->cbSegLeft = pSgBuf->paSegs[pSgBuf->idxSeg].cbSeg;
72 }
73
74 *pcbData = cbData;
75 }
76 else
77 pSgBuf->pvSegCur = (uint8_t *)pSgBuf->pvSegCur + cbData;
78
79 return pvBuf;
80}
81
82
83RTDECL(void) RTSgBufInit(PRTSGBUF pSgBuf, PCRTSGSEG paSegs, size_t cSegs)
84{
85 AssertPtr(pSgBuf);
86 Assert( (cSegs > 0 && VALID_PTR(paSegs))
87 || (!cSegs && !paSegs));
88 Assert(cSegs < (~(unsigned)0 >> 1));
89
90 pSgBuf->paSegs = paSegs;
91 pSgBuf->cSegs = (unsigned)cSegs;
92 pSgBuf->idxSeg = 0;
93 if (cSegs && paSegs)
94 {
95 pSgBuf->pvSegCur = paSegs[0].pvSeg;
96 pSgBuf->cbSegLeft = paSegs[0].cbSeg;
97 }
98 else
99 {
100 pSgBuf->pvSegCur = NULL;
101 pSgBuf->cbSegLeft = 0;
102 }
103}
104
105
106RTDECL(void) RTSgBufReset(PRTSGBUF pSgBuf)
107{
108 AssertPtrReturnVoid(pSgBuf);
109
110 pSgBuf->idxSeg = 0;
111 if (pSgBuf->cSegs)
112 {
113 pSgBuf->pvSegCur = pSgBuf->paSegs[0].pvSeg;
114 pSgBuf->cbSegLeft = pSgBuf->paSegs[0].cbSeg;
115 }
116 else
117 {
118 pSgBuf->pvSegCur = NULL;
119 pSgBuf->cbSegLeft = 0;
120 }
121}
122
123
124RTDECL(void) RTSgBufClone(PRTSGBUF pSgBufTo, PCRTSGBUF pSgBufFrom)
125{
126 AssertPtr(pSgBufTo);
127 AssertPtr(pSgBufFrom);
128
129 pSgBufTo->paSegs = pSgBufFrom->paSegs;
130 pSgBufTo->cSegs = pSgBufFrom->cSegs;
131 pSgBufTo->idxSeg = pSgBufFrom->idxSeg;
132 pSgBufTo->pvSegCur = pSgBufFrom->pvSegCur;
133 pSgBufTo->cbSegLeft = pSgBufFrom->cbSegLeft;
134}
135
136
137RTDECL(void *) RTSgBufGetNextSegment(PRTSGBUF pSgBuf, size_t *pcbSeg)
138{
139 AssertPtrReturn(pSgBuf, NULL);
140 AssertPtrReturn(pcbSeg, NULL);
141
142 if (!*pcbSeg)
143 *pcbSeg = pSgBuf->cbSegLeft;
144
145 return rtSgBufGet(pSgBuf, pcbSeg);
146}
147
148
149RTDECL(size_t) RTSgBufCopy(PRTSGBUF pSgBufDst, PRTSGBUF pSgBufSrc, size_t cbCopy)
150{
151 AssertPtrReturn(pSgBufDst, 0);
152 AssertPtrReturn(pSgBufSrc, 0);
153
154 size_t cbLeft = cbCopy;
155 while (cbLeft)
156 {
157 size_t cbThisCopy = RT_MIN(RT_MIN(pSgBufDst->cbSegLeft, cbLeft), pSgBufSrc->cbSegLeft);
158 if (!cbThisCopy)
159 break;
160
161 size_t cbTmp = cbThisCopy;
162 void *pvBufDst = rtSgBufGet(pSgBufDst, &cbTmp);
163 Assert(cbTmp == cbThisCopy);
164 void *pvBufSrc = rtSgBufGet(pSgBufSrc, &cbTmp);
165 Assert(cbTmp == cbThisCopy);
166
167 memcpy(pvBufDst, pvBufSrc, cbThisCopy);
168
169 cbLeft -= cbThisCopy;
170 }
171
172 return cbCopy - cbLeft;
173}
174
175
176RTDECL(int) RTSgBufCmp(PCRTSGBUF pSgBuf1, PCRTSGBUF pSgBuf2, size_t cbCmp)
177{
178 AssertPtrReturn(pSgBuf1, 0);
179 AssertPtrReturn(pSgBuf2, 0);
180
181 /* Set up the temporary buffers */
182 RTSGBUF SgBuf1;
183 RTSgBufClone(&SgBuf1, pSgBuf1);
184 RTSGBUF SgBuf2;
185 RTSgBufClone(&SgBuf2, pSgBuf2);
186
187 size_t cbLeft = cbCmp;
188 while (cbLeft)
189 {
190 size_t cbThisCmp = RT_MIN(RT_MIN(SgBuf1.cbSegLeft, cbLeft), SgBuf2.cbSegLeft);
191 if (!cbThisCmp)
192 break;
193
194 size_t cbTmp = cbThisCmp;
195 void *pvBuf1 = rtSgBufGet(&SgBuf1, &cbTmp);
196 Assert(cbTmp == cbThisCmp);
197 void *pvBuf2 = rtSgBufGet(&SgBuf2, &cbTmp);
198 Assert(cbTmp == cbThisCmp);
199
200 int rc = memcmp(pvBuf1, pvBuf2, cbThisCmp);
201 if (rc)
202 return rc;
203
204 cbLeft -= cbThisCmp;
205 }
206
207 return 0;
208}
209
210
211RTDECL(int) RTSgBufCmpEx(PRTSGBUF pSgBuf1, PRTSGBUF pSgBuf2, size_t cbCmp, size_t *poffDiff, bool fAdvance)
212{
213 AssertPtrReturn(pSgBuf1, 0);
214 AssertPtrReturn(pSgBuf2, 0);
215
216 RTSGBUF SgBuf1Tmp;
217 RTSGBUF SgBuf2Tmp;
218 PRTSGBUF pSgBuf1Tmp;
219 PRTSGBUF pSgBuf2Tmp;
220
221 if (!fAdvance)
222 {
223 /* Set up the temporary buffers */
224 RTSgBufClone(&SgBuf1Tmp, pSgBuf1);
225 RTSgBufClone(&SgBuf2Tmp, pSgBuf2);
226 pSgBuf1Tmp = &SgBuf1Tmp;
227 pSgBuf2Tmp = &SgBuf2Tmp;
228 }
229 else
230 {
231 pSgBuf1Tmp = pSgBuf1;
232 pSgBuf2Tmp = pSgBuf2;
233 }
234
235 size_t cbLeft = cbCmp;
236 size_t off = 0;
237 while (cbLeft)
238 {
239 size_t cbThisCmp = RT_MIN(RT_MIN(pSgBuf1Tmp->cbSegLeft, cbLeft), pSgBuf2Tmp->cbSegLeft);
240 if (!cbThisCmp)
241 break;
242
243 size_t cbTmp = cbThisCmp;
244 uint8_t *pbBuf1 = (uint8_t *)rtSgBufGet(pSgBuf1Tmp, &cbTmp);
245 Assert(cbTmp == cbThisCmp);
246 uint8_t *pbBuf2 = (uint8_t *)rtSgBufGet(pSgBuf2Tmp, &cbTmp);
247 Assert(cbTmp == cbThisCmp);
248
249 int iDiff = memcmp(pbBuf1, pbBuf2, cbThisCmp);
250 if (iDiff)
251 {
252 /* Locate the first byte that differs if the caller requested this. */
253 if (poffDiff)
254 {
255 while ( cbThisCmp-- > 0
256 && *pbBuf1 == *pbBuf2)
257 {
258 pbBuf1++;
259 pbBuf2++;
260 off++;
261 }
262
263 *poffDiff = off;
264 }
265 return iDiff;
266 }
267
268 cbLeft -= cbThisCmp;
269 off += cbThisCmp;
270 }
271
272 return 0;
273}
274
275
276RTDECL(size_t) RTSgBufSet(PRTSGBUF pSgBuf, uint8_t ubFill, size_t cbSet)
277{
278 AssertPtrReturn(pSgBuf, 0);
279
280 size_t cbLeft = cbSet;
281
282 while (cbLeft)
283 {
284 size_t cbThisSet = cbLeft;
285 void *pvBuf = rtSgBufGet(pSgBuf, &cbThisSet);
286
287 if (!cbThisSet)
288 break;
289
290 memset(pvBuf, ubFill, cbThisSet);
291
292 cbLeft -= cbThisSet;
293 }
294
295 return cbSet - cbLeft;
296}
297
298
299RTDECL(size_t) RTSgBufCopyToBuf(PRTSGBUF pSgBuf, void *pvBuf, size_t cbCopy)
300{
301 AssertPtrReturn(pSgBuf, 0);
302 AssertPtrReturn(pvBuf, 0);
303
304 size_t cbLeft = cbCopy;
305
306 while (cbLeft)
307 {
308 size_t cbThisCopy = cbLeft;
309 void *pvSrc = rtSgBufGet(pSgBuf, &cbThisCopy);
310
311 if (!cbThisCopy)
312 break;
313
314 memcpy(pvBuf, pvSrc, cbThisCopy);
315
316 cbLeft -= cbThisCopy;
317 pvBuf = (void *)((uintptr_t)pvBuf + cbThisCopy);
318 }
319
320 return cbCopy - cbLeft;
321}
322
323
324RTDECL(size_t) RTSgBufCopyFromBuf(PRTSGBUF pSgBuf, const void *pvBuf, size_t cbCopy)
325{
326 AssertPtrReturn(pSgBuf, 0);
327 AssertPtrReturn(pvBuf, 0);
328
329 size_t cbLeft = cbCopy;
330
331 while (cbLeft)
332 {
333 size_t cbThisCopy = cbLeft;
334 void *pvDst = rtSgBufGet(pSgBuf, &cbThisCopy);
335
336 if (!cbThisCopy)
337 break;
338
339 memcpy(pvDst, pvBuf, cbThisCopy);
340
341 cbLeft -= cbThisCopy;
342 pvBuf = (const void *)((uintptr_t)pvBuf + cbThisCopy);
343 }
344
345 return cbCopy - cbLeft;
346}
347
348
349RTDECL(size_t) RTSgBufAdvance(PRTSGBUF pSgBuf, size_t cbAdvance)
350{
351 AssertPtrReturn(pSgBuf, 0);
352
353 size_t cbLeft = cbAdvance;
354 while (cbLeft)
355 {
356 size_t cbThisAdvance = cbLeft;
357 rtSgBufGet(pSgBuf, &cbThisAdvance);
358 if (!cbThisAdvance)
359 break;
360
361 cbLeft -= cbThisAdvance;
362 }
363
364 return cbAdvance - cbLeft;
365}
366
367
368RTDECL(size_t) RTSgBufSegArrayCreate(PRTSGBUF pSgBuf, PRTSGSEG paSeg, unsigned *pcSeg, size_t cbData)
369{
370 AssertPtrReturn(pSgBuf, 0);
371 AssertPtrReturn(pcSeg, 0);
372
373 unsigned cSeg = 0;
374 size_t cb = 0;
375
376 if (!paSeg)
377 {
378 if (pSgBuf->cbSegLeft > 0)
379 {
380 size_t idx = pSgBuf->idxSeg;
381 cSeg = 1;
382
383 cb += RT_MIN(pSgBuf->cbSegLeft, cbData);
384 cbData -= RT_MIN(pSgBuf->cbSegLeft, cbData);
385
386 while ( cbData
387 && idx < pSgBuf->cSegs - 1)
388 {
389 idx++;
390 cSeg++;
391 cb += RT_MIN(pSgBuf->paSegs[idx].cbSeg, cbData);
392 cbData -= RT_MIN(pSgBuf->paSegs[idx].cbSeg, cbData);
393 }
394 }
395 }
396 else
397 {
398 while ( cbData
399 && cSeg < *pcSeg)
400 {
401 size_t cbThisSeg = cbData;
402 void *pvSeg = rtSgBufGet(pSgBuf, &cbThisSeg);
403
404 if (!cbThisSeg)
405 {
406 Assert(!pvSeg);
407 break;
408 }
409
410 AssertMsg(cbThisSeg <= cbData, ("Impossible!\n"));
411
412 paSeg[cSeg].cbSeg = cbThisSeg;
413 paSeg[cSeg].pvSeg = pvSeg;
414 cSeg++;
415 cbData -= cbThisSeg;
416 cb += cbThisSeg;
417 }
418 }
419
420 *pcSeg = cSeg;
421
422 return cb;
423}
424
425
426RTDECL(bool) RTSgBufIsZero(PRTSGBUF pSgBuf, size_t cbCheck)
427{
428 RTSGBUF SgBufTmp;
429 RTSgBufClone(&SgBufTmp, pSgBuf);
430
431 bool fIsZero = true;
432 size_t cbLeft = cbCheck;
433 while (cbLeft)
434 {
435 size_t cbThisCheck = cbLeft;
436 void *pvBuf = rtSgBufGet(&SgBufTmp, &cbThisCheck);
437 if (!cbThisCheck)
438 break;
439 fIsZero = ASMMemIsZero(pvBuf, cbThisCheck);
440 if (!fIsZero)
441 break;
442 cbLeft -= cbThisCheck;
443 }
444
445 return fIsZero;
446}
447
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