private void ReadBytecode(Stream input, FunctionDefinition funcDef)
        {
            funcDef.Instructions       = new List <IInstruction>();
            funcDef.InstructionOffsets = new List <int>();
            var unencodedByteCodeLength = input.ReadValueEncodedS32();
            int read;

            for (read = 0; read < unencodedByteCodeLength;)
            {
                funcDef.InstructionOffsets.Add(read);
                var op     = input.ReadValueU8();
                var opcode = (Script.Opcode)op;

                read++;
                Script.IInstruction instruction = null;

                switch (opcode)
                {
                case Script.Opcode.OP_Target:
                {
                    instruction = new Target();
                    break;
                }

                case Script.Opcode.OP_ShortConst:
                {
                    instruction = new ShortConst();
                    break;
                }

                case Script.Opcode.OP_IntConst:
                {
                    instruction = new IntConst();
                    break;
                }

                case Script.Opcode.OP_FloatConst:
                {
                    instruction = new FloatConst();
                    break;
                }

                case Script.Opcode.OP_StringConst:
                {
                    instruction = new StringConst(this);
                    break;
                }

                case Script.Opcode.OP_VirtualFunc:
                {
                    instruction = new VirtualFunc(this);
                    break;
                }

                case Script.Opcode.OP_Context:
                case Script.Opcode.OP_SwitchLabel:
                {
                    instruction = new U16U16(opcode);
                    break;
                }

                case Script.Opcode.OP_Assign:
                case Script.Opcode.OP_JumpIfFalse:
                case Script.Opcode.OP_Jump:
                case Script.Opcode.OP_Skip:
                {
                    instruction = new U16(opcode);
                    break;
                }

                case Script.Opcode.OP_LocalVar:
                case Script.Opcode.OP_ObjectVar:
                case Script.Opcode.OP_ParamVar:
                case Script.Opcode.OP_StructMember:
                {
                    instruction = new TypeMember(opcode, this);
                    break;
                }

                case Script.Opcode.OP_Switch:
                {
                    instruction = new Switch();
                    break;
                }

                case Script.Opcode.OP_Constructor:
                {
                    instruction = new Constructor(this);
                    break;
                }

                case Script.Opcode.OP_TestEqual:
                case Script.Opcode.OP_EnumToInt:
                case Script.Opcode.OP_ArrayPushBack:
                case Script.Opcode.OP_ArraySize:
                case Script.Opcode.OP_ArrayElement:
                case Script.Opcode.OP_New:
                case Script.Opcode.OP_ArrayClear:
                case Script.Opcode.OP_DynamicCast:
                case Script.Opcode.OP_ArrayContainsFast:
                case Script.Opcode.OP_ArrayRemoveFast:
                case Script.Opcode.OP_TestNotEqual:
                case Script.Opcode.OP_ArrayErase:
                case Script.Opcode.OP_EnumToString:
                case Script.Opcode.OP_ArrayContains:
                case Script.Opcode.OP_ArrayResize:
                case Script.Opcode.OP_ArrayInsert:
                case Script.Opcode.OP_ArrayGrow:
                case Script.Opcode.OP_ArrayFindFirstFast:
                case Script.Opcode.OP_ArrayLast:
                case Script.Opcode.OP_ArrayRemove:
                case Script.Opcode.OP_SaveValue:
                {
                    instruction = new TypeRef(opcode, this);
                    break;
                }

                case Script.Opcode.OP_NameConst:
                {
                    instruction = new NameConst(Strings);
                    break;
                }

                case Script.Opcode.OP_FinalFunc:
                {
                    instruction = new FinalFunc(this);
                    break;
                }

                case Script.Opcode.OP_EntryFunc:
                case Script.Opcode.OP_SavePoint:
                {
                    instruction = new U16S32(opcode, this);
                    break;
                }

                case Script.Opcode.OP_Nop:
                case Script.Opcode.OP_ParamEnd:
                case Script.Opcode.OP_IntZero:
                case Script.Opcode.OP_IntOne:
                case Script.Opcode.OP_BoolFalse:
                case Script.Opcode.OP_BoolTrue:
                case Script.Opcode.OP_Return:
                case Script.Opcode.OP_GetServer:
                case Script.Opcode.OP_GetCamera:
                case Script.Opcode.OP_NameToString:
                case Script.Opcode.OP_GetPlayer:
                case Script.Opcode.OP_IntToFloat:
                case Script.Opcode.OP_This:
                case Script.Opcode.OP_Null:
                case Script.Opcode.OP_GetGame:
                case Script.Opcode.OP_ObjectToBool:
                case Script.Opcode.OP_IntToString:
                case Script.Opcode.OP_FloatToString:
                case Script.Opcode.OP_IntToByte:
                case Script.Opcode.OP_ObjectToString:
                case Script.Opcode.OP_SwitchDefault:
                case Script.Opcode.OP_BoolToString:
                case Script.Opcode.OP_GetHud:
                case Script.Opcode.OP_FloatToInt:
                case Script.Opcode.OP_NameToBool:
                case Script.Opcode.OP_Parent:
                case Script.Opcode.OP_IntToBool:
                case Script.Opcode.OP_ByteToInt:
                case Script.Opcode.OP_FloatToBool:
                case Script.Opcode.OP_ByteToFloat:
                case Script.Opcode.OP_StringToBool:
                case Script.Opcode.OP_SavePointEnd:
                case Script.Opcode.OP_StringToInt:
                case Script.Opcode.OP_GetSound:
                {
                    instruction = new Simple(opcode);
                    break;
                }

                default:
                {
                    throw new NotImplementedException("unhandled " + opcode.ToString());
                }
                }
                read += instruction.Deserialize(input);
                funcDef.Instructions.Add(instruction);
            }

            if (read != unencodedByteCodeLength)
            {
                throw new InvalidOperationException();
            }
        }