protected static FileHasher BuildFileHasher(IEnumerable<FormulaOp> ops)
{
Type uint_t = typeof(uint).MakeByRefType();
DynamicMethod method = new DynamicMethod("HashFile", typeof(void),
new Type[] { uint_t, uint_t, uint_t, uint_t, typeof(byte[]) });
MethodInfo touint32 = typeof(BitConverter).GetMethod("ToUInt32");
ILGenerator gen = method.GetILGenerator();
Label start = gen.DefineLabel();
LocalBuilder index = gen.DeclareLocal(typeof(int));
LocalBuilder len = gen.DeclareLocal(typeof(int));
// initialize the loop counter
gen.Emit(OpCodes.Ldc_I4_0);
gen.Emit(OpCodes.Stloc, index);
// load the length of the array into a local
gen.Emit(OpCodes.Ldarg, (short)4);
gen.Emit(OpCodes.Ldlen);
gen.Emit(OpCodes.Conv_I4);
gen.Emit(OpCodes.Stloc, len);
// start of loop across the file
gen.MarkLabel(start);
// load the value of arg4 at index into the address of arg3
gen.Emit(OpCodes.Ldarg_3);
gen.Emit(OpCodes.Ldarg_S, (byte)4);
gen.Emit(OpCodes.Ldloc, index);
gen.EmitCall(OpCodes.Call, touint32, null);
gen.Emit(OpCodes.Stind_I4);
// for each op in the formula...
foreach (var op in ops)
{
// load the result address
gen.Emit(Ldargs[op.Result]);
// load the first value
gen.Emit(Ldargs[op.Variable1]);
gen.Emit(OpCodes.Ldind_U4);
// load the second value
gen.Emit(Ldargs[op.Variable2]);
gen.Emit(OpCodes.Ldind_U4);
// execute the operator
gen.Emit(Operators[op.Operation]);
// store the result in the result address
gen.Emit(OpCodes.Stind_I4);
}
// increment the loop counter
gen.Emit(OpCodes.Ldloc, index);
gen.Emit(OpCodes.Ldc_I4_4);
gen.Emit(OpCodes.Add);
gen.Emit(OpCodes.Stloc, index);
// jump back to the top of the label if the loop counter is less arg4's length
gen.Emit(OpCodes.Ldloc, index);
gen.Emit(OpCodes.Ldloc, len);
gen.Emit(OpCodes.Blt, start);
gen.Emit(OpCodes.Ret);
FileHasher del = (FileHasher)method.CreateDelegate(typeof(FileHasher));
return del;
}