X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FMono.Posix%2FMono.Unix%2FUnixMarshal.cs;h=7b8d8c85cb27f164902ed03be77ecb2bb8ab928f;hb=ace29afea299c410e495c2b8fd11a28bbe51fec7;hp=c9ba832f18dd4212e31e0d3a785605e8120be2e2;hpb=74c2e813151ef52866b58da63aeeed698b5e67dd;p=mono.git diff --git a/mcs/class/Mono.Posix/Mono.Unix/UnixMarshal.cs b/mcs/class/Mono.Posix/Mono.Unix/UnixMarshal.cs index c9ba832f18d..7b8d8c85cb2 100644 --- a/mcs/class/Mono.Posix/Mono.Unix/UnixMarshal.cs +++ b/mcs/class/Mono.Posix/Mono.Unix/UnixMarshal.cs @@ -4,7 +4,7 @@ // Authors: // Jonathan Pryor (jonpryor@vt.edu) // -// (C) 2004 Jonathan Pryor +// (C) 2004-2006 Jonathan Pryor // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -55,7 +55,7 @@ namespace Mono.Unix { // be thread-safe between managed & unmanaged code. internal class ErrorMarshal { - internal delegate string ErrorTranslator (Error errno); + internal delegate string ErrorTranslator (Native.Errno errno); internal static readonly ErrorTranslator Translate; @@ -63,26 +63,26 @@ namespace Mono.Unix { { try { Translate = new ErrorTranslator (strerror_r); - Translate (Error.ERANGE); + Translate (Native.Errno.ERANGE); } - catch (EntryPointNotFoundException e) { + catch (EntryPointNotFoundException) { Translate = new ErrorTranslator (strerror); } } - private static string strerror (Error errno) + private static string strerror (Native.Errno errno) { - return Stdlib.strerror (errno); + return Native.Stdlib.strerror (errno); } - private static string strerror_r (Error errno) + private static string strerror_r (Native.Errno errno) { StringBuilder buf = new StringBuilder (16); int r = 0; do { buf.Capacity *= 2; - r = Syscall.strerror_r (errno, buf); - } while (r == -1 && Stdlib.GetLastError() == Error.ERANGE); + r = Native.Syscall.strerror_r (errno, buf); + } while (r == -1 && Native.Stdlib.GetLastError() == Native.Errno.ERANGE); if (r == -1) return "** Unknown error code: " + ((int) errno) + "**"; @@ -94,37 +94,137 @@ namespace Mono.Unix { { private UnixMarshal () {} - public static string GetErrorDescription (Error errno) + [CLSCompliant (false)] + public static string GetErrorDescription (Native.Errno errno) { return ErrorMarshal.Translate (errno); } - public static IntPtr Alloc (long size) + public static IntPtr AllocHeap (long size) { if (size < 0) throw new ArgumentOutOfRangeException ("size", "< 0"); - return Stdlib.malloc ((ulong) size); + return Native.Stdlib.malloc ((ulong) size); } - public static IntPtr ReAlloc (IntPtr ptr, long size) + public static IntPtr ReAllocHeap (IntPtr ptr, long size) { if (size < 0) throw new ArgumentOutOfRangeException ("size", "< 0"); - return Stdlib.realloc (ptr, (ulong) size); + return Native.Stdlib.realloc (ptr, (ulong) size); } - public static void Free (IntPtr ptr) + public static void FreeHeap (IntPtr ptr) { - Stdlib.free (ptr); + Native.Stdlib.free (ptr); + } + + public static unsafe string PtrToStringUnix (IntPtr p) + { + if (p == IntPtr.Zero) + return null; + + int len = checked ((int) Native.Stdlib.strlen (p)); + return new string ((sbyte*) p, 0, len, UnixEncoding.Instance); } public static string PtrToString (IntPtr p) { - // TODO: deal with character set issues. Will PtrToStringAnsi always - // "Do The Right Thing"? if (p == IntPtr.Zero) return null; - return Marshal.PtrToStringAnsi (p); + return PtrToString (p, UnixEncoding.Instance); + } + + public static unsafe string PtrToString (IntPtr p, Encoding encoding) + { + if (p == IntPtr.Zero) + return null; + + int len = GetStringByteLength (p, encoding); + + // Due to variable-length encoding schemes, GetStringByteLength() may + // have returned multiple "null" characters. (For example, when + // encoding a string into UTF-8 there will be 4 terminating nulls.) + // We don't want these null's to be in the returned string, so strip + // them off. + string s = new string ((sbyte*) p, 0, len, encoding); + len = s.Length; + while (len > 0 && s [len-1] == 0) + --len; + if (len == s.Length) + return s; + return s.Substring (0, len); + } + + private static int GetStringByteLength (IntPtr p, Encoding encoding) + { + Type encodingType = encoding.GetType (); + + int len = -1; + + // Encodings that will always end with a single null byte + if (typeof(UTF8Encoding).IsAssignableFrom (encodingType) || + typeof(UTF7Encoding).IsAssignableFrom (encodingType) || + typeof(UnixEncoding).IsAssignableFrom (encodingType) || + typeof(ASCIIEncoding).IsAssignableFrom (encodingType)) { + len = checked ((int) Native.Stdlib.strlen (p)); + } + // Encodings that will always end with a 0x0000 16-bit word + else if (typeof(UnicodeEncoding).IsAssignableFrom (encodingType)) { + len = GetInt16BufferLength (p); + } + // Some non-public encoding, such as Latin1 or a DBCS charset. + // Look for a sequence of encoding.GetMaxByteCount() bytes that are all + // 0, which should be the terminating null. + // This is "iffy", since it may fail for variable-width encodings; for + // example, UTF8Encoding.GetMaxByteCount(1) = 4, so this would read 3 + // bytes past the end of the string, possibly into garbage memory + // (which is why we special case UTF above). + else { + len = GetRandomBufferLength (p, encoding.GetMaxByteCount(1)); + } + + if (len == -1) + throw new NotSupportedException ("Unable to determine native string buffer length"); + return len; + } + + private static int GetInt16BufferLength (IntPtr p) + { + int len = 0; + while (Marshal.ReadInt16 (p, len*2) != 0) + checked {++len;} + return checked(len*2); + } + + private static int GetInt32BufferLength (IntPtr p) + { + int len = 0; + while (Marshal.ReadInt32 (p, len*4) != 0) + checked {++len;} + return checked(len*4); + } + + private static int GetRandomBufferLength (IntPtr p, int nullLength) + { + switch (nullLength) { + case 1: return checked ((int) Native.Stdlib.strlen (p)); + case 2: return GetInt16BufferLength (p); + case 4: return GetInt32BufferLength (p); + } + + int len = 0; + int num_null_seen = 0; + + do { + byte b = Marshal.ReadByte (p, len++); + if (b == 0) + ++num_null_seen; + else + num_null_seen = 0; + } while (num_null_seen != nullLength); + + return len; } /* @@ -142,12 +242,17 @@ namespace Mono.Unix { * for strings. */ public static string[] PtrToStringArray (IntPtr stringArray) + { + return PtrToStringArray (stringArray, UnixEncoding.Instance); + } + + public static string[] PtrToStringArray (IntPtr stringArray, Encoding encoding) { if (stringArray == IntPtr.Zero) return new string[]{}; int argc = CountStrings (stringArray); - return PtrToStringArray (argc, stringArray); + return PtrToStringArray (argc, stringArray, encoding); } private static int CountStrings (IntPtr stringArray) @@ -168,6 +273,11 @@ namespace Mono.Unix { * argv[argc] = NULL, which PtrToStringArray(IntPtr) requires). */ public static string[] PtrToStringArray (int count, IntPtr stringArray) + { + return PtrToStringArray (count, stringArray, UnixEncoding.Instance); + } + + public static string[] PtrToStringArray (int count, IntPtr stringArray, Encoding encoding) { if (count < 0) throw new ArgumentOutOfRangeException ("count", "< 0"); @@ -177,23 +287,67 @@ namespace Mono.Unix { string[] members = new string[count]; for (int i = 0; i < count; ++i) { IntPtr s = Marshal.ReadIntPtr (stringArray, i * IntPtr.Size); - members[i] = PtrToString (s); + members[i] = PtrToString (s, encoding); } return members; } + public static IntPtr StringToHeap (string s) + { + return StringToHeap (s, UnixEncoding.Instance); + } + + public static IntPtr StringToHeap (string s, Encoding encoding) + { + return StringToHeap (s, 0, s.Length, encoding); + } + + public static IntPtr StringToHeap (string s, int index, int count) + { + return StringToHeap (s, index, count, UnixEncoding.Instance); + } + + public static IntPtr StringToHeap (string s, int index, int count, Encoding encoding) + { + int min_byte_count = encoding.GetMaxByteCount(1); + char[] copy = s.ToCharArray (index, count); + byte[] marshal = new byte [encoding.GetByteCount (copy) + min_byte_count]; + + int bytes_copied = encoding.GetBytes (copy, 0, copy.Length, marshal, 0); + + if (bytes_copied != (marshal.Length-min_byte_count)) + throw new NotSupportedException ("encoding.GetBytes() doesn't equal encoding.GetByteCount()!"); + + IntPtr mem = AllocHeap (marshal.Length); + if (mem == IntPtr.Zero) + throw new OutOfMemoryException (); + + bool copied = false; + try { + Marshal.Copy (marshal, 0, mem, marshal.Length); + copied = true; + } + finally { + if (!copied) + FreeHeap (mem); + } + + return mem; + } + public static bool ShouldRetrySyscall (int r) { - if (r == -1 && Stdlib.GetLastError () == Error.EINTR) + if (r == -1 && Native.Stdlib.GetLastError () == Native.Errno.EINTR) return true; return false; } - public static bool ShouldRetrySyscall (int r, out Error error) + [CLSCompliant (false)] + public static bool ShouldRetrySyscall (int r, out Native.Errno errno) { - error = (Error) 0; - if (r == -1 && (error = Stdlib.GetLastError ()) == Error.EINTR) + errno = (Native.Errno) 0; + if (r == -1 && (errno = Native.Stdlib.GetLastError ()) == Native.Errno.EINTR) return true; return false; } @@ -235,23 +389,41 @@ namespace Mono.Unix { return false; } - internal static Exception CreateExceptionForError (Error errno) + internal static Exception CreateExceptionForError (Native.Errno errno) { string message = GetErrorDescription (errno); UnixIOException p = new UnixIOException (errno); + + // Ordering: Order alphabetically by exception first (right column), + // then order alphabetically by Errno value (left column) for the given + // exception. switch (errno) { - case Error.EFAULT: return new NullReferenceException (message, p); - case Error.EINVAL: return new ArgumentException (message, p); - case Error.EIO: - case Error.ENOSPC: - case Error.EROFS: - case Error.ESPIPE: - return new IOException (message, p); - case Error.ENAMETOOLONG: return new PathTooLongException (message, p); - case Error.ENOENT: return new FileNotFoundException (message, p); - case Error.ENOEXEC: return new InvalidProgramException (message, p); - case Error.EOVERFLOW: return new OverflowException (message, p); - case Error.ERANGE: return new ArgumentOutOfRangeException (message); + case Native.Errno.EBADF: + case Native.Errno.EINVAL: return new ArgumentException (message, p); + + case Native.Errno.ERANGE: return new ArgumentOutOfRangeException (message); + case Native.Errno.ENOTDIR: return new DirectoryNotFoundException (message, p); + case Native.Errno.ENOENT: return new FileNotFoundException (message, p); + + case Native.Errno.EOPNOTSUPP: + case Native.Errno.EPERM: return new InvalidOperationException (message, p); + + case Native.Errno.ENOEXEC: return new InvalidProgramException (message, p); + + case Native.Errno.EIO: + case Native.Errno.ENOSPC: + case Native.Errno.ENOTEMPTY: + case Native.Errno.ENXIO: + case Native.Errno.EROFS: + case Native.Errno.ESPIPE: return new IOException (message, p); + + case Native.Errno.EFAULT: return new NullReferenceException (message, p); + case Native.Errno.EOVERFLOW: return new OverflowException (message, p); + case Native.Errno.ENAMETOOLONG: return new PathTooLongException (message, p); + + case Native.Errno.EACCES: + case Native.Errno.EISDIR: return new UnauthorizedAccessException (message, p); + default: /* ignore */ break; } return p; @@ -259,10 +431,11 @@ namespace Mono.Unix { internal static Exception CreateExceptionForLastError () { - return CreateExceptionForError (Stdlib.GetLastError()); + return CreateExceptionForError (Native.Stdlib.GetLastError()); } - public static void ThrowExceptionForError (Error errno) + [CLSCompliant (false)] + public static void ThrowExceptionForError (Native.Errno errno) { throw CreateExceptionForError (errno); } @@ -272,7 +445,8 @@ namespace Mono.Unix { throw CreateExceptionForLastError (); } - public static void ThrowExceptionForErrorIf (int retval, Error errno) + [CLSCompliant (false)] + public static void ThrowExceptionForErrorIf (int retval, Native.Errno errno) { if (retval == -1) ThrowExceptionForError (errno);