@@ -8,10 +8,10 @@ namespace Adaptive.SimpleBinaryEncoding
88 /// </summary>
99 public sealed unsafe class DirectBuffer : IDisposable
1010 {
11- private readonly byte [ ] _buffer ;
1211 private readonly byte * _pBuffer ;
1312 private bool _disposed ;
1413 private GCHandle _pinnedGCHandle ;
14+ private readonly bool _needToFreeGCHandle ;
1515 private readonly int _capacity ;
1616
1717 /// <summary>
@@ -24,10 +24,25 @@ public DirectBuffer(byte[] byteArray)
2424
2525 // pin the buffer so it does not get moved around by GC, this is required since we use pointers
2626 _pinnedGCHandle = GCHandle . Alloc ( byteArray , GCHandleType . Pinned ) ;
27+ _needToFreeGCHandle = true ;
2728
28- _buffer = byteArray ;
29- _pBuffer = ( byte * ) _pinnedGCHandle . AddrOfPinnedObject ( ) . ToPointer ( ) ;
30- _capacity = _buffer . Length ;
29+ _pBuffer = ( byte * ) _pinnedGCHandle . AddrOfPinnedObject ( ) . ToPointer ( ) ;
30+ _capacity = byteArray . Length ;
31+ }
32+
33+ /// <summary>
34+ /// Constructs a <see cref="DirectBuffer"/> from an unmanaged byte buffer owned by external code
35+ /// </summary>
36+ /// <param name="pBuffer">Unmanaged byte buffer</param>
37+ /// <param name="bufferLength">Length of the buffer</param>
38+ public DirectBuffer ( byte * pBuffer , int bufferLength )
39+ {
40+ if ( pBuffer == null ) throw new ArgumentNullException ( "pBuffer" ) ;
41+ if ( bufferLength < 0 ) throw new ArgumentException ( "Buffer size must be > 0" , "bufferLength" ) ;
42+
43+ _pBuffer = pBuffer ;
44+ _capacity = bufferLength ;
45+ _needToFreeGCHandle = false ;
3146 }
3247
3348 /// <summary>
@@ -38,7 +53,7 @@ public void CheckLimit(int limit)
3853 {
3954 if ( limit > _capacity )
4055 {
41- throw new IndexOutOfRangeException ( string . Format ( "limit={0} is beyond capacity={1}" , limit , _buffer . Length ) ) ;
56+ throw new IndexOutOfRangeException ( string . Format ( "limit={0} is beyond capacity={1}" , limit , _capacity ) ) ;
4257 }
4358 }
4459
@@ -480,7 +495,8 @@ public void DoublePutLittleEndian(int index, double value)
480495 public int GetBytes ( int index , byte [ ] destination , int offsetDestination , int length )
481496 {
482497 int count = Math . Min ( length , _capacity - index ) ;
483- Buffer . BlockCopy ( _buffer , index , destination , offsetDestination , count ) ;
498+ Marshal . Copy ( ( IntPtr ) ( _pBuffer + index ) , destination , offsetDestination , count ) ;
499+
484500 return count ;
485501 }
486502
@@ -495,12 +511,11 @@ public int GetBytes(int index, byte[] destination, int offsetDestination, int le
495511 public int SetBytes ( int index , byte [ ] src , int offset , int length )
496512 {
497513 int count = Math . Min ( length , _capacity - index ) ;
498- Buffer . BlockCopy ( src , offset , _buffer , index , count ) ;
514+ Marshal . Copy ( src , offset , ( IntPtr ) ( _pBuffer + index ) , count ) ;
499515
500516 return count ;
501517 }
502518
503-
504519 /// <summary>
505520 /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
506521 /// </summary>
@@ -521,7 +536,9 @@ private void Dispose(bool disposing)
521536 if ( _disposed )
522537 return ;
523538
524- _pinnedGCHandle . Free ( ) ;
539+ if ( _needToFreeGCHandle )
540+ _pinnedGCHandle . Free ( ) ;
541+
525542 _disposed = true ;
526543 }
527544 }
0 commit comments