667 lines
24 KiB
C#
667 lines
24 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Reflection;
|
|
using System.Threading;
|
|
#if USE35
|
|
using AspClassic.Scripting.Ast;
|
|
#else
|
|
using System.Linq.Expressions;
|
|
#endif
|
|
|
|
namespace Dlrsoft.VBScript.Runtime
|
|
{
|
|
public class HelperFunctions
|
|
{
|
|
public static object GetDefaultPropertyValue(object target)
|
|
{
|
|
if (target == null) return target;
|
|
|
|
while (target.GetType().IsCOMObject)
|
|
{
|
|
target = target.GetType().InvokeMember(string.Empty,
|
|
BindingFlags.Default | BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.GetProperty,
|
|
null,
|
|
target,
|
|
null);
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
public static object Concatenate(object left, object right)
|
|
{
|
|
bool leftDBNull = false;
|
|
|
|
if (left == null)
|
|
{
|
|
left = String.Empty;
|
|
}
|
|
else if (left is DBNull)
|
|
{
|
|
left = String.Empty;
|
|
leftDBNull = true;
|
|
}
|
|
else
|
|
{
|
|
if (left.GetType().IsCOMObject)
|
|
{
|
|
left = GetDefaultPropertyValue(left);
|
|
}
|
|
|
|
if (!(left is string))
|
|
{
|
|
left = left.ToString();
|
|
}
|
|
}
|
|
|
|
if (right == null)
|
|
{
|
|
right = string.Empty;
|
|
}
|
|
else if (right is DBNull)
|
|
{
|
|
if (leftDBNull) return DBNull.Value;
|
|
right = string.Empty;
|
|
}
|
|
else
|
|
{
|
|
if (right.GetType().IsCOMObject)
|
|
{
|
|
right = GetDefaultPropertyValue(right);
|
|
}
|
|
|
|
if (!(right is string))
|
|
{
|
|
right = right.ToString();
|
|
}
|
|
}
|
|
|
|
return (string)left + (string)right;
|
|
}
|
|
|
|
|
|
|
|
public static object BinaryOp(ExpressionType op, object left, object right)
|
|
{
|
|
if (left == null || right == null)
|
|
{
|
|
if (op == ExpressionType.Equal)
|
|
{
|
|
if (left == null && right == null)
|
|
{
|
|
return true;
|
|
}
|
|
else if (string.Empty.Equals(left) || string.Empty.Equals(right))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else if (op == ExpressionType.NotEqual)
|
|
{
|
|
if (left == null && right == null)
|
|
{
|
|
return false;
|
|
}
|
|
else if (string.Empty.Equals(left) || string.Empty.Equals(right))
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Type ltype = left.GetType();
|
|
Type rtype = right.GetType();
|
|
|
|
if (op == ExpressionType.Equal)
|
|
{
|
|
if (left == right) return true;
|
|
}
|
|
|
|
|
|
if (ltype.IsCOMObject)
|
|
{
|
|
left = GetDefaultPropertyValue(left);
|
|
ltype = left.GetType();
|
|
}
|
|
|
|
if (rtype.IsCOMObject)
|
|
{
|
|
right = GetDefaultPropertyValue(right);
|
|
rtype = right.GetType();
|
|
}
|
|
|
|
if (!ltype.IsValueType && ltype != typeof(string))
|
|
{
|
|
left = left.ToString();
|
|
ltype = typeof(string);
|
|
}
|
|
|
|
if (!rtype.IsValueType && rtype != typeof(string))
|
|
{
|
|
right = right.ToString();
|
|
rtype = typeof(string);
|
|
}
|
|
|
|
Type targetType;
|
|
if (ltype == rtype || CanConvert(rtype, ltype))
|
|
{
|
|
targetType = ltype;
|
|
}
|
|
else
|
|
{
|
|
targetType = rtype;
|
|
}
|
|
|
|
switch (op)
|
|
{
|
|
case ExpressionType.Add:
|
|
if (targetType == typeof(int))
|
|
{
|
|
return Convert.ToInt32(left) + Convert.ToInt32(right);
|
|
}
|
|
else if (targetType == typeof(double))
|
|
{
|
|
return Convert.ToDouble(left) + Convert.ToDouble(right);
|
|
}
|
|
else if (targetType == typeof(long))
|
|
{
|
|
return Convert.ToInt64(left) + Convert.ToInt64(right);
|
|
}
|
|
else if (targetType == typeof(float))
|
|
{
|
|
return Convert.ToSingle(left) + Convert.ToSingle(right);
|
|
}
|
|
else if (targetType == typeof(decimal))
|
|
{
|
|
return Convert.ToDecimal(left) + Convert.ToDecimal(right);
|
|
}
|
|
else if (targetType == typeof(string))
|
|
{
|
|
return (string)left + (string)right;
|
|
}
|
|
break;
|
|
case ExpressionType.Subtract:
|
|
if (targetType == typeof(int))
|
|
{
|
|
return Convert.ToInt32(left) - Convert.ToInt32(right);
|
|
}
|
|
else if (targetType == typeof(double) || targetType == typeof(string))
|
|
{
|
|
return Convert.ToDouble(left) - Convert.ToDouble(right);
|
|
}
|
|
else if (targetType == typeof(long))
|
|
{
|
|
return Convert.ToInt64(left) - Convert.ToInt64(right);
|
|
}
|
|
else if (targetType == typeof(float))
|
|
{
|
|
return Convert.ToSingle(left) - Convert.ToSingle(right);
|
|
}
|
|
else if (targetType == typeof(decimal))
|
|
{
|
|
return Convert.ToDecimal(left) - Convert.ToDecimal(right);
|
|
}
|
|
break;
|
|
case ExpressionType.Multiply:
|
|
if (targetType == typeof(int))
|
|
{
|
|
return Convert.ToInt32(left) * Convert.ToInt32(right);
|
|
}
|
|
else if (targetType == typeof(double) || targetType == typeof(string))
|
|
{
|
|
return Convert.ToDouble(left) * Convert.ToDouble(right);
|
|
}
|
|
else if (targetType == typeof(long))
|
|
{
|
|
return Convert.ToInt64(left) * Convert.ToInt64(right);
|
|
}
|
|
else if (targetType == typeof(float))
|
|
{
|
|
return Convert.ToSingle(left) * Convert.ToSingle(right);
|
|
}
|
|
else if (targetType == typeof(decimal))
|
|
{
|
|
return Convert.ToDecimal(left) * Convert.ToDecimal(right);
|
|
}
|
|
break;
|
|
case ExpressionType.Divide:
|
|
if (targetType == typeof(int))
|
|
{
|
|
return Convert.ToInt32(left) / Convert.ToInt32(right);
|
|
}
|
|
else if (targetType == typeof(double) || targetType == typeof(string))
|
|
{
|
|
return Convert.ToDouble(left) / Convert.ToDouble(right);
|
|
}
|
|
else if (targetType == typeof(long))
|
|
{
|
|
return Convert.ToInt64(left) / Convert.ToInt64(right);
|
|
}
|
|
else if (targetType == typeof(float))
|
|
{
|
|
return Convert.ToSingle(left) / Convert.ToSingle(right);
|
|
}
|
|
else if (targetType == typeof(decimal))
|
|
{
|
|
return Convert.ToDecimal(left) / Convert.ToDecimal(right);
|
|
}
|
|
break;
|
|
case ExpressionType.Equal:
|
|
try
|
|
{
|
|
if (targetType == typeof(int))
|
|
{
|
|
return Convert.ToInt32(left) == Convert.ToInt32(right);
|
|
}
|
|
else if (targetType == typeof(double))
|
|
{
|
|
return Convert.ToDouble(left) == Convert.ToDouble(right);
|
|
}
|
|
else if (targetType == typeof(long))
|
|
{
|
|
return Convert.ToInt64(left) == Convert.ToInt64(right);
|
|
}
|
|
else if (targetType == typeof(float))
|
|
{
|
|
return Convert.ToSingle(left) == Convert.ToSingle(right);
|
|
}
|
|
else if (targetType == typeof(decimal))
|
|
{
|
|
return Convert.ToDecimal(left) == Convert.ToDecimal(right);
|
|
}
|
|
else if (targetType == typeof(string))
|
|
{
|
|
return ((string)left).Equals(right);
|
|
}
|
|
else
|
|
{
|
|
return left == right;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return false;
|
|
}
|
|
case ExpressionType.NotEqual:
|
|
try
|
|
{
|
|
if (targetType == typeof(int))
|
|
{
|
|
return Convert.ToInt32(left) != Convert.ToInt32(right);
|
|
}
|
|
else if (targetType == typeof(double))
|
|
{
|
|
return Convert.ToDouble(left) != Convert.ToDouble(right);
|
|
}
|
|
else if (targetType == typeof(long))
|
|
{
|
|
return Convert.ToInt64(left) != Convert.ToInt64(right);
|
|
}
|
|
else if (targetType == typeof(float))
|
|
{
|
|
return Convert.ToSingle(left) != Convert.ToSingle(right);
|
|
}
|
|
else if (targetType == typeof(decimal))
|
|
{
|
|
return Convert.ToDecimal(left) != Convert.ToDecimal(right);
|
|
}
|
|
else if (targetType == typeof(string))
|
|
{
|
|
return !((string)left).Equals(right);
|
|
}
|
|
else
|
|
{
|
|
return left != right;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
case ExpressionType.GreaterThan:
|
|
if (targetType == typeof(int))
|
|
{
|
|
return Convert.ToInt32(left) > Convert.ToInt32(right);
|
|
}
|
|
else if (targetType == typeof(double))
|
|
{
|
|
return Convert.ToDouble(left) > Convert.ToDouble(right);
|
|
}
|
|
else if (targetType == typeof(long))
|
|
{
|
|
return Convert.ToInt64(left) > Convert.ToInt64(right);
|
|
}
|
|
else if (targetType == typeof(float))
|
|
{
|
|
return Convert.ToSingle(left) > Convert.ToSingle(right);
|
|
}
|
|
else if (targetType == typeof(decimal))
|
|
{
|
|
return Convert.ToDecimal(left) > Convert.ToDecimal(right);
|
|
}
|
|
else if (targetType == typeof(string))
|
|
{
|
|
int result = ((string)left).CompareTo(right);
|
|
return (result > 0);
|
|
}
|
|
break;
|
|
case ExpressionType.GreaterThanOrEqual:
|
|
if (targetType == typeof(int))
|
|
{
|
|
return Convert.ToInt32(left) >= Convert.ToInt32(right);
|
|
}
|
|
else if (targetType == typeof(double))
|
|
{
|
|
return Convert.ToDouble(left) >= Convert.ToDouble(right);
|
|
}
|
|
else if (targetType == typeof(long))
|
|
{
|
|
return Convert.ToInt64(left) >= Convert.ToInt64(right);
|
|
}
|
|
else if (targetType == typeof(float))
|
|
{
|
|
return Convert.ToSingle(left) >= Convert.ToSingle(right);
|
|
}
|
|
else if (targetType == typeof(decimal))
|
|
{
|
|
return Convert.ToDecimal(left) >= Convert.ToDecimal(right);
|
|
}
|
|
else if (targetType == typeof(string))
|
|
{
|
|
int result = ((string)left).CompareTo(right);
|
|
return (result >= 0);
|
|
}
|
|
break;
|
|
case ExpressionType.LessThan:
|
|
if (targetType == typeof(int))
|
|
{
|
|
return Convert.ToInt32(left) < Convert.ToInt32(right);
|
|
}
|
|
else if (targetType == typeof(double))
|
|
{
|
|
return Convert.ToDouble(left) < Convert.ToDouble(right);
|
|
}
|
|
else if (targetType == typeof(long))
|
|
{
|
|
return Convert.ToInt64(left) < Convert.ToInt64(right);
|
|
}
|
|
else if (targetType == typeof(float))
|
|
{
|
|
return Convert.ToSingle(left) < Convert.ToSingle(right);
|
|
}
|
|
else if (targetType == typeof(decimal))
|
|
{
|
|
return Convert.ToDecimal(left) < Convert.ToDecimal(right);
|
|
}
|
|
else if (targetType == typeof(string))
|
|
{
|
|
int result = ((string)left).CompareTo(right);
|
|
return (result < 0);
|
|
}
|
|
break;
|
|
case ExpressionType.LessThanOrEqual:
|
|
if (targetType == typeof(int))
|
|
{
|
|
return Convert.ToInt32(left) <= Convert.ToInt32(right);
|
|
}
|
|
else if (targetType == typeof(double))
|
|
{
|
|
return Convert.ToDouble(left) <= Convert.ToDouble(right);
|
|
}
|
|
else if (targetType == typeof(long))
|
|
{
|
|
return Convert.ToInt64(left) <= Convert.ToInt64(right);
|
|
}
|
|
else if (targetType == typeof(float))
|
|
{
|
|
return Convert.ToSingle(left) <= Convert.ToSingle(right);
|
|
}
|
|
else if (targetType == typeof(decimal))
|
|
{
|
|
return Convert.ToDecimal(left) <= Convert.ToDecimal(right);
|
|
}
|
|
else if (targetType == typeof(string))
|
|
{
|
|
int result = ((string)left).CompareTo(right);
|
|
return (result <= 0);
|
|
}
|
|
break;
|
|
case ExpressionType.And:
|
|
if (targetType == typeof(bool))
|
|
{
|
|
return (bool)left && (bool)right;
|
|
}
|
|
else if (targetType == typeof(int))
|
|
{
|
|
return Convert.ToInt32(left) & Convert.ToInt32(right);
|
|
}
|
|
else if (targetType == typeof(long))
|
|
{
|
|
return Convert.ToInt64(left) & Convert.ToInt64(right);
|
|
}
|
|
else
|
|
{
|
|
return (bool)BuiltInFunctions.CBool(left) && (bool)BuiltInFunctions.CBool(right);
|
|
}
|
|
break;
|
|
case ExpressionType.Or:
|
|
if (targetType == typeof(bool))
|
|
{
|
|
return (bool)left || (bool)right;
|
|
}
|
|
else if (targetType == typeof(int))
|
|
{
|
|
return Convert.ToInt32(left) | Convert.ToInt32(right);
|
|
}
|
|
else if (targetType == typeof(long))
|
|
{
|
|
return Convert.ToInt64(left) | Convert.ToInt64(right);
|
|
}
|
|
else
|
|
{
|
|
return (bool)BuiltInFunctions.CBool(left) || (bool)BuiltInFunctions.CBool(right);
|
|
}
|
|
break;
|
|
}
|
|
throw new ArgumentException(string.Format("Operation {0} between {1} and {2} is not implemeted.", op, ltype.Name, rtype.Name));
|
|
}
|
|
|
|
private static bool CanConvert(Type fromType, Type toType)
|
|
{
|
|
if (toType.IsAssignableFrom(fromType)) return true;
|
|
|
|
if (fromType == typeof(string) && (toType.IsPrimitive))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static object Redim(Type t, params int[] ubounds)
|
|
{
|
|
return redimInternal(t, ubounds);
|
|
}
|
|
|
|
public static Array redimInternal(Type t, params int[] ubounds)
|
|
{
|
|
if (ubounds == null) throw new ArgumentException("Must supply bound(s) when redim an array.");
|
|
for (int i = 0; i < ubounds.Length; i++)
|
|
{
|
|
//Convert from ubound to length
|
|
ubounds[i] += 1;
|
|
}
|
|
|
|
|
|
return Array.CreateInstance(t, ubounds);
|
|
}
|
|
|
|
//public static object RedimPreserve(object array, int length1)
|
|
//{
|
|
// return redimPreserveInternal(array, length1);
|
|
//}
|
|
|
|
//public static object RedimPreserve(object array, int length1, int length2)
|
|
//{
|
|
// return redimPreserveInternal(array, length1, length2);
|
|
//}
|
|
|
|
//public static object RedimPreserve(object array, int length1, int length2, int length3)
|
|
//{
|
|
// return redimPreserveInternal(array, length1, length2, length3);
|
|
//}
|
|
|
|
//public static object RedimPreserve(object array, int length1, int length2, int length3, int length4)
|
|
//{
|
|
// return redimPreserveInternal(array, length1, length2, length3, length4);
|
|
//}
|
|
|
|
//public static object RedimPreserve(object array, int length1, int length2, int length3, int length4, int length5)
|
|
//{
|
|
// return redimPreserveInternal(array, length1, length2, length3, length4, length5);
|
|
//}
|
|
|
|
//public static object RedimPreserve(object array, int length1, int length2, int length3, int length4, int length5, int length6)
|
|
//{
|
|
// return redimPreserveInternal(array, length1, length2, length3, length4, length5, length6);
|
|
//}
|
|
|
|
public static object RedimPreserve(object array, params int[] lengths)
|
|
{
|
|
return redimPreserveInternal(array, lengths);
|
|
}
|
|
|
|
private static Array redimPreserveInternal(object array, params int[] lengths)
|
|
{
|
|
if (array == null) throw new ArgumentException("To redim an array, the array must be a previously declared array.");
|
|
|
|
Type t = array.GetType();
|
|
|
|
if (!t.IsArray) throw new ArgumentException("Redim variable is not an array.");
|
|
|
|
int oldDimension = ((Array)array).Rank;
|
|
int newDimension = lengths.Length;
|
|
|
|
if (oldDimension != newDimension) throw new ArgumentException(string.Format("Cannot change dimension of the array from {0} to {1}", oldDimension, newDimension));
|
|
|
|
int elementsToCopy = 1;
|
|
for (int i = 0; i < oldDimension - 1; i++)
|
|
{
|
|
int oldBound = ((Array)array).GetUpperBound(i);
|
|
if (oldBound != lengths[i])
|
|
throw new ArgumentException(string.Format("Can only resize the last dimension. You are trying to resize dimension {0} from {1} to {2}",
|
|
i + 1, oldBound, lengths[i]));
|
|
|
|
elementsToCopy *= ((Array)array).GetLength(i);
|
|
}
|
|
|
|
elementsToCopy *= (((Array)array).GetLength(oldDimension - 1) < lengths[oldDimension - 1]) ? ((Array)array).GetLength(oldDimension - 1) : lengths[oldDimension - 1];
|
|
|
|
Array newArray = redimInternal(t.GetElementType(), lengths);
|
|
|
|
Array.Copy((Array)array, newArray, elementsToCopy);
|
|
|
|
return newArray;
|
|
}
|
|
|
|
public static void SetError(ErrObject err, Exception ex)
|
|
{
|
|
//Don't catch ThreadAbortException since it is captured by Response.Redirect
|
|
if (ex is ThreadAbortException)
|
|
throw ex;
|
|
|
|
err.internalRaise(ex);
|
|
}
|
|
|
|
public static object Eqv(object left, object right)
|
|
{
|
|
if (left is DBNull || right is DBNull) return DBNull.Value;
|
|
|
|
CheckLogicOperand(ref left);
|
|
CheckLogicOperand(ref right);
|
|
if (left is int) BoolToInt(ref right);
|
|
if (right is int) BoolToInt(ref left);
|
|
|
|
if (left is bool)
|
|
return (bool)left == (bool)right;
|
|
|
|
return ~((int)left ^ (int)right);
|
|
}
|
|
|
|
public static object Imp(object left, object right)
|
|
{
|
|
throw new NotImplementedException("Imp method is not implemented.");
|
|
}
|
|
|
|
public static object Not(object target)
|
|
{
|
|
if (target == null) return null;
|
|
|
|
if (target.GetType().IsCOMObject)
|
|
{
|
|
target = GetDefaultPropertyValue(target);
|
|
}
|
|
|
|
return !(bool)BuiltInFunctions.CBool(target);
|
|
}
|
|
|
|
public static object Negate(object target)
|
|
{
|
|
if (target == null) return null;
|
|
|
|
if (target.GetType().IsCOMObject)
|
|
{
|
|
target = GetDefaultPropertyValue(target);
|
|
}
|
|
|
|
return -(double)BuiltInFunctions.CDbl(target);
|
|
}
|
|
|
|
private static void CheckLogicOperand(ref object value)
|
|
{
|
|
if (value == null) value = 0;
|
|
|
|
if (value is float || value is double)
|
|
{
|
|
value = Convert.ToInt32(value);
|
|
}
|
|
|
|
if (value is string)
|
|
{
|
|
bool boolResult;
|
|
int intResult;
|
|
if (bool.TryParse((string)value, out boolResult))
|
|
{
|
|
value = boolResult;
|
|
}
|
|
else if (int.TryParse((string)value, out intResult))
|
|
{
|
|
value = intResult;
|
|
}
|
|
}
|
|
|
|
if (value is bool || value is int) return;
|
|
|
|
throw new ArgumentException("Logic functions or operators requires arguments that can be converted to bool or int.");
|
|
}
|
|
|
|
private static void BoolToInt(ref object value)
|
|
{
|
|
if (value is bool) value = (bool)value ? -1 : 0;
|
|
}
|
|
}
|
|
}
|