/// <summary> /// Reads a single CIL instruction from a given data stream. /// </summary> /// <param name="stream">The source data stream.</param> /// <param name="instruction">The instruction that was read, undefined if the method returns zero.</param> /// <returns>A value indicating if an instruction was read, <c>false</c> if the end of the stream was reached.</returns> public static bool ReadInstruction(Stream stream, out RawInstruction instruction) { Contract.Requires(stream != null && stream.CanRead); int firstOpcodeByte = stream.ReadByte(); if (unchecked ((byte)firstOpcodeByte) != firstOpcodeByte) { instruction = default(RawInstruction); return(false); } OpcodeValue opcodeValue; if (OpcodeValueEnum.IsFirstOfTwoBytes((byte)firstOpcodeByte)) { opcodeValue = (OpcodeValue)((firstOpcodeByte << 8) | stream.ReadUInt8()); } else { opcodeValue = (OpcodeValue)firstOpcodeByte; } var opcode = Opcode.FromValue(opcodeValue); if (opcode == Opcode.Switch) { // Read jump table int[] jumpTable = new int[stream.ReadUInt32()]; for (int i = 0; i < jumpTable.Length; ++i) { jumpTable[i] = stream.ReadInt32(); } instruction = RawInstruction.CreateSwitch(jumpTable); } else { NumericalOperand operand; switch ((int)opcode.OperandKind.GetSizeInBytes()) { case 0: operand = default(NumericalOperand); break; case 1: operand = stream.ReadInt8(); break; case 2: operand = stream.ReadInt16(); break; case 4: operand = stream.ReadInt32(); break; case 8: operand = stream.ReadInt64(); break; default: throw new NotSupportedException("Unexpected opcode operand size"); } instruction = new RawInstruction(opcode, operand); } return(true); }
/// <summary> /// Writes a <c>switch</c> CIL instruction to this sink. /// </summary> /// <param name="jumpTable">The switch's jump table.</param> public void Switch(int[] jumpTable) { Instruction(RawInstruction.CreateSwitch(jumpTable)); }