|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using Microsoft.ML.Runtime;
namespace Microsoft.ML.Internal.Utilities
{
internal static partial class Utils
{
private const int _bulkReadThresholdInBytes = 4096;
public static void CloseEx(this Stream stream)
{
if (stream == null)
return;
stream.Close();
}
public static void CloseEx(this TextWriter writer)
{
if (writer == null)
return;
writer.Close();
}
/// <summary>
/// Similar to Stream.CopyTo but takes a length rather than assuming copy to end. Returns amount copied.
/// </summary>
/// <param name="source">Source stream to copy from</param>
/// <param name="destination">Destination stream to copy to</param>
/// <param name="length">Number of bytes to copy</param>
/// <param name="bufferSize">Size of buffer to use when copying, default is 81920 to match that of Stream</param>
/// <returns>number of bytes copied</returns>
public static long CopyRange(this Stream source, Stream destination, long length, int bufferSize = 81920)
{
// should use ArrayPool once we can take that dependency
byte[] buffer = new byte[bufferSize];
int read;
long remaining = length;
while (remaining != 0 &&
(read = source.Read(buffer, 0, (int)Math.Min(buffer.Length, remaining))) != 0)
{
destination.Write(buffer, 0, read);
remaining -= read;
}
return length - remaining;
}
public static void WriteBoolByte(this BinaryWriter writer, bool x)
{
Contracts.AssertValue(writer);
writer.Write((byte)(x ? 1 : 0));
}
/// <summary>
/// Writes a length prefixed span of ints.
/// </summary>
public static void WriteIntArray(this BinaryWriter writer, ReadOnlySpan<int> values)
{
Contracts.AssertValue(writer);
writer.Write(values.Length);
for (int i = 0; i < values.Length; i++)
writer.Write(values[i]);
}
/// <summary>
/// Writes a span of ints without the length prefix.
/// </summary>
public static void WriteIntsNoCount(this BinaryWriter writer, ReadOnlySpan<int> values)
{
Contracts.AssertValue(writer);
for (int i = 0; i < values.Length; i++)
writer.Write(values[i]);
}
/// <summary>
/// Writes a length prefixed span of uints.
/// </summary>
public static void WriteUIntArray(this BinaryWriter writer, ReadOnlySpan<uint> values)
{
Contracts.AssertValue(writer);
writer.Write(values.Length);
for (int i = 0; i < values.Length; i++)
writer.Write(values[i]);
}
/// <summary>
/// Writes a span of uints without the length prefix.
/// </summary>
public static void WriteUIntsNoCount(this BinaryWriter writer, ReadOnlySpan<uint> values)
{
Contracts.AssertValue(writer);
for (int i = 0; i < values.Length; i++)
writer.Write(values[i]);
}
/// <summary>
/// Writes a length prefixed array of bytes.
/// </summary>
public static void WriteByteArray(this BinaryWriter writer, byte[] values)
{
Contracts.AssertValue(writer);
Contracts.AssertValueOrNull(values);
if (values == null)
{
writer.Write(0);
return;
}
writer.Write(values.Length);
// This method doesn't write the length of the binary array.
writer.Write(values);
}
/// <summary>
/// Writes a length prefixed span of bytes.
/// </summary>
public static void WriteByteArray(this BinaryWriter writer, ReadOnlySpan<byte> values)
{
Contracts.AssertValue(writer);
writer.Write(values.Length);
for (int i = 0; i < values.Length; i++)
writer.Write(values[i]);
}
/// <summary>
/// Writes a length prefixed array of bytes.
/// </summary>
public static void WriteByteArray(this BinaryWriter writer, byte[] values, int count)
{
Contracts.AssertValue(writer);
Contracts.AssertValueOrNull(values);
Contracts.Assert(0 <= count && count <= Utils.Size(values));
writer.Write(count);
writer.Write(values, 0, count);
}
/// <summary>
/// Writes an array of bytes without the length prefix.
/// </summary>
public static void WriteBytesNoCount(this BinaryWriter writer, byte[] values, int count)
{
Contracts.AssertValue(writer);
Contracts.AssertValueOrNull(values);
Contracts.Assert(0 <= count && count <= Utils.Size(values));
writer.Write(values, 0, count);
}
/// <summary>
/// Writes a length prefixed span of Floats.
/// </summary>
public static void WriteSingleArray(this BinaryWriter writer, ReadOnlySpan<float> values)
{
Contracts.AssertValue(writer);
writer.Write(values.Length);
for (int i = 0; i < values.Length; i++)
writer.Write(values[i]);
}
/// <summary>
/// Writes a length prefixed array of Floats.
/// </summary>
public static void WriteSingleArray(this BinaryWriter writer, IEnumerable<float> values, int count)
{
Contracts.AssertValue(writer);
Contracts.AssertValue(values);
writer.Write(count);
int cv = 0;
foreach (var val in values)
{
Contracts.Assert(cv < count);
writer.Write(val);
cv++;
}
Contracts.Assert(cv == count);
}
/// <summary>
/// Writes a span of Floats without the length prefix.
/// </summary>
public static void WriteSinglesNoCount(this BinaryWriter writer, ReadOnlySpan<float> values)
{
Contracts.AssertValue(writer);
for (int i = 0; i < values.Length; i++)
writer.Write(values[i]);
}
/// <summary>
/// Writes a length prefixed span of doubles.
/// </summary>
public static void WriteDoubleArray(this BinaryWriter writer, ReadOnlySpan<double> values)
{
Contracts.AssertValue(writer);
writer.Write(values.Length);
for (int i = 0; i < values.Length; i++)
writer.Write(values[i]);
}
/// <summary>
/// Writes a span of doubles without the length prefix.
/// </summary>
public static void WriteDoublesNoCount(this BinaryWriter writer, ReadOnlySpan<double> values)
{
Contracts.AssertValue(writer);
for (int i = 0; i < values.Length; i++)
writer.Write(values[i]);
}
/// <summary>
/// Writes a length prefixed span of bools as bytes with 0/1 values.
/// </summary>
public static void WriteBoolByteArray(this BinaryWriter writer, ReadOnlySpan<bool> values)
{
Contracts.AssertValue(writer);
writer.Write(values.Length);
for (int i = 0; i < values.Length; i++)
writer.Write(values[i] ? (byte)1 : (byte)0);
}
/// <summary>
/// Writes a span of bools as bytes with 0/1 values, without the length prefix.
/// </summary>
public static void WriteBoolBytesNoCount(this BinaryWriter writer, ReadOnlySpan<bool> values)
{
Contracts.AssertValue(writer);
for (int i = 0; i < values.Length; i++)
writer.Write(values[i] ? (byte)1 : (byte)0);
}
/// <summary>
/// Writes a length prefixed span of chars.
/// </summary>
public static void WriteCharArray(this BinaryWriter writer, ReadOnlySpan<char> values)
{
Contracts.AssertValue(writer);
writer.Write(values.Length);
for (int i = 0; i < values.Length; i++)
writer.Write((short)values[i]);
}
/// <summary>
/// Writes a length prefixed array of packed bits.
/// </summary>
public static void WriteBitArray(this BinaryWriter writer, BitArray arr)
{
var numBits = Utils.Size(arr);
writer.Write(numBits);
if (numBits > 0)
{
var numBytes = (numBits + 7) / 8;
var bytes = new byte[numBytes];
arr.CopyTo(bytes, 0);
writer.Write(bytes, 0, bytes.Length);
}
}
public static long WriteSByteStream(this BinaryWriter writer, IEnumerable<sbyte> e)
{
long c = 0;
foreach (var v in e)
{
writer.Write(v);
c++;
}
return c;
}
public static long WriteByteStream(this BinaryWriter writer, IEnumerable<byte> e)
{
long c = 0;
foreach (var v in e)
{
writer.Write(v);
c++;
}
return c;
}
public static long WriteIntStream(this BinaryWriter writer, IEnumerable<int> e)
{
long c = 0;
foreach (var v in e)
{
writer.Write(v);
c++;
}
return c;
}
public static long WriteUIntStream(this BinaryWriter writer, IEnumerable<uint> e)
{
long c = 0;
foreach (var v in e)
{
writer.Write(v);
c++;
}
return c;
}
public static long WriteShortStream(this BinaryWriter writer, IEnumerable<short> e)
{
long c = 0;
foreach (var v in e)
{
writer.Write(v);
c++;
}
return c;
}
public static long WriteUShortStream(this BinaryWriter writer, IEnumerable<ushort> e)
{
long c = 0;
foreach (var v in e)
{
writer.Write(v);
c++;
}
return c;
}
public static long WriteLongStream(this BinaryWriter writer, IEnumerable<long> e)
{
long c = 0;
foreach (var v in e)
{
writer.Write(v);
c++;
}
return c;
}
public static long WriteULongStream(this BinaryWriter writer, IEnumerable<long> e)
{
long c = 0;
foreach (var v in e)
{
writer.Write(v);
c++;
}
return c;
}
public static long WriteSingleStream(this BinaryWriter writer, IEnumerable<float> e)
{
long c = 0;
foreach (var v in e)
{
writer.Write(v);
c++;
}
return c;
}
public static long WriteDoubleStream(this BinaryWriter writer, IEnumerable<double> e)
{
long c = 0;
foreach (var v in e)
{
writer.Write(v);
c++;
}
return c;
}
public static long WriteStringStream(this BinaryWriter writer, IEnumerable<string> e)
{
long c = 0;
foreach (var v in e)
{
writer.Write(v);
c++;
}
return c;
}
/// <summary>
/// Writes what Microsoft calls a UTF-7 encoded number in the binary reader and
/// writer string methods. For non-negative integers this is equivalent to LEB128
/// (see https://en.wikipedia.org/wiki/LEB128).
/// </summary>
public static void WriteLeb128Int(this BinaryWriter writer, ulong value)
{
// Copied from the internal source code for Write7BitEncodedInt()
while (value >= 0x80)
{
writer.Write((byte)(value | 0x80));
value >>= 7;
}
writer.Write((byte)value);
}
/// <summary>
/// The number of bytes that would be written if one were to attempt to write
/// the value in LEB128.
/// </summary>
public static int Leb128IntLength(ulong value)
{
int len = 1;
while (value >= 0x80)
{
len++;
value >>= 7;
}
return len;
}
public static long FpCur(this BinaryWriter writer)
{
return writer.BaseStream.Position;
}
public static void Seek(this BinaryWriter writer, long fp)
{
writer.BaseStream.Position = fp;
}
public static long FpCur(this BinaryReader reader)
{
return reader.BaseStream.Position;
}
public static void Seek(this BinaryReader reader, long fp)
{
reader.BaseStream.Position = fp;
}
public static bool ReadBoolByte(this BinaryReader reader)
{
byte b = reader.ReadByte();
Contracts.CheckDecode(b <= 1);
return b != 0;
}
public static float ReadFloat(this BinaryReader reader)
{
return reader.ReadSingle();
}
public static float[] ReadFloatArray(this BinaryReader reader)
{
Contracts.AssertValue(reader);
int size = reader.ReadInt32();
Contracts.CheckDecode(size >= 0);
return ReadFloatArray(reader, size);
}
public static float[] ReadFloatArray(this BinaryReader reader, int size)
{
Contracts.AssertValue(reader);
Contracts.Assert(size >= 0);
if (size == 0)
return null;
var values = new float[size];
long bufferSizeInBytes = (long)size * sizeof(float);
if (bufferSizeInBytes < _bulkReadThresholdInBytes)
{
for (int i = 0; i < size; i++)
values[i] = reader.ReadFloat();
}
else
{
unsafe
{
fixed (void* dst = values)
{
ReadBytes(reader, dst, bufferSizeInBytes, bufferSizeInBytes);
}
}
}
return values;
}
public static void ReadFloatArray(this BinaryReader reader, float[] array, int start, int count)
{
Contracts.AssertValue(reader);
Contracts.AssertValue(array);
Contracts.Assert(0 <= start && start < array.Length);
Contracts.Assert(0 < count && count <= array.Length - start);
long bufferReadLengthInBytes = (long)count * sizeof(float);
if (bufferReadLengthInBytes < _bulkReadThresholdInBytes)
{
for (int i = 0; i < count; i++)
array[start + i] = reader.ReadFloat();
}
else
{
unsafe
{
fixed (void* dst = array)
{
long bufferBeginOffsetInBytes = (long)start * sizeof(float);
long bufferSizeInBytes = ((long)array.Length - start) * sizeof(float);
ReadBytes(reader, (byte*)dst + bufferBeginOffsetInBytes, bufferSizeInBytes, bufferReadLengthInBytes);
}
}
}
}
public static float[] ReadSingleArray(this BinaryReader reader)
{
Contracts.AssertValue(reader);
int size = reader.ReadInt32();
Contracts.CheckDecode(size >= 0);
return ReadSingleArray(reader, size);
}
public static float[] ReadSingleArray(this BinaryReader reader, int size)
{
Contracts.AssertValue(reader);
Contracts.Assert(size >= 0);
if (size == 0)
return null;
var values = new float[size];
long bufferSizeInBytes = (long)size * sizeof(float);
if (bufferSizeInBytes < _bulkReadThresholdInBytes)
{
for (int i = 0; i < size; i++)
values[i] = reader.ReadSingle();
}
else
{
unsafe
{
fixed (void* dst = values)
{
ReadBytes(reader, dst, bufferSizeInBytes, bufferSizeInBytes);
}
}
}
return values;
}
public static double[] ReadDoubleArray(this BinaryReader reader)
{
Contracts.AssertValue(reader);
int size = reader.ReadInt32();
Contracts.CheckDecode(size >= 0);
return ReadDoubleArray(reader, size);
}
public static double[] ReadDoubleArray(this BinaryReader reader, int size)
{
Contracts.AssertValue(reader);
Contracts.Assert(size >= 0);
if (size == 0)
return null;
var values = new double[size];
long bufferSizeInBytes = (long)size * sizeof(double);
if (bufferSizeInBytes < _bulkReadThresholdInBytes)
{
for (int i = 0; i < size; i++)
values[i] = reader.ReadDouble();
}
else
{
unsafe
{
fixed (void* dst = values)
{
ReadBytes(reader, dst, bufferSizeInBytes, bufferSizeInBytes);
}
}
}
return values;
}
public static int[] ReadIntArray(this BinaryReader reader)
{
Contracts.AssertValue(reader);
int size = reader.ReadInt32();
Contracts.CheckDecode(size >= 0);
return ReadIntArray(reader, size);
}
public static int[] ReadIntArray(this BinaryReader reader, int size)
{
Contracts.AssertValue(reader);
Contracts.Assert(size >= 0);
if (size == 0)
return null;
var values = new int[size];
long bufferSizeInBytes = (long)size * sizeof(int);
if (bufferSizeInBytes < _bulkReadThresholdInBytes)
{
for (int i = 0; i < size; i++)
values[i] = reader.ReadInt32();
}
else
{
unsafe
{
fixed (void* dst = values)
{
ReadBytes(reader, dst, bufferSizeInBytes, bufferSizeInBytes);
}
}
}
return values;
}
public static uint[] ReadUIntArray(this BinaryReader reader)
{
Contracts.AssertValue(reader);
int size = reader.ReadInt32();
Contracts.CheckDecode(size >= 0);
return ReadUIntArray(reader, size);
}
public static uint[] ReadUIntArray(this BinaryReader reader, int size)
{
Contracts.AssertValue(reader);
Contracts.Assert(size >= 0);
if (size == 0)
return null;
var values = new uint[size];
long bufferSizeInBytes = (long)size * sizeof(uint);
if (bufferSizeInBytes < _bulkReadThresholdInBytes)
{
for (int i = 0; i < size; i++)
values[i] = reader.ReadUInt32();
}
else
{
unsafe
{
fixed (void* dst = values)
{
ReadBytes(reader, dst, bufferSizeInBytes, bufferSizeInBytes);
}
}
}
return values;
}
public static long[] ReadLongArray(this BinaryReader reader)
{
Contracts.AssertValue(reader);
int size = reader.ReadInt32();
Contracts.CheckDecode(size >= 0);
return ReadLongArray(reader, size);
}
public static long[] ReadLongArray(this BinaryReader reader, int size)
{
Contracts.AssertValue(reader);
Contracts.Assert(size >= 0);
if (size == 0)
return null;
var values = new long[size];
long bufferSizeInBytes = (long)size * sizeof(long);
if (bufferSizeInBytes < _bulkReadThresholdInBytes)
{
for (int i = 0; i < size; i++)
values[i] = reader.ReadInt64();
}
else
{
unsafe
{
fixed (void* dst = values)
{
ReadBytes(reader, dst, bufferSizeInBytes, bufferSizeInBytes);
}
}
}
return values;
}
public static bool[] ReadBoolArray(this BinaryReader reader)
{
Contracts.AssertValue(reader);
int size = reader.ReadInt32();
Contracts.CheckDecode(size >= 0);
return ReadBoolArray(reader, size);
}
public static bool[] ReadBoolArray(this BinaryReader reader, int size)
{
Contracts.AssertValue(reader);
Contracts.Assert(size >= 0);
if (size == 0)
return null;
var values = new bool[size];
long bufferSizeInBytes = (long)size * sizeof(bool);
if (bufferSizeInBytes < _bulkReadThresholdInBytes)
{
for (int i = 0; i < size; i++)
{
byte b = reader.ReadByte();
Contracts.CheckDecode(b <= 1);
values[i] = b != 0;
}
}
else
{
unsafe
{
fixed (void* dst = values)
{
ReadBytes(reader, dst, bufferSizeInBytes, bufferSizeInBytes);
for (long i = 0; i < size; i++)
Contracts.CheckDecode(*((byte*)dst + i) <= 1);
}
}
}
return values;
}
public static char[] ReadCharArray(this BinaryReader reader)
{
Contracts.AssertValue(reader);
int size = reader.ReadInt32();
Contracts.CheckDecode(size >= 0);
return ReadCharArray(reader, size);
}
public static char[] ReadCharArray(this BinaryReader reader, int size)
{
Contracts.AssertValue(reader);
Contracts.Assert(size >= 0);
if (size == 0)
return null;
var values = new char[size];
long bufferSizeInBytes = (long)size * sizeof(char);
if (bufferSizeInBytes < _bulkReadThresholdInBytes)
{
for (int i = 0; i < size; i++)
values[i] = (char)reader.ReadInt16();
}
else
{
unsafe
{
fixed (void* dst = values)
{
ReadBytes(reader, dst, bufferSizeInBytes, bufferSizeInBytes);
}
}
}
return values;
}
public static byte[] ReadByteArray(this BinaryReader reader)
{
Contracts.AssertValue(reader);
int size = reader.ReadInt32();
Contracts.CheckDecode(size >= 0);
return ReadByteArray(reader, size);
}
public static byte[] ReadByteArray(this BinaryReader reader, int size)
{
Contracts.AssertValue(reader);
Contracts.Assert(size >= 0);
if (size == 0)
return null;
var bytes = reader.ReadBytes(size);
Contracts.CheckDecode(bytes.Length == size);
return bytes;
}
public static BitArray ReadBitArray(this BinaryReader reader)
{
int numBits = reader.ReadInt32();
Contracts.CheckDecode(numBits >= 0);
if (numBits == 0)
return null;
var numBytes = (numBits + 7) / 8;
var bytes = reader.ReadByteArray(numBytes);
var returnArray = new BitArray(bytes);
returnArray.Length = numBits;
return returnArray;
}
public static unsafe void ReadBytes(this BinaryReader reader, void* destination, long destinationSizeInBytes, long bytesToRead, ref byte[] work)
{
Contracts.AssertValue(reader);
Contracts.Assert(bytesToRead >= 0);
Contracts.Assert(destinationSizeInBytes >= bytesToRead);
Contracts.Assert(destination != null);
Contracts.AssertValueOrNull(work);
// Size our read buffer to 70KB to stay off the LOH.
const int blockSize = 70 * 1024;
int desiredWorkSize = (int)Math.Min(blockSize, bytesToRead);
EnsureSize(ref work, desiredWorkSize);
fixed (void* src = work)
{
long offset = 0;
while (offset < bytesToRead)
{
int toRead = (int)Math.Min(bytesToRead - offset, blockSize);
int read = reader.Read(work, 0, toRead);
Contracts.CheckDecode(read == toRead);
Buffer.MemoryCopy(src, (byte*)destination + offset, destinationSizeInBytes - offset, read);
offset += read;
}
Contracts.Assert(offset == bytesToRead);
}
}
public static unsafe void ReadBytes(this BinaryReader reader, void* destination, long destinationSizeInBytes, long bytesToRead)
{
byte[] work = null;
ReadBytes(reader, destination, destinationSizeInBytes, bytesToRead, ref work);
}
/// <summary>
/// If this return it will read exactly length bytes, and unlike the
/// regular read method fails if it cannot.
/// </summary>
/// <param name="s">The stream</param>
/// <param name="buff">The buffer into which to write the data.</param>
/// <param name="offset">The offset of the output array into which to write.</param>
/// <param name="length">The number of bytes to read.</param>
public static void ReadBlock(this Stream s, byte[] buff, int offset, int length)
{
int pos = 0;
int read;
while (pos != length)
{
read = s.Read(buff, offset + pos, length - pos);
Contracts.CheckIO(read > 0, "Unexpected failure to read");
pos += read;
}
}
/// <summary>
/// If this return it will try to read exactly length bytes.
/// </summary>
/// <param name="s">The stream</param>
/// <param name="buff">The buffer into which to write the data.</param>
/// <param name="offset">The offset of the output array into which to write.</param>
/// <param name="length">The number of bytes to read.</param>
public static int TryReadBlock(this Stream s, byte[] buff, int offset, int length)
{
int pos = 0;
int read = -1;
while (pos != length && read != 0)
{
read = s.Read(buff, offset + pos, length - pos);
pos += read;
}
return pos;
}
/// <summary>
/// Reads a LEB128 encoded unsigned integer.
/// </summary>
public static ulong ReadLeb128Int(this BinaryReader reader)
{
// Copied from the internal source code for Read7BitEncodedInt()
ulong value = 0;
int shift = 0;
byte b;
do
{
// ReadByte handles end of stream cases for us.
b = reader.ReadByte();
if (shift == 9 * 7 && b > 0x01)
throw Contracts.ExceptDecode("LEB128 encoded integer exceeded expected length");
value |= (((ulong)(b & 0x7F)) << shift);
shift += 7;
} while ((b & 0x80) != 0);
return value;
}
private static Encoding _utf8NoBom;
/// <summary>
/// A convenience method to open a stream writer, by default with no-BOM UTF-8 encoding,
/// buffer size of 1K, and the stream left open.
/// </summary>
public static StreamWriter OpenWriter(Stream stream, Encoding encoding = null, int bufferSize = 1024, bool leaveOpen = true)
{
Contracts.CheckValue(stream, nameof(stream));
Contracts.CheckParam(0 < bufferSize, nameof(bufferSize), "buffer size must be positive");
if (encoding == null)
{
// Even though the StreamWriter default encoding is BOM-less UTF8, note
// that Encoding.UTF8 indicates we should write with a BOM!!
if (_utf8NoBom == null)
Interlocked.CompareExchange(ref _utf8NoBom, new UTF8Encoding(false), null);
encoding = _utf8NoBom;
}
return new StreamWriter(stream, encoding, bufferSize: bufferSize, leaveOpen: leaveOpen);
}
#if !CORECLR // REVIEW: Remove this once we're on a .Net version that has it as an instance method.
/// <summary>
/// This extension method assumes that the origin was zero.
/// </summary>
public static bool TryGetBuffer(this MemoryStream mem, out ArraySegment<byte> buffer)
{
try
{
var bytes = mem.GetBuffer();
buffer = new ArraySegment<byte>(bytes, 0, (int)mem.Length);
return true;
}
catch (UnauthorizedAccessException)
{
buffer = default(ArraySegment<byte>);
return false;
}
}
#endif
// REVIEW: need to plumb IExceptionContext into the method.
/// <summary>
/// Checks that the directory of the file name passed in already exists.
/// This is meant to be called before calling an API that creates the file,
/// so the file need not exist.
/// </summary>
/// <param name="file">An absolute or relative file path, or null to skip the check
/// (useful for optional user parameters)</param>
/// <param name="userArgument">The user level parameter name, as exposed by the command line help</param>
public static void CheckOptionalUserDirectory(string file, string userArgument)
{
if (string.IsNullOrWhiteSpace(file))
return;
// We can't check for URI directories.
if (Uri.IsWellFormedUriString(file, UriKind.Absolute))
return;
string dir;
#pragma warning disable MSML_ContractsNameUsesNameof
try
{
// Relative paths are interpreted as local.
dir = Path.GetDirectoryName(Path.GetFullPath(file));
}
catch (NotSupportedException exc)
{
throw Contracts.ExceptUserArg(userArgument, exc.Message);
}
catch (PathTooLongException exc)
{
throw Contracts.ExceptUserArg(userArgument, exc.Message);
}
catch (System.Security.SecurityException exc)
{
throw Contracts.ExceptUserArg(userArgument, exc.Message);
}
if (!Directory.Exists(dir))
throw Contracts.ExceptUserArg(userArgument, "Cannot find directory '{0}'.", dir);
}
#pragma warning restore MSML_ContractsNameUsesNameof
}
}
|