|
1 // Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32\euser\cbase\ub_buf.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include "ub_std.h" |
|
19 |
|
20 class TBufSegLink : public TDblQueLink |
|
21 { |
|
22 public: |
|
23 inline TBufSegLink() : iLen(0) {} |
|
24 inline TBufSegLink *Next() const {return((TBufSegLink *)iNext);} |
|
25 inline TBufSegLink *Prev() const {return((TBufSegLink *)iPrev);} |
|
26 public: |
|
27 TInt iLen; |
|
28 }; |
|
29 |
|
30 EXPORT_C CBufBase::CBufBase(TInt anExpandSize) |
|
31 // |
|
32 // Constructor |
|
33 // |
|
34 /** |
|
35 @internalComponent |
|
36 */ |
|
37 { |
|
38 |
|
39 __ASSERT_ALWAYS(anExpandSize>=0,Panic(EBufExpandSizeNegative)); |
|
40 // iSize=0; |
|
41 iExpandSize=anExpandSize; |
|
42 } |
|
43 |
|
44 EXPORT_C CBufBase::~CBufBase() |
|
45 /** |
|
46 Destructor |
|
47 */ |
|
48 { |
|
49 } |
|
50 |
|
51 EXPORT_C void CBufBase::Reset() |
|
52 /** |
|
53 Deletes all data in the buffer. |
|
54 |
|
55 Its behaviour is the same as calling Delete(0,Size()). |
|
56 The buffer is compressed before the function returns. |
|
57 */ |
|
58 { |
|
59 |
|
60 if (iSize) |
|
61 Delete(0,iSize); |
|
62 Compress(); |
|
63 } |
|
64 |
|
65 EXPORT_C void CBufBase::Read(TInt aPos,TDes8 &aDes) const |
|
66 // |
|
67 // Read up to aDes.MaxLength() bytes. |
|
68 // |
|
69 /** |
|
70 Reads data from the buffer into a descriptor. |
|
71 |
|
72 Data, starting at the specified buffer position is written to the descriptor, |
|
73 filling the descriptor. |
|
74 |
|
75 @param aPos Buffer position from which data is read: must be in range zero |
|
76 to Size(). |
|
77 @param aDes On return, contains the data read from the buffer; its MaxLength() |
|
78 specifies the amount of data to be read. |
|
79 */ |
|
80 { |
|
81 |
|
82 Read(aPos,aDes,aDes.MaxLength()); |
|
83 } |
|
84 |
|
85 EXPORT_C void CBufBase::Read(TInt aPos,TDes8 &aDes,TInt aLength) const |
|
86 /** |
|
87 Reads the specified number of bytes of data from the buffer into a descriptor. |
|
88 |
|
89 @param aPos Buffer position from which data is read: must be in range zero |
|
90 to (Size() minus the length of the data to be read). |
|
91 @param aDes On return, contains data read from the buffer. |
|
92 @param aLength The length of the data to be read. |
|
93 */ |
|
94 { |
|
95 |
|
96 aDes.SetLength(aLength); |
|
97 Read(aPos,(TAny *)aDes.Ptr(),aLength); |
|
98 } |
|
99 |
|
100 EXPORT_C void CBufBase::Read(TInt aPos,TAny *aPtr,TInt aLength) const |
|
101 /** |
|
102 Reads the specified number of bytes of data from the buffer into a specified |
|
103 address. |
|
104 |
|
105 @param aPos Buffer position from which data is read: must be in range zero |
|
106 to (Size() minus the length of the data to be read). |
|
107 @param aPtr The address into which the data should be read. |
|
108 @param aLength The length of the data to be read. |
|
109 */ |
|
110 { |
|
111 |
|
112 if (aLength==0) |
|
113 return; |
|
114 __ASSERT_ALWAYS(aLength>0,Panic(EBufReadLengthNegative)); |
|
115 __ASSERT_ALWAYS((aPos+aLength)<=iSize,Panic(EBufReadBeyondEnd)); |
|
116 TUint8 *pT=(TUint8 *)aPtr; |
|
117 while (aLength) |
|
118 { |
|
119 TPtr8 p=((CBufBase *)this)->Ptr(aPos); |
|
120 TInt s=Min(p.Length(),aLength); |
|
121 pT=Mem::Copy(pT,p.Ptr(),s); |
|
122 aLength-=s; |
|
123 aPos+=s; |
|
124 } |
|
125 } |
|
126 |
|
127 EXPORT_C void CBufBase::Write(TInt aPos,const TDesC8 &aDes) |
|
128 // |
|
129 // Write aDes.Length() characters to the buffer. Does not cause any expansion. |
|
130 // |
|
131 /** |
|
132 Writes data from a descriptor to the buffer. |
|
133 |
|
134 The data in the descriptor overwrites the data in the buffer from the insertion |
|
135 point onwards. |
|
136 |
|
137 No new space is allocated; this function cannot fail (provided the parameters |
|
138 are specified within the bounds of the buffer and descriptor). |
|
139 |
|
140 No shuffling occurs; new data is written to the memory locations occupied |
|
141 by the data it overwrites. |
|
142 |
|
143 @param aPos Buffer position at which data will begin to be written; must be |
|
144 in range zero to (Size() minus the length of the data |
|
145 to be written). |
|
146 @param aDes Contains the data to be written. The length of data to be written |
|
147 is the descriptor length. |
|
148 */ |
|
149 { |
|
150 |
|
151 Write(aPos,aDes.Ptr(),aDes.Length()); |
|
152 } |
|
153 |
|
154 EXPORT_C void CBufBase::Write(TInt aPos,const TDesC8 &aDes,TInt aLength) |
|
155 // |
|
156 // Write aDes.Length() characters to the buffer. Does not cause any expansion. |
|
157 // |
|
158 /** |
|
159 Writes the specified number of bytes of data from a descriptor to the buffer. |
|
160 |
|
161 The data in the descriptor overwrites the data in the buffer from the insertion |
|
162 point onwards. |
|
163 |
|
164 No new space is allocated; this function cannot fail (provided the parameters |
|
165 are specified within the bounds of the buffer and descriptor). |
|
166 |
|
167 No shuffling occurs; new data is written to the memory locations occupied |
|
168 by the data it overwrites. |
|
169 |
|
170 @param aPos Buffer position at which data will begin to be written; must be |
|
171 in range zero to (Size() minus the length of the data to |
|
172 be written). |
|
173 @param aDes Contains the data to be written. |
|
174 @param aLength The length of the data to be written. |
|
175 */ |
|
176 { |
|
177 |
|
178 Write(aPos,aDes.Ptr(),aLength); |
|
179 } |
|
180 |
|
181 EXPORT_C void CBufBase::Write(TInt aPos,const TAny *aPtr,TInt aLength) |
|
182 /** |
|
183 Writes the specified number of bytes of data from the specified address to the |
|
184 buffer. |
|
185 |
|
186 The data in the buffer is overwritten from the insertion point onwards. |
|
187 |
|
188 No new space is allocated; this function cannot fail (provided the parameters |
|
189 are specified within the bounds of the buffer and descriptor). |
|
190 |
|
191 No shuffling occurs: new data is written to the memory locations occupied |
|
192 by the data it overwrites. |
|
193 |
|
194 @param aPos Buffer position at which data will begin to be written; must be |
|
195 in range zero to (Size() minus the length of the data to |
|
196 be written). |
|
197 @param aPtr The address of the data to be written. |
|
198 @param aLength The length of the data to be written. |
|
199 |
|
200 @panic E32USER-CBase 7, if aLength is not positive |
|
201 @panic E32USER-CBase 5, if aPos + aLength is greater than the number of |
|
202 data bytes in the buffer, i.e. if the target appears |
|
203 to be outside the buffer. |
|
204 */ |
|
205 { |
|
206 |
|
207 if (aLength==0) |
|
208 return; |
|
209 __ASSERT_ALWAYS(aLength>0,Panic(EBufWriteLengthNegative)); |
|
210 __ASSERT_ALWAYS((aPos+aLength)<=iSize,Panic(EBufWriteBeyondEnd)); |
|
211 const TUint8 *pS=(const TUint8 *)aPtr; |
|
212 while (aLength) |
|
213 { |
|
214 TPtr8 p=Ptr(aPos); |
|
215 TInt s=Min(p.Length(),aLength); |
|
216 Mem::Copy((TAny *)p.Ptr(),pS,s); |
|
217 pS+=s; |
|
218 aLength-=s; |
|
219 aPos+=s; |
|
220 } |
|
221 } |
|
222 |
|
223 EXPORT_C void CBufBase::InsertL(TInt aPos,const TDesC8 &aDes) |
|
224 // |
|
225 // Insert aDes.Length() bytes into the buffer. |
|
226 // |
|
227 /** |
|
228 Inserts data into the buffer. |
|
229 |
|
230 Data at and beyond the insertion position is moved to make way for the inserted |
|
231 data. Data before the insertion position remains in place. |
|
232 |
|
233 Notes: |
|
234 |
|
235 1. Insertion may require more buffer space to be allocated. |
|
236 |
|
237 2. In the case of flat buffers, the buffer is extended by a ReAllocL() of the |
|
238 buffer's heap cell, to the smallest multiple of the granularity that will |
|
239 contain the data required. If this reallocation fails, the insertion is |
|
240 impossible and a leave occurs. |
|
241 |
|
242 3. In the case of segmented buffers, a reallocation is performed if the segment |
|
243 containing the insertion position has insufficient space, and |
|
244 immediately-neighbouring segments cannot be used to contain the new data. |
|
245 As many new segments as are necessary to contain the inserted data are |
|
246 allocated. Each new segment's length is the buffer's granularity. |
|
247 If extension or new allocation fails, a leave occurs. |
|
248 |
|
249 4. Insertion may also require data to be shuffled. In the case of flat buffers, |
|
250 data beyond the insertion point is shuffled up to create a gap; the new data |
|
251 is then inserted into this gap. In the case of segmented buffers, shuffling |
|
252 is minimised by inserting the new data into newly-allocated buffers, and |
|
253 shuffling only immediately-neighbouring buffers if possible. This may result |
|
254 in some wastage of space, but is much more time-efficient for large amounts |
|
255 of data. |
|
256 |
|
257 @param aPos Buffer position before which the data will be inserted; must be |
|
258 in range zero to Size(). |
|
259 @param aDes The data to be inserted; the length of the data is the descriptor |
|
260 length. |
|
261 |
|
262 @leave KErrNoMemory If the insertion requires a bigger buffer, and the |
|
263 necessary allocation or re-allocation fails. |
|
264 */ |
|
265 { |
|
266 |
|
267 InsertL(aPos,aDes.Ptr(),aDes.Length()); |
|
268 } |
|
269 |
|
270 EXPORT_C void CBufBase::InsertL(TInt aPos,const TDesC8 &aDes,TInt aLength) |
|
271 // |
|
272 // Insert aLength bytes into the buffer. |
|
273 // |
|
274 /** |
|
275 Inserts the specified number of bytes of data from a descriptor into |
|
276 the buffer. |
|
277 |
|
278 aLength bytes of data from aDes are inserted into the buffer at aPos. Data at |
|
279 and beyond the insertion position is moved to make way for the inserted data. |
|
280 Data before the insertion position remains in place. |
|
281 |
|
282 Notes: |
|
283 |
|
284 1. Insertion may require more buffer space to be allocated. |
|
285 |
|
286 2. In the case of flat buffers, the buffer is extended by a ReAllocL() of the |
|
287 buffer's heap cell, to the smallest multiple of the granularity that will |
|
288 contain the data required. If this reallocation fails, the insertion is |
|
289 impossible and a leave occurs. |
|
290 |
|
291 3. In the case of segmented buffers, a reallocation is performed if the segment |
|
292 containing the insertion position has insufficient space, and |
|
293 immediately-neighbouring segments cannot be used to contain the new data. |
|
294 As many new segments as are necessary to contain the inserted data are |
|
295 allocated. Each new segment's length is the buffer's granularity. |
|
296 If extension or new allocation fails, a leave occurs. |
|
297 |
|
298 4. Insertion may also require data to be shuffled. In the case of flat buffers, |
|
299 data beyond the insertion point is shuffled up to create a gap: the new data |
|
300 is then inserted into this gap. In the case of segmented buffers, shuffling |
|
301 is minimised by inserting the new data into newly-allocated buffers, |
|
302 and shuffling only immediately-neighbouring buffers if possible. |
|
303 This may result in some wastage of space, but is much more time-efficient |
|
304 for large amounts of data. |
|
305 |
|
306 @param aPos Buffer position before which the data will be inserted; must be |
|
307 in range zero to Size(). |
|
308 @param aDes The data to be inserted. |
|
309 @param aLength The length of data to be inserted. |
|
310 |
|
311 @leave KErrNoMemory If the insertion requires a bigger buffer, and the |
|
312 necessary allocation or re-allocation fails. |
|
313 */ |
|
314 { |
|
315 |
|
316 InsertL(aPos,aDes.Ptr(),aLength); |
|
317 } |
|
318 |
|
319 EXPORT_C void CBufBase::InsertL(TInt aPos,const TAny *aPtr,TInt aLength) |
|
320 /** |
|
321 Inserts bytes of data from the specified address into the buffer. |
|
322 |
|
323 Inserts aLength bytes of data found at address aPtr into the buffer at aPos. |
|
324 Data at and beyond the insertion position is moved to make way for the inserted |
|
325 data. Data before the insertion position remains in place. |
|
326 |
|
327 Notes: |
|
328 |
|
329 1. Insertion may require more buffer space to be allocated. |
|
330 |
|
331 2. In the case of flat buffers, the buffer is extended by a ReAllocL() of the |
|
332 buffer's heap cell, to the smallest multiple of the granularity that will |
|
333 contain the data required. If this reallocation fails, the insertion is |
|
334 impossible and a leave occurs. |
|
335 |
|
336 2. In the case of segmented buffers, a reallocation is performed if the segment |
|
337 containing the insertion position has insufficient space, and |
|
338 immediately-neighbouring segments cannot be used to contain the new data. |
|
339 As many new segments as are necessary to contain the inserted data are |
|
340 allocated. Each new segment's length is the buffer's granularity. |
|
341 If extension or new allocation fails, a leave occurs. |
|
342 |
|
343 4. Insertion may also require data to be shuffled. In the case of flat buffers, |
|
344 data beyond the insertion point is shuffled up to create a gap: the new data |
|
345 is then inserted into this gap. In the case of segmented buffers, shuffling |
|
346 is minimised by inserting the new data into newly-allocated buffers, and |
|
347 shuffling only immediately-neighbouring buffers if possible. This may result |
|
348 in some wastage of space, but is much more time-efficient for large amounts |
|
349 of data. |
|
350 |
|
351 @param aPos Buffer position before which the data will be inserted: must be |
|
352 in range zero to Size(). |
|
353 @param aPtr The address of the data to be inserted. |
|
354 @param aLength The length of the data to be inserted. |
|
355 |
|
356 @leave KErrNoMemory If the insertion requires a bigger buffer, and the |
|
357 necessary allocation or re-allocation fails. |
|
358 */ |
|
359 { |
|
360 |
|
361 if (aLength==0) |
|
362 return; |
|
363 __ASSERT_ALWAYS(aLength>0,Panic(EBufInsertLengthNegative)); |
|
364 __ASSERT_ALWAYS(aPtr,Panic(EBufInsertBadPtr)); |
|
365 DoInsertL(aPos,aPtr,aLength); |
|
366 } |
|
367 |
|
368 EXPORT_C void CBufBase::ExpandL(TInt aPos,TInt aLength) |
|
369 /** |
|
370 Inserts an uninitialised region into the buffer. |
|
371 |
|
372 Data at and beyond the insertion position is moved to make way for the inserted |
|
373 region. Data before the insertion position remains in place. |
|
374 |
|
375 Note: |
|
376 |
|
377 1. The inserted region is not initialised. After using ExpandL(), you should |
|
378 then use a series of Write()s to fill this region with data. |
|
379 |
|
380 2. Use ExpandL() followed by a series of Write()s when you know the amount of |
|
381 data to be inserted, in advance. It is more efficient than a series of |
|
382 InsertL()s. In addition, once the result of the ExpandL() has been checked, |
|
383 it is guaranteed that the Write()s do not leave, which can sometimes be |
|
384 useful. |
|
385 |
|
386 @param aPos Buffer position before which the region will be inserted; must |
|
387 be in range zero to Size(). |
|
388 @param aLength The length of the region to be inserted. |
|
389 */ |
|
390 { |
|
391 |
|
392 if (aLength==0) |
|
393 return; |
|
394 __ASSERT_ALWAYS(aLength>0,Panic(EBufInsertLengthNegative)); |
|
395 DoInsertL(aPos,NULL,aLength); |
|
396 } |
|
397 |
|
398 EXPORT_C void CBufBase::ResizeL(TInt aSize) |
|
399 /** |
|
400 Re-sizes the buffer to the specified size. |
|
401 |
|
402 The new size can be larger or smaller than the existing size. |
|
403 |
|
404 If the new size is larger than the existing size, the buffer is expanded by |
|
405 adding uninitialised data to the end of it. |
|
406 |
|
407 If the new size is smaller than the existing size, the buffer is reduced; |
|
408 any data at the end of the buffer is lost. |
|
409 |
|
410 Notes: |
|
411 |
|
412 1. If the new size is larger than the existing size, the function is equivalent |
|
413 to Delete(aSize,Size()-aSize). |
|
414 |
|
415 2. If the new size is smaller than the existing size, the function is equivalent |
|
416 to ExpandL((Size(),aSize-Size()). |
|
417 |
|
418 3. The motivations for using ResizeL() are the same as those for using Delete() |
|
419 and ExpandL(). |
|
420 |
|
421 @param aSize The new size of the buffer; this value must be greater than or |
|
422 equal to zero. |
|
423 */ |
|
424 { |
|
425 |
|
426 TInt excess=iSize-aSize; |
|
427 if (excess>0) |
|
428 Delete(aSize,excess); |
|
429 else |
|
430 ExpandL(iSize,-excess); |
|
431 } |
|
432 |
|
433 EXPORT_C CBufFlat *CBufFlat::NewL(TInt anExpandSize) |
|
434 /** |
|
435 Allocates and constructs a flat buffer. |
|
436 |
|
437 If there is insufficient memory available to allocate the flat buffer, the |
|
438 function leaves. |
|
439 |
|
440 @param anExpandSize The granularity of buffer expansion. Additional space, |
|
441 when required, is always allocated in multiples of |
|
442 this number. Note: although a value of zero is permitted |
|
443 by this interface, it has no meaning, and risks raising |
|
444 panics later during execution. We suggest that you pass |
|
445 a positive value. |
|
446 |
|
447 @return A pointer to the flat buffer object. |
|
448 |
|
449 @panic E32USER-CBase 3 if the granularity is negative. |
|
450 */ |
|
451 { |
|
452 |
|
453 return(new(ELeave) CBufFlat(anExpandSize)); |
|
454 } |
|
455 |
|
456 EXPORT_C CBufFlat::CBufFlat(TInt anExpandSize) |
|
457 // |
|
458 // Constructor |
|
459 // |
|
460 /** |
|
461 @internalComponent |
|
462 */ |
|
463 : CBufBase(anExpandSize) |
|
464 { |
|
465 |
|
466 // iMaxSize=0; |
|
467 // iPtr=NULL; |
|
468 } |
|
469 |
|
470 EXPORT_C CBufFlat::~CBufFlat() |
|
471 /** |
|
472 Destructor. |
|
473 |
|
474 Frees all resources owned by the object, prior to its destruction. |
|
475 Specifically, it frees the allocated cell used as a buffer. |
|
476 */ |
|
477 { |
|
478 |
|
479 User::Free(iPtr); |
|
480 } |
|
481 |
|
482 EXPORT_C void CBufFlat::Compress() |
|
483 /** |
|
484 Compresses the buffer so as to occupy minimal space. |
|
485 |
|
486 This frees any unused memory at the end of the buffer. |
|
487 |
|
488 @see CBufBase::Compress |
|
489 */ |
|
490 { |
|
491 |
|
492 SetReserveL(iSize); |
|
493 } |
|
494 |
|
495 EXPORT_C void CBufFlat::SetReserveL(TInt aSize) |
|
496 /** |
|
497 Specifies a minimum amount of space which the flat buffer should occupy. |
|
498 |
|
499 If the required size is zero, the heap cell is deleted. If it is different |
|
500 from the current size, the heap cell is rellocated accordingly. |
|
501 |
|
502 @param aSize The size of the buffer required. If there is no data in the |
|
503 buffer, i.e. Size() returns zero, then this value |
|
504 can be zero, which causes the buffer's allocated heap cell |
|
505 to be deleted. |
|
506 |
|
507 @panic E32USER-CBase 10, if aSize is negative. |
|
508 @panic E32USER-CBase 11, if there is data in the buffer, and aSize is less than |
|
509 the value returned by Size(). |
|
510 */ |
|
511 { |
|
512 |
|
513 __ASSERT_ALWAYS(aSize>=0,Panic(EBufFlatReserveNegative)); |
|
514 __ASSERT_ALWAYS(aSize>=iSize,Panic(EBufFlatReserveSetTooSmall)); |
|
515 if (!aSize) |
|
516 { |
|
517 User::Free(iPtr); |
|
518 iPtr=NULL; |
|
519 } |
|
520 else |
|
521 iPtr=(TUint8 *)User::ReAllocL(iPtr,aSize); |
|
522 iMaxSize=aSize; |
|
523 } |
|
524 |
|
525 EXPORT_C void CBufFlat::DoInsertL(TInt aPos,const TAny *aPtr,TInt aLength) |
|
526 // |
|
527 // Insert into the buffer. Can cause expansion. |
|
528 // |
|
529 { |
|
530 |
|
531 __ASSERT_ALWAYS(aPos>=0 && aPos<=iSize,Panic(EBufFlatPosOutOfRange)); |
|
532 TInt len=iSize+aLength; |
|
533 if (len>iMaxSize) |
|
534 { |
|
535 TInt r=len-iMaxSize; |
|
536 r=((r/iExpandSize)+1)*iExpandSize; |
|
537 SetReserveL(iMaxSize+r); |
|
538 } |
|
539 Mem::Copy(iPtr+aPos+aLength,iPtr+aPos,iSize-aPos); |
|
540 if (aPtr) |
|
541 Mem::Copy(iPtr+aPos,aPtr,aLength); |
|
542 iSize+=aLength; |
|
543 } |
|
544 |
|
545 EXPORT_C void CBufFlat::Delete(TInt aPos,TInt aLength) |
|
546 /** |
|
547 Deletes data from the buffer. |
|
548 |
|
549 During deletion, any data beyond the deleted data is shuffled up so that |
|
550 the buffer contents are contiguous. No memory is freed. |
|
551 |
|
552 @param aPos Buffer position where the deletion will begin; must be in the |
|
553 range zero to (Size() minus the length of the data |
|
554 to be deleted). |
|
555 @param aLength The number of bytes to be deleted. |
|
556 |
|
557 @panic E32USER-CBase 12, if aPos is negative or is greater than the |
|
558 current size of the buffer. |
|
559 @panic E32USER-CBase 13, if aPos + aLength is greater than the |
|
560 current size of the buffer. |
|
561 |
|
562 @see CBufBase::Delete |
|
563 */ |
|
564 { |
|
565 |
|
566 __ASSERT_ALWAYS(aPos>=0 && aPos<=iSize,Panic(EBufFlatPosOutOfRange)); |
|
567 __ASSERT_ALWAYS((aPos+aLength)<=iSize,Panic(EBufFlatDeleteBeyondEnd)); |
|
568 Mem::Copy(iPtr+aPos,iPtr+aPos+aLength,iSize-aLength-aPos); |
|
569 iSize-=aLength; |
|
570 } |
|
571 |
|
572 EXPORT_C TPtr8 CBufFlat::Ptr(TInt aPos) |
|
573 /** |
|
574 Gets a pointer descriptor to represent the data starting at the specified |
|
575 data byte through to the end of the contiguous region containing that byte. |
|
576 |
|
577 Calculation of the pointer and length involves only a few machine instructions |
|
578 and is independent of the data contained in the buffer. |
|
579 |
|
580 @param aPos Buffer position: must be in range zero to Size(). |
|
581 |
|
582 @return Descriptor representing the data starting at aPos to the end of |
|
583 the buffer. |
|
584 */ |
|
585 { |
|
586 |
|
587 __ASSERT_ALWAYS(aPos>=0 && aPos<=iSize,Panic(EBufFlatPosOutOfRange)); |
|
588 TInt len=iSize-aPos; |
|
589 return(TPtr8(iPtr+aPos,len,len)); |
|
590 } |
|
591 |
|
592 EXPORT_C TPtr8 CBufFlat::BackPtr(TInt aPos) |
|
593 // |
|
594 // Return a pointer to the buffer which has the maximum amount of data |
|
595 // before aPos, and the amount of data remaining. |
|
596 // |
|
597 /** |
|
598 Gets a pointer descriptor to represent the data starting at the beginning |
|
599 of the contiguous region containing that byte through to the byte immediately |
|
600 preceding the specified byte. |
|
601 |
|
602 The descriptor always points to the beginning of the buffer containing |
|
603 the specified byte. Calculation of the pointer and length involves only a few |
|
604 machine instructions and is independent of the data contained in the buffer. |
|
605 |
|
606 @param aPos Buffer position: must be in range zero to Size(). |
|
607 |
|
608 @return Descriptor representing the back contiguous region. |
|
609 |
|
610 @see CBufBase::BackPtr |
|
611 */ |
|
612 { |
|
613 |
|
614 __ASSERT_ALWAYS(aPos>=0 && aPos<=iSize,Panic(EBufFlatPosOutOfRange)); |
|
615 return(TPtr8(iPtr,aPos,aPos)); |
|
616 } |
|
617 |
|
618 void CBufSeg::InsertIntoSegment(TBufSegLink *aSeg,TInt anOffset,const TAny *aPtr,TInt aLength) |
|
619 // |
|
620 // Insert into the segment. |
|
621 // |
|
622 { |
|
623 |
|
624 if (aLength) |
|
625 { |
|
626 TUint8 *pS=((TUint8 *)(aSeg+1))+anOffset; |
|
627 Mem::Copy(pS+aLength,pS,aSeg->iLen-anOffset); |
|
628 if (aPtr) |
|
629 Mem::Copy(pS,aPtr,aLength); |
|
630 aSeg->iLen+=aLength; |
|
631 } |
|
632 } |
|
633 |
|
634 void CBufSeg::DeleteFromSegment(TBufSegLink *aSeg,TInt anOffset,TInt aLength) |
|
635 // |
|
636 // Delete from the segment. |
|
637 // |
|
638 { |
|
639 |
|
640 if (aLength) |
|
641 { |
|
642 TUint8 *pS=((TUint8 *)(aSeg+1))+anOffset; |
|
643 Mem::Copy(pS,pS+aLength,aSeg->iLen-anOffset-aLength); |
|
644 aSeg->iLen-=aLength; |
|
645 } |
|
646 } |
|
647 |
|
648 void CBufSeg::FreeSegment(TBufSegLink *aSeg) |
|
649 // |
|
650 // Free an entire segment. |
|
651 // |
|
652 { |
|
653 |
|
654 aSeg->Deque(); |
|
655 User::Free(aSeg); |
|
656 } |
|
657 |
|
658 void CBufSeg::SetSBO(TInt aPos) |
|
659 // |
|
660 // Set a segment-base-offset struct (SBO) to a new pos. |
|
661 // If the initial psbo->seg is not NULL, it assumes that it is a valid |
|
662 // SBO for a different position and counts relative to the initial SBO |
|
663 // to set the desired position. If the initial psbo->seg is NULL, it starts |
|
664 // scanning from the beginning ie pos=0. |
|
665 // When the position is between segments A and B, there are two equivalent |
|
666 // positions: (1) at the beginning of B and (2) at the end of A. |
|
667 // Option (1) is suitable for referencing the data and deleting. |
|
668 // Option (2) is best for insertion when A is not full. |
|
669 // This function uses option (1) and will always set the SBO to the |
|
670 // beginning of the next segment. It does however set to the end of the |
|
671 // last segment when pos is equal to the number of bytes in the buffer. |
|
672 // |
|
673 { |
|
674 |
|
675 __ASSERT_ALWAYS(aPos>=0 && aPos<=iSize,Panic(EBufSegPosOutOfRange)); |
|
676 if (aPos==iSize) |
|
677 { // Positioning to end is treated as a special case |
|
678 iSeg=0; |
|
679 if (iSize) |
|
680 iBase=aPos-(iOffset=(iSeg=iQue.Last())->iLen); |
|
681 return; |
|
682 } |
|
683 TInt base=iBase; |
|
684 TBufSegLink *next; |
|
685 if ((next=iSeg)==NULL) |
|
686 { // anSbo is not valid - set to pos=0 |
|
687 next=iQue.First(); |
|
688 base=0; |
|
689 } |
|
690 if (aPos<base) |
|
691 { // Look to the left |
|
692 do |
|
693 { |
|
694 next=next->Prev(); |
|
695 base-=next->iLen; |
|
696 } while (aPos<base); |
|
697 } |
|
698 else |
|
699 { // Look to the right |
|
700 TBufSegLink *nn; |
|
701 while (aPos>=(base+next->iLen) && !iQue.IsHead(nn=next->Next())) |
|
702 { |
|
703 base+=next->iLen; |
|
704 next=nn; |
|
705 } |
|
706 } |
|
707 iSeg=next; |
|
708 iBase=base; |
|
709 iOffset=aPos-base; |
|
710 __ASSERT_DEBUG(iOffset<=iExpandSize,Panic(EBufSegSetSBO)); |
|
711 } |
|
712 |
|
713 void CBufSeg::AllocSegL(TBufSegLink *aSeg,TInt aNumber) |
|
714 // |
|
715 // Allocate a number of segments. |
|
716 // |
|
717 { |
|
718 |
|
719 for (TInt i=0;i<aNumber;i++) |
|
720 { |
|
721 TBufSegLink *pL=(TBufSegLink *)User::Alloc(sizeof(TBufSegLink)+iExpandSize); |
|
722 if (pL==NULL) |
|
723 { // alloc failed - tidy up |
|
724 while (i--) |
|
725 FreeSegment(aSeg->Next()); |
|
726 User::Leave(KErrNoMemory); |
|
727 } |
|
728 new(pL) TBufSegLink; |
|
729 pL->Enque(aSeg); |
|
730 } |
|
731 } |
|
732 |
|
733 EXPORT_C CBufSeg *CBufSeg::NewL(TInt anExpandSize) |
|
734 /** |
|
735 Allocates and constructs a segmented buffer. |
|
736 |
|
737 If there is insufficient memory available to allocate the segmented buffer, |
|
738 the function leaves. |
|
739 |
|
740 @param anExpandSize The granularity of the buffer. Each segment contains (in |
|
741 addition to 16 bytes of overhead) this number of bytes for |
|
742 data. Note: although a value of zero is permitted by this |
|
743 interface, it has no meaning, and risks raising panics later |
|
744 during execution. We suggest that you pass a positive value. |
|
745 |
|
746 @return If successful, a pointer to the segmented buffer object. |
|
747 |
|
748 @panic E32USER-CBase 3 if the granularity is negative. |
|
749 */ |
|
750 { |
|
751 |
|
752 return(new(ELeave) CBufSeg(anExpandSize)); |
|
753 } |
|
754 |
|
755 EXPORT_C CBufSeg::CBufSeg(TInt anExpandSize) |
|
756 // |
|
757 // Constructor |
|
758 // |
|
759 : CBufBase(anExpandSize) |
|
760 { |
|
761 |
|
762 // iSeg=NULL; |
|
763 } |
|
764 |
|
765 EXPORT_C CBufSeg::~CBufSeg() |
|
766 /** |
|
767 Destructor. |
|
768 |
|
769 Frees all resources owned by the object, prior to its destruction. |
|
770 |
|
771 Specifically, it frees all segments allocated to the buffer. |
|
772 */ |
|
773 { |
|
774 |
|
775 Delete(0,iSize); |
|
776 } |
|
777 |
|
778 EXPORT_C void CBufSeg::Compress() |
|
779 /** |
|
780 Compresses the buffer so as to occupy minimal space. |
|
781 |
|
782 Fills any space in each segment of the buffer by moving contents from the next |
|
783 segment to the current one. Where this activity results in empty segments, |
|
784 it frees the memory associated with these segments. |
|
785 |
|
786 @see CBufBase::Compress |
|
787 */ |
|
788 { |
|
789 |
|
790 if (!iSize) |
|
791 return; |
|
792 iSeg=NULL; // Invalidate current position |
|
793 TBufSegLink *p1=iQue.First(); |
|
794 TBufSegLink *p2; |
|
795 while (!iQue.IsHead(p2=p1->Next())) |
|
796 { |
|
797 TInt rem=iExpandSize-p1->iLen; |
|
798 if (rem==0) |
|
799 { |
|
800 p1=p2; |
|
801 continue; // Full |
|
802 } |
|
803 if (rem>=p2->iLen) |
|
804 { // Zap the next segment |
|
805 InsertIntoSegment(p1,p1->iLen,p2+1,p2->iLen); |
|
806 FreeSegment(p2); |
|
807 continue; |
|
808 } |
|
809 InsertIntoSegment(p1,p1->iLen,p2+1,rem); // Make full |
|
810 DeleteFromSegment(p2,0,rem); |
|
811 p1=p2; |
|
812 } |
|
813 } |
|
814 |
|
815 EXPORT_C void CBufSeg::DoInsertL(TInt aPos,const TAny *aPtr,TInt aLength) |
|
816 // |
|
817 // Insert data at the specified position. This is quite tricky. |
|
818 // In general, the data to be copied may be broken down into the |
|
819 // following elements: |
|
820 // s1 bytes into the current segment (p1) |
|
821 // nseg-1 segments of self->sgbuf.hd.len (ie full segments) |
|
822 // s2 bytes into segment nseg |
|
823 // s3 bytes into the next segment (p2) |
|
824 // where p2 is the next segment before the insertion of nseg new segments. |
|
825 // In addition, any remaining data to the right of the insertion point must |
|
826 // be moved appropriately. In general, r1 bytes must be moved into segment |
|
827 // nseg (r2 bytes) and segment p2 (r3 bytes) where r1=r2+r3. |
|
828 // |
|
829 { |
|
830 |
|
831 SetSBO(aPos); |
|
832 TInt slen=iExpandSize; |
|
833 TInt ofs=iOffset; |
|
834 TInt ll=0; |
|
835 TInt s1=0; |
|
836 TInt r1=0; |
|
837 TBufSegLink *p1=(TBufSegLink *)(&iQue); |
|
838 TBufSegLink *p2=p1->Next(); |
|
839 TUint8 *pR=NULL; |
|
840 if (iSize) |
|
841 { |
|
842 p1=iSeg; |
|
843 if (!iQue.IsHead(p2=p1->Prev()) && ofs==0 && p2->iLen<slen) |
|
844 { |
|
845 iSeg=p1=p2; |
|
846 iOffset=ofs=p1->iLen; |
|
847 iBase-=ofs; |
|
848 } |
|
849 s1=slen-ofs; |
|
850 if (s1>aLength) |
|
851 s1=aLength; |
|
852 TInt r2=slen-p1->iLen; |
|
853 if (aLength>r2) |
|
854 { |
|
855 pR=((TUint8 *)(p1+1))+ofs; |
|
856 r1=aLength-r2; |
|
857 r2=p1->iLen-ofs; |
|
858 if (r1>r2) |
|
859 r1=r2; |
|
860 else |
|
861 pR+=(r2-r1); |
|
862 } |
|
863 p2=p1->Next(); |
|
864 ll=slen-p1->iLen; |
|
865 if (!iQue.IsHead(p2)) |
|
866 ll+=slen-p2->iLen; |
|
867 } |
|
868 TUint8 *pB=((TUint8 *)aPtr)+s1; |
|
869 TInt lrem=aLength-s1; |
|
870 TBufSegLink *pP=p1; |
|
871 if (aLength>ll) |
|
872 {// Need some more segments |
|
873 TInt nseg=(slen-1+aLength-ll)/slen; |
|
874 AllocSegL(p1,nseg); // Could leave |
|
875 while (nseg--) |
|
876 { // Copy into allocated segments |
|
877 pP=pP->Next(); |
|
878 TInt gap=slen; |
|
879 if (lrem<gap) |
|
880 gap=lrem; |
|
881 InsertIntoSegment(pP,0,aPtr==NULL ? NULL : pB,gap); |
|
882 pB+=gap; |
|
883 lrem-=gap; |
|
884 } |
|
885 } |
|
886 if (lrem) |
|
887 { |
|
888 InsertIntoSegment(p2,0,aPtr==NULL ? NULL : pB,lrem); |
|
889 InsertIntoSegment(p2,lrem,pR,r1); |
|
890 } |
|
891 else |
|
892 { |
|
893 TInt r2=0; |
|
894 if (pP!=p1) |
|
895 { |
|
896 r2=slen-pP->iLen; |
|
897 if (r2>r1) |
|
898 r2=r1; |
|
899 } |
|
900 InsertIntoSegment(pP,pP->iLen,pR,r2); // Moved from p1 |
|
901 InsertIntoSegment(p2,0,pR+r2,r1-r2); // Also moved from p1 |
|
902 } |
|
903 p1->iLen-=r1; |
|
904 InsertIntoSegment(p1,ofs,aPtr,s1); |
|
905 iSize+=aLength; |
|
906 } |
|
907 |
|
908 EXPORT_C void CBufSeg::Delete(TInt aPos,TInt aLength) |
|
909 /** |
|
910 Deletes data from the buffer. |
|
911 |
|
912 During deletion, shuffling is minimised by deleting intermediate segments |
|
913 and allowing segments to contain less data than the buffer granularity. |
|
914 |
|
915 @param aPos Buffer position where the deletion will begin; must be in the |
|
916 range zero to (Size() minus the length of the data |
|
917 to be deleted). |
|
918 @param aLength The number of bytes to be deleted. |
|
919 |
|
920 @see CBufBase::Delete |
|
921 */ |
|
922 { |
|
923 |
|
924 if (aLength==0) |
|
925 return; |
|
926 SetSBO(aPos); |
|
927 TInt ofs=iOffset; |
|
928 __ASSERT_ALWAYS((iBase+ofs+aLength)<=iSize,Panic(EBufSegDeleteBeyondEnd)); |
|
929 iSize-=aLength; |
|
930 TBufSegLink *p1=iSeg; |
|
931 TBufSegLink *p2; |
|
932 TInt rem=p1->iLen-ofs; |
|
933 FOREVER |
|
934 { |
|
935 p2=p1->Next(); |
|
936 TInt gap=aLength; |
|
937 if (gap>rem) |
|
938 gap=rem; |
|
939 DeleteFromSegment(p1,ofs,gap); |
|
940 if (p1->iLen==0) |
|
941 { |
|
942 iSeg=NULL; |
|
943 FreeSegment(p1); |
|
944 } |
|
945 p1=p2; |
|
946 if ((aLength-=gap)==0) |
|
947 break; |
|
948 rem=p1->iLen; |
|
949 ofs=0; |
|
950 } |
|
951 if (iSize) |
|
952 { |
|
953 p1=p2->Prev(); |
|
954 if (!iQue.IsHead(p1) && !iQue.IsHead(p2)) |
|
955 { |
|
956 if ((p1->iLen+p2->iLen)<=iExpandSize) |
|
957 { // Join to the right |
|
958 InsertIntoSegment(p1,p1->iLen,p2+1,p2->iLen); |
|
959 FreeSegment(p2); |
|
960 } |
|
961 } |
|
962 } |
|
963 SetSBO(aPos); |
|
964 } |
|
965 |
|
966 EXPORT_C TPtr8 CBufSeg::Ptr(TInt aPos) |
|
967 /** |
|
968 Gets a pointer descriptor to represent the data starting at the specified |
|
969 data byte through to the end of the contiguous region containing that byte. |
|
970 |
|
971 The time needed for calculation of the pointer depends on how many segments |
|
972 there are in the buffer, and how near the target segment is to the segment |
|
973 which was last used in the buffer. |
|
974 |
|
975 @param aPos Buffer position: must be in range zero to Size(). |
|
976 |
|
977 @return Descriptor representing the data starting at aPos to the end of |
|
978 the contiguous region containing that byte. |
|
979 */ |
|
980 { |
|
981 |
|
982 if (iSize==0) |
|
983 return(TPtr8(NULL,0,0)); |
|
984 SetSBO(aPos); |
|
985 TInt len=iSeg->iLen-iOffset; |
|
986 return(TPtr8(((TUint8 *)(iSeg+1))+iOffset,len,len)); |
|
987 } |
|
988 |
|
989 EXPORT_C TPtr8 CBufSeg::BackPtr(TInt aPos) |
|
990 // |
|
991 // Return a pointer to the buffer which has the maximum amount of data |
|
992 // before aPos, and the amount of data remaining. |
|
993 // |
|
994 /** |
|
995 Gets a pointer descriptor to represent the data starting at the beginning |
|
996 of the contiguous region containing that byte through to the byte immediately |
|
997 preceding the specified byte. |
|
998 |
|
999 The descriptor always points to the beginning of the segment containing the |
|
1000 specified byte. The time needed for calculation of the pointer depends on how |
|
1001 many segments there are in the buffer, and how near the target segment is to |
|
1002 the segment which was last used in the buffer. |
|
1003 |
|
1004 @param aPos Buffer position: must be in range zero to Size(). |
|
1005 |
|
1006 @return Descriptor representing the back contiguous region. |
|
1007 |
|
1008 @see CBufBase::BackPtr |
|
1009 */ |
|
1010 |
|
1011 |
|
1012 { |
|
1013 |
|
1014 if (aPos==0) |
|
1015 return(TPtr8(NULL,0,0)); |
|
1016 SetSBO(aPos); |
|
1017 if (iOffset) |
|
1018 return(TPtr8((TUint8 *)(iSeg+1),iOffset,iOffset)); |
|
1019 TBufSegLink *pL=iSeg->Prev(); |
|
1020 TInt len=pL->iLen; |
|
1021 return(TPtr8((TUint8 *)(pL+1),len,len)); |
|
1022 } |
|
1023 |