Merge remote branch 'upstream/master'
[mono.git] / mcs / class / corlib / System.Runtime.InteropServices / SafeBuffer.cs
index 54b16f65e26a7bb5722e23c5083db79433b06b5e..0fe9321eb916edda366fb22e5e29b0fe4aeded8f 100644 (file)
@@ -35,27 +35,41 @@ using Microsoft.Win32.SafeHandles;
 
 namespace System.Runtime.InteropServices
 {
-       [CLSCompliant (false)]
        public abstract class SafeBuffer : SafeHandleZeroOrMinusOneIsInvalid, IDisposable {
                ulong byte_length;
+               unsafe byte *last_byte;
                bool inited;
 
-               protected SafeBuffer (bool ownsHandle) : base (ownsHandle) {
+               protected SafeBuffer (bool ownsHandle) : base (ownsHandle)
+               {
                }
 
-               public void Initialize (ulong numBytes) {
-                       byte_length = numBytes;
+               [CLSCompliant (false)]
+               public void Initialize (ulong numBytes)
+               {
+                       if (numBytes == 0)
+                               throw new ArgumentOutOfRangeException ("numBytes");
+
                        inited = true;
+                       byte_length = numBytes;
+                       unsafe {
+                               last_byte = (byte *) (((byte *) handle) + numBytes);
+                       }
                }
 
-               public void Initialize (uint numElements, uint sizeOfEachElement) {
+               [CLSCompliant (false)]
+               public void Initialize (uint numElements, uint sizeOfEachElement)
+               {
                        Initialize (numElements * sizeOfEachElement);
                }
 
-               public void Initialize<T> (uint numElements) where T : struct {
+               [CLSCompliant (false)]
+               public void Initialize<T> (uint numElements) where T : struct
+               {
                        Initialize (numElements, (uint)Marshal.SizeOf (typeof (T)));
                }
 
+               [CLSCompliant (false)]
                public unsafe void AcquirePointer (ref byte* pointer) {
                        if (!inited)
                                throw new InvalidOperationException ();
@@ -72,30 +86,72 @@ namespace System.Runtime.InteropServices
                        DangerousRelease ();
                }
 
+               [CLSCompliant (false)]
                public ulong ByteLength {
                        get {
                                return byte_length;
                        }
                }
 
-               [MonoTODO]
-               public T Read<T> (ulong byteOffset) where T : struct {
-                       throw new NotImplementedException ();
+               [CLSCompliant (false)]
+               public T Read<T> (ulong byteOffset) where T : struct
+               {
+                       if (!inited)
+                               throw new InvalidOperationException ();
+
+                       unsafe {
+                               byte *source = (((byte *) handle) + byteOffset);
+                               if (source >= last_byte || source + Marshal.SizeOf (typeof (T)) > last_byte){
+                                       throw new ArgumentException ("byteOffset");
+                               }
+
+                               return (T) Marshal.PtrToStructure ((IntPtr) source, typeof (T));
+                       }
                }
 
-               [MonoTODO]
+               [CLSCompliant (false)]
                public void ReadArray<T> (ulong byteOffset, T[] array, int index, int count) where T : struct {
-                       throw new NotImplementedException ();
+                       if (!inited)
+                               throw new InvalidOperationException ();
+
+                       unsafe {
+                               int size = Marshal.SizeOf (typeof (T)) * count;
+                               byte *source = (((byte *) handle) + byteOffset);
+                               if (source >= last_byte || source + size > last_byte)
+                                       throw new ArgumentException ("byteOffset");
+                               
+                               Marshal.copy_from_unmanaged ((IntPtr) source, index, array, count);
+                       }
                }
 
-               [MonoTODO]
+               [CLSCompliant (false)]
                public void Write<T> (ulong byteOffset, T value) where T : struct {
-                       throw new NotImplementedException ();
+                       if (!inited)
+                               throw new InvalidOperationException ();
+
+                       unsafe {
+                               byte *target = (((byte *) handle) + byteOffset);
+                               if (target >= last_byte || target + Marshal.SizeOf (typeof (T)) > last_byte)
+                                       throw new ArgumentException ("byteOffset");
+
+                               Marshal.StructureToPtr (value, (IntPtr) target, false);
+                       }
                }
 
-               [MonoTODO]
-               public void WriteArray<T> (ulong byteOffset, T[] array, int index, int count) where T : struct {
-                       throw new NotImplementedException ();
+               [CLSCompliant (false)]
+               public void WriteArray<T> (ulong byteOffset, T[] array, int index, int count) where T : struct
+               {
+                       if (!inited)
+                               throw new InvalidOperationException ();
+
+                       unsafe {
+                               byte *target = ((byte *) handle) + byteOffset;
+                               int size = Marshal.SizeOf (typeof (T)) * count;
+                               if (target >= last_byte || target + size > last_byte)
+                                       throw new ArgumentException ("would overrite");
+                               
+                               Marshal.copy_to_unmanaged (array, index, (IntPtr) target, count);
+                       }
                }
        }
 }