<commit_before>/*
 * Copyright (c) 2007-2008 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#include "arch/x86/regs/misc.hh"
#include "arch/x86/predecoder.hh"
#include "base/misc.hh"
#include "base/trace.hh"
#include "base/types.hh"
#include "cpu/thread_context.hh"
#include "debug/Predecoder.hh"

namespace X86ISA
{
    void Predecoder::doReset()
    {
        origPC = basePC + offset;
        DPRINTF(Predecoder, "Setting origPC to %#x\n", origPC);
        emi.rex = 0;
        emi.legacy = 0;
        emi.opcode.num = 0;
        emi.opcode.op = 0;
        emi.opcode.prefixA = emi.opcode.prefixB = 0;

        immediateCollected = 0;
        emi.immediate = 0;
        emi.displacement = 0;
        emi.dispSize = 0;

        emi.modRM = 0;
        emi.sib = 0;
        m5Reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
        emi.mode.mode = m5Reg.mode;
        emi.mode.submode = m5Reg.submode;
    }

    void Predecoder::process()
    {
        //This function drives the predecoder state machine.

        //Some sanity checks. You shouldn't try to process more bytes if
        //there aren't any, and you shouldn't overwrite an already
        //predecoder ExtMachInst.
        assert(!outOfBytes);
        assert(!emiIsReady);

        //While there's still something to do...
        while(!emiIsReady && !outOfBytes)
        {
            uint8_t nextByte = getNextByte();
            switch(state)
            {
              case ResetState:
                doReset();
                state = PrefixState;
              case PrefixState:
                state = doPrefixState(nextByte);
                break;
              case OpcodeState:
                state = doOpcodeState(nextByte);
                break;
              case ModRMState:
                state = doModRMState(nextByte);
                break;
              case SIBState:
                state = doSIBState(nextByte);
                break;
              case DisplacementState:
                state = doDisplacementState();
                break;
              case ImmediateState:
                state = doImmediateState();
                break;
              case ErrorState:
                panic("Went to the error state in the predecoder.\n");
              default:
                panic("Unrecognized state! %d\n", state);
            }
        }
    }

    //Either get a prefix and record it in the ExtMachInst, or send the
    //state machine on to get the opcode(s).
    Predecoder::State Predecoder::doPrefixState(uint8_t nextByte)
    {
        uint8_t prefix = Prefixes[nextByte];
        State nextState = PrefixState;
        // REX prefixes are only recognized in 64 bit mode.
        if (prefix == RexPrefix && emi.mode.submode != SixtyFourBitMode)
            prefix = 0;
        if (prefix)
            consumeByte();
        switch(prefix)
        {
            //Operand size override prefixes
          case OperandSizeOverride:
            DPRINTF(Predecoder, "Found operand size override prefix.\n");
            emi.legacy.op = true;
            break;
          case AddressSizeOverride:
            DPRINTF(Predecoder, "Found address size override prefix.\n");
            emi.legacy.addr = true;
            break;
            //Segment override prefixes
          case CSOverride:
          case DSOverride:
          case ESOverride:
          case FSOverride:
          case GSOverride:
          case SSOverride:
            DPRINTF(Predecoder, "Found segment override.\n");
            emi.legacy.seg = prefix;
            break;
          case Lock:
            DPRINTF(Predecoder, "Found lock prefix.\n");
            emi.legacy.lock = true;
            break;
          case Rep:
            DPRINTF(Predecoder, "Found rep prefix.\n");
            emi.legacy.rep = true;
            break;
          case Repne:
            DPRINTF(Predecoder, "Found repne prefix.\n");
            emi.legacy.repne = true;
            break;
          case RexPrefix:
            DPRINTF(Predecoder, "Found Rex prefix %#x.\n", nextByte);
            emi.rex = nextByte;
            break;
          case 0:
            nextState = OpcodeState;
            break;
          default:
            panic("Unrecognized prefix %#x\n", nextByte);
        }
        return nextState;
    }

    //Load all the opcodes (currently up to 2) and then figure out
    //what immediate and/or ModRM is needed.
    Predecoder::State Predecoder::doOpcodeState(uint8_t nextByte)
    {
        State nextState = ErrorState;
        emi.opcode.num++;
        //We can't handle 3+ byte opcodes right now
        assert(emi.opcode.num < 4);
        consumeByte();
        if(emi.opcode.num == 1 && nextByte == 0x0f)
        {
            nextState = OpcodeState;
            DPRINTF(Predecoder, "Found two byte opcode.\n");
            emi.opcode.prefixA = nextByte;
        }
        else if(emi.opcode.num == 2 && (nextByte == 0x38 || nextByte == 0x3F))
        {
            nextState = OpcodeState;
            DPRINTF(Predecoder, "Found three byte opcode.\n");
            emi.opcode.prefixB = nextByte;
        }
        else
        {
            DPRINTF(Predecoder, "Found opcode %#x.\n", nextByte);
            emi.opcode.op = nextByte;

            //Figure out the effective operand size. This can be overriden to
            //a fixed value at the decoder level.
            int logOpSize;
            if (emi.rex.w)
                logOpSize = 3; // 64 bit operand size
            else if (emi.legacy.op)
                logOpSize = m5Reg.altOp;
            else
                logOpSize = m5Reg.defOp;

            //Set the actual op size
            emi.opSize = 1 << logOpSize;

            //Figure out the effective address size. This can be overriden to
            //a fixed value at the decoder level.
            int logAddrSize;
            if(emi.legacy.addr)
                logAddrSize = m5Reg.altAddr;
            else
                logAddrSize = m5Reg.defAddr;

            //Set the actual address size
            emi.addrSize = 1 << logAddrSize;

            //Figure out the effective stack width. This can be overriden to
            //a fixed value at the decoder level.
            emi.stackSize = 1 << m5Reg.stack;

            //Figure out how big of an immediate we'll retreive based
            //on the opcode.
            int immType = ImmediateType[emi.opcode.num - 1][nextByte];
            if (emi.opcode.num == 1 && nextByte >= 0xA0 && nextByte <= 0xA3)
                immediateSize = SizeTypeToSize[logAddrSize - 1][immType];
            else
                immediateSize = SizeTypeToSize[logOpSize - 1][immType];

            //Determine what to expect next
            if (UsesModRM[emi.opcode.num - 1][nextByte]) {
                nextState = ModRMState;
            } else {
                if(immediateSize) {
                    nextState = ImmediateState;
                } else {
                    emiIsReady = true;
                    nextState = ResetState;
                }
            }
        }
        return nextState;
    }

    //Get the ModRM byte and determine what displacement, if any, there is.
    //Also determine whether or not to get the SIB byte, displacement, or
    //immediate next.
    Predecoder::State Predecoder::doModRMState(uint8_t nextByte)
    {
        State nextState = ErrorState;
        ModRM modRM;
        modRM = nextByte;
        DPRINTF(Predecoder, "Found modrm byte %#x.\n", nextByte);
        if (m5Reg.defOp == 1) {
            //figure out 16 bit displacement size
            if ((modRM.mod == 0 && modRM.rm == 6) || modRM.mod == 2)
                displacementSize = 2;
            else if (modRM.mod == 1)
                displacementSize = 1;
            else
                displacementSize = 0;
        } else {
            //figure out 32/64 bit displacement size
            if ((modRM.mod == 0 && modRM.rm == 5) || modRM.mod == 2)
                displacementSize = 4;
            else if (modRM.mod == 1)
                displacementSize = 1;
            else
                displacementSize = 0;
        }

        // The "test" instruction in group 3 needs an immediate, even though
        // the other instructions with the same actual opcode don't.
        if (emi.opcode.num == 1 && (modRM.reg & 0x6) == 0) {
           if (emi.opcode.op == 0xF6)
               immediateSize = 1;
           else if (emi.opcode.op == 0xF7)
               immediateSize = (emi.opSize == 8) ? 4 : emi.opSize;
        }

        //If there's an SIB, get that next.
        //There is no SIB in 16 bit mode.
        if (modRM.rm == 4 && modRM.mod != 3) {
                // && in 32/64 bit mode)
            nextState = SIBState;
        } else if(displacementSize) {
            nextState = DisplacementState;
        } else if(immediateSize) {
            nextState = ImmediateState;
        } else {
            emiIsReady = true;
            nextState = ResetState;
        }
        //The ModRM byte is consumed no matter what
        consumeByte();
        emi.modRM = modRM;
        return nextState;
    }

    //Get the SIB byte. We don't do anything with it at this point, other
    //than storing it in the ExtMachInst. Determine if we need to get a
    //displacement or immediate next.
    Predecoder::State Predecoder::doSIBState(uint8_t nextByte)
    {
        State nextState = ErrorState;
        emi.sib = nextByte;
        DPRINTF(Predecoder, "Found SIB byte %#x.\n", nextByte);
        consumeByte();
        if (emi.modRM.mod == 0 && emi.sib.base == 5)
            displacementSize = 4;
        if (displacementSize) {
            nextState = DisplacementState;
        } else if(immediateSize) {
            nextState = ImmediateState;
        } else {
            emiIsReady = true;
            nextState = ResetState;
        }
        return nextState;
    }

    //Gather up the displacement, or at least as much of it
    //as we can get.
    Predecoder::State Predecoder::doDisplacementState()
    {
        State nextState = ErrorState;

        getImmediate(immediateCollected,
                emi.displacement,
                displacementSize);

        DPRINTF(Predecoder, "Collecting %d byte displacement, got %d bytes.\n",
                displacementSize, immediateCollected);

        if(displacementSize == immediateCollected) {
            //Reset this for other immediates.
            immediateCollected = 0;
            //Sign extend the displacement
            switch(displacementSize)
            {
              case 1:
                emi.displacement = sext<8>(emi.displacement);
                break;
              case 2:
                emi.displacement = sext<16>(emi.displacement);
                break;
              case 4:
                emi.displacement = sext<32>(emi.displacement);
                break;
              default:
                panic("Undefined displacement size!\n");
            }
            DPRINTF(Predecoder, "Collected displacement %#x.\n",
                    emi.displacement);
            if(immediateSize) {
                nextState = ImmediateState;
            } else {
                emiIsReady = true;
                nextState = ResetState;
            }

            emi.dispSize = displacementSize;
        }
        else
            nextState = DisplacementState;
        return nextState;
    }

    //Gather up the immediate, or at least as much of it
    //as we can get
    Predecoder::State Predecoder::doImmediateState()
    {
        State nextState = ErrorState;

        getImmediate(immediateCollected,
                emi.immediate,
                immediateSize);

        DPRINTF(Predecoder, "Collecting %d byte immediate, got %d bytes.\n",
                immediateSize, immediateCollected);

        if(immediateSize == immediateCollected)
        {
            //Reset this for other immediates.
            immediateCollected = 0;

            //XXX Warning! The following is an observed pattern and might
            //not always be true!

            //Instructions which use 64 bit operands but 32 bit immediates
            //need to have the immediate sign extended to 64 bits.
            //Instructions which use true 64 bit immediates won't be
            //affected, and instructions that use true 32 bit immediates
            //won't notice.
            switch(immediateSize)
            {
              case 4:
                emi.immediate = sext<32>(emi.immediate);
                break;
              case 1:
                emi.immediate = sext<8>(emi.immediate);
            }

            DPRINTF(Predecoder, "Collected immediate %#x.\n",
                    emi.immediate);
            emiIsReady = true;
            nextState = ResetState;
        }
        else
            nextState = ImmediateState;
        return nextState;
    }
}
<commit_msg>X86: Fix the constant detecting three byte opcodes in the predecoder.<commit_after>/*
 * Copyright (c) 2007-2008 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#include "arch/x86/regs/misc.hh"
#include "arch/x86/predecoder.hh"
#include "base/misc.hh"
#include "base/trace.hh"
#include "base/types.hh"
#include "cpu/thread_context.hh"
#include "debug/Predecoder.hh"

namespace X86ISA
{
    void Predecoder::doReset()
    {
        origPC = basePC + offset;
        DPRINTF(Predecoder, "Setting origPC to %#x\n", origPC);
        emi.rex = 0;
        emi.legacy = 0;
        emi.opcode.num = 0;
        emi.opcode.op = 0;
        emi.opcode.prefixA = emi.opcode.prefixB = 0;

        immediateCollected = 0;
        emi.immediate = 0;
        emi.displacement = 0;
        emi.dispSize = 0;

        emi.modRM = 0;
        emi.sib = 0;
        m5Reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
        emi.mode.mode = m5Reg.mode;
        emi.mode.submode = m5Reg.submode;
    }

    void Predecoder::process()
    {
        //This function drives the predecoder state machine.

        //Some sanity checks. You shouldn't try to process more bytes if
        //there aren't any, and you shouldn't overwrite an already
        //predecoder ExtMachInst.
        assert(!outOfBytes);
        assert(!emiIsReady);

        //While there's still something to do...
        while(!emiIsReady && !outOfBytes)
        {
            uint8_t nextByte = getNextByte();
            switch(state)
            {
              case ResetState:
                doReset();
                state = PrefixState;
              case PrefixState:
                state = doPrefixState(nextByte);
                break;
              case OpcodeState:
                state = doOpcodeState(nextByte);
                break;
              case ModRMState:
                state = doModRMState(nextByte);
                break;
              case SIBState:
                state = doSIBState(nextByte);
                break;
              case DisplacementState:
                state = doDisplacementState();
                break;
              case ImmediateState:
                state = doImmediateState();
                break;
              case ErrorState:
                panic("Went to the error state in the predecoder.\n");
              default:
                panic("Unrecognized state! %d\n", state);
            }
        }
    }

    //Either get a prefix and record it in the ExtMachInst, or send the
    //state machine on to get the opcode(s).
    Predecoder::State Predecoder::doPrefixState(uint8_t nextByte)
    {
        uint8_t prefix = Prefixes[nextByte];
        State nextState = PrefixState;
        // REX prefixes are only recognized in 64 bit mode.
        if (prefix == RexPrefix && emi.mode.submode != SixtyFourBitMode)
            prefix = 0;
        if (prefix)
            consumeByte();
        switch(prefix)
        {
            //Operand size override prefixes
          case OperandSizeOverride:
            DPRINTF(Predecoder, "Found operand size override prefix.\n");
            emi.legacy.op = true;
            break;
          case AddressSizeOverride:
            DPRINTF(Predecoder, "Found address size override prefix.\n");
            emi.legacy.addr = true;
            break;
            //Segment override prefixes
          case CSOverride:
          case DSOverride:
          case ESOverride:
          case FSOverride:
          case GSOverride:
          case SSOverride:
            DPRINTF(Predecoder, "Found segment override.\n");
            emi.legacy.seg = prefix;
            break;
          case Lock:
            DPRINTF(Predecoder, "Found lock prefix.\n");
            emi.legacy.lock = true;
            break;
          case Rep:
            DPRINTF(Predecoder, "Found rep prefix.\n");
            emi.legacy.rep = true;
            break;
          case Repne:
            DPRINTF(Predecoder, "Found repne prefix.\n");
            emi.legacy.repne = true;
            break;
          case RexPrefix:
            DPRINTF(Predecoder, "Found Rex prefix %#x.\n", nextByte);
            emi.rex = nextByte;
            break;
          case 0:
            nextState = OpcodeState;
            break;
          default:
            panic("Unrecognized prefix %#x\n", nextByte);
        }
        return nextState;
    }

    //Load all the opcodes (currently up to 2) and then figure out
    //what immediate and/or ModRM is needed.
    Predecoder::State Predecoder::doOpcodeState(uint8_t nextByte)
    {
        State nextState = ErrorState;
        emi.opcode.num++;
        //We can't handle 3+ byte opcodes right now
        assert(emi.opcode.num < 4);
        consumeByte();
        if(emi.opcode.num == 1 && nextByte == 0x0f)
        {
            nextState = OpcodeState;
            DPRINTF(Predecoder, "Found two byte opcode.\n");
            emi.opcode.prefixA = nextByte;
        }
        else if(emi.opcode.num == 2 && (nextByte == 0x38 || nextByte == 0x3A))
        {
            nextState = OpcodeState;
            DPRINTF(Predecoder, "Found three byte opcode.\n");
            emi.opcode.prefixB = nextByte;
        }
        else
        {
            DPRINTF(Predecoder, "Found opcode %#x.\n", nextByte);
            emi.opcode.op = nextByte;

            //Figure out the effective operand size. This can be overriden to
            //a fixed value at the decoder level.
            int logOpSize;
            if (emi.rex.w)
                logOpSize = 3; // 64 bit operand size
            else if (emi.legacy.op)
                logOpSize = m5Reg.altOp;
            else
                logOpSize = m5Reg.defOp;

            //Set the actual op size
            emi.opSize = 1 << logOpSize;

            //Figure out the effective address size. This can be overriden to
            //a fixed value at the decoder level.
            int logAddrSize;
            if(emi.legacy.addr)
                logAddrSize = m5Reg.altAddr;
            else
                logAddrSize = m5Reg.defAddr;

            //Set the actual address size
            emi.addrSize = 1 << logAddrSize;

            //Figure out the effective stack width. This can be overriden to
            //a fixed value at the decoder level.
            emi.stackSize = 1 << m5Reg.stack;

            //Figure out how big of an immediate we'll retreive based
            //on the opcode.
            int immType = ImmediateType[emi.opcode.num - 1][nextByte];
            if (emi.opcode.num == 1 && nextByte >= 0xA0 && nextByte <= 0xA3)
                immediateSize = SizeTypeToSize[logAddrSize - 1][immType];
            else
                immediateSize = SizeTypeToSize[logOpSize - 1][immType];

            //Determine what to expect next
            if (UsesModRM[emi.opcode.num - 1][nextByte]) {
                nextState = ModRMState;
            } else {
                if(immediateSize) {
                    nextState = ImmediateState;
                } else {
                    emiIsReady = true;
                    nextState = ResetState;
                }
            }
        }
        return nextState;
    }

    //Get the ModRM byte and determine what displacement, if any, there is.
    //Also determine whether or not to get the SIB byte, displacement, or
    //immediate next.
    Predecoder::State Predecoder::doModRMState(uint8_t nextByte)
    {
        State nextState = ErrorState;
        ModRM modRM;
        modRM = nextByte;
        DPRINTF(Predecoder, "Found modrm byte %#x.\n", nextByte);
        if (m5Reg.defOp == 1) {
            //figure out 16 bit displacement size
            if ((modRM.mod == 0 && modRM.rm == 6) || modRM.mod == 2)
                displacementSize = 2;
            else if (modRM.mod == 1)
                displacementSize = 1;
            else
                displacementSize = 0;
        } else {
            //figure out 32/64 bit displacement size
            if ((modRM.mod == 0 && modRM.rm == 5) || modRM.mod == 2)
                displacementSize = 4;
            else if (modRM.mod == 1)
                displacementSize = 1;
            else
                displacementSize = 0;
        }

        // The "test" instruction in group 3 needs an immediate, even though
        // the other instructions with the same actual opcode don't.
        if (emi.opcode.num == 1 && (modRM.reg & 0x6) == 0) {
           if (emi.opcode.op == 0xF6)
               immediateSize = 1;
           else if (emi.opcode.op == 0xF7)
               immediateSize = (emi.opSize == 8) ? 4 : emi.opSize;
        }

        //If there's an SIB, get that next.
        //There is no SIB in 16 bit mode.
        if (modRM.rm == 4 && modRM.mod != 3) {
                // && in 32/64 bit mode)
            nextState = SIBState;
        } else if(displacementSize) {
            nextState = DisplacementState;
        } else if(immediateSize) {
            nextState = ImmediateState;
        } else {
            emiIsReady = true;
            nextState = ResetState;
        }
        //The ModRM byte is consumed no matter what
        consumeByte();
        emi.modRM = modRM;
        return nextState;
    }

    //Get the SIB byte. We don't do anything with it at this point, other
    //than storing it in the ExtMachInst. Determine if we need to get a
    //displacement or immediate next.
    Predecoder::State Predecoder::doSIBState(uint8_t nextByte)
    {
        State nextState = ErrorState;
        emi.sib = nextByte;
        DPRINTF(Predecoder, "Found SIB byte %#x.\n", nextByte);
        consumeByte();
        if (emi.modRM.mod == 0 && emi.sib.base == 5)
            displacementSize = 4;
        if (displacementSize) {
            nextState = DisplacementState;
        } else if(immediateSize) {
            nextState = ImmediateState;
        } else {
            emiIsReady = true;
            nextState = ResetState;
        }
        return nextState;
    }

    //Gather up the displacement, or at least as much of it
    //as we can get.
    Predecoder::State Predecoder::doDisplacementState()
    {
        State nextState = ErrorState;

        getImmediate(immediateCollected,
                emi.displacement,
                displacementSize);

        DPRINTF(Predecoder, "Collecting %d byte displacement, got %d bytes.\n",
                displacementSize, immediateCollected);

        if(displacementSize == immediateCollected) {
            //Reset this for other immediates.
            immediateCollected = 0;
            //Sign extend the displacement
            switch(displacementSize)
            {
              case 1:
                emi.displacement = sext<8>(emi.displacement);
                break;
              case 2:
                emi.displacement = sext<16>(emi.displacement);
                break;
              case 4:
                emi.displacement = sext<32>(emi.displacement);
                break;
              default:
                panic("Undefined displacement size!\n");
            }
            DPRINTF(Predecoder, "Collected displacement %#x.\n",
                    emi.displacement);
            if(immediateSize) {
                nextState = ImmediateState;
            } else {
                emiIsReady = true;
                nextState = ResetState;
            }

            emi.dispSize = displacementSize;
        }
        else
            nextState = DisplacementState;
        return nextState;
    }

    //Gather up the immediate, or at least as much of it
    //as we can get
    Predecoder::State Predecoder::doImmediateState()
    {
        State nextState = ErrorState;

        getImmediate(immediateCollected,
                emi.immediate,
                immediateSize);

        DPRINTF(Predecoder, "Collecting %d byte immediate, got %d bytes.\n",
                immediateSize, immediateCollected);

        if(immediateSize == immediateCollected)
        {
            //Reset this for other immediates.
            immediateCollected = 0;

            //XXX Warning! The following is an observed pattern and might
            //not always be true!

            //Instructions which use 64 bit operands but 32 bit immediates
            //need to have the immediate sign extended to 64 bits.
            //Instructions which use true 64 bit immediates won't be
            //affected, and instructions that use true 32 bit immediates
            //won't notice.
            switch(immediateSize)
            {
              case 4:
                emi.immediate = sext<32>(emi.immediate);
                break;
              case 1:
                emi.immediate = sext<8>(emi.immediate);
            }

            DPRINTF(Predecoder, "Collected immediate %#x.\n",
                    emi.immediate);
            emiIsReady = true;
            nextState = ResetState;
        }
        else
            nextState = ImmediateState;
        return nextState;
    }
}
<|endoftext|>


<commit_before>#line 2 "togo/resource/types.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief Resource types.
@ingroup types
@ingroup resource
*/

#pragma once

#include <togo/config.hpp>
#include <togo/types.hpp>
#include <togo/utility/traits.hpp>
#include <togo/string/types.hpp>
#include <togo/hash/types.hpp>
#include <togo/hash/hash.hpp>
#include <togo/memory/types.hpp>
#include <togo/collection/types.hpp>
#include <togo/io/types.hpp>
#include <togo/io/file_stream.hpp>

namespace togo {

/**
	@addtogroup resource
	@{
*/

/// Format versions.
enum : u32 {
	/// TestResource format version.
	SER_FORMAT_VERSION_TEST_RESOURCE = 1,

	/// ResourcePackage manifest format version.
	SER_FORMAT_VERSION_PKG_MANIFEST = 3,
};

/// Resource type.
using ResourceType = hash32;

/// Resource name hash.
using ResourceNameHash = hash64;

/// Combined resource tags hash.
using ResourceTagsHash = hash64;

/// Combined resource tags hash combiner.
using ResourceTagsHashCombiner = HashCombiner64;

/// Package name hash.
using ResourcePackageNameHash = hash32;

/** @cond INTERNAL */
static_assert(
	is_same<ResourceType, hash32>::value,
	"changed ResourceType type breaks binary formats,"
	" hash functions, and likely other things"
);
static_assert(
	is_same<ResourceNameHash, hash64>::value,
	"changed ResourceNameHash type breaks binary formats,"
	" hash functions, and likely other things"
);
static_assert(
	is_same<ResourceTagsHash, hash64>::value,
	"changed ResourceTagsHash type breaks binary formats,"
	" hash functions, and likely other things"
);
/** @endcond */ // INTERNAL

/// Resource type hash literal.
inline constexpr ResourceType
operator"" _resource_type(
	char const* const data,
	std::size_t const size
) {
	return hash::calc32_ce(data, size);
}

/// Resource name hash literal.
inline constexpr ResourceNameHash
operator"" _resource_name(
	char const* const data,
	std::size_t const size
) {
	return hash::calc64_ce(data, size);
}

/// Combined resource tags hash literal.
///
/// Note that this only takes a single string. Tags should be sorted
/// and separator-less for the return value of this literal to be
/// compatible with the runtime combiner-based hash function.
inline constexpr ResourceTagsHash
operator"" _resource_tags(
	char const* const data,
	std::size_t const size
) {
	return hash::calc64_ce(data, size);
}

/// Package name hash literal.
inline constexpr ResourcePackageNameHash
operator"" _resource_package_name(
	char const* const data,
	std::size_t const size
) {
	return hash::calc32_ce(data, size);
}

/// Resource types.
enum : ResourceType {
	/// Non-type.
	RES_TYPE_NULL = ""_resource_type,

	/// TestResource.
	RES_TYPE_TEST = "test"_resource_type,

	/// gfx::RenderConfig.
	RES_TYPE_RENDER_CONFIG = "render_config"_resource_type,
};

/// Resource names.
enum : ResourceNameHash {
	/// Null name.
	RES_NAME_NULL = ""_resource_name,
};

/// Resource package names.
enum : ResourcePackageNameHash {
	/// Null name.
	PKG_NAME_NULL = ""_resource_package_name,
};

/// Resource path parts.
struct ResourcePathParts {
	struct Tag {
		StringRef name{};
		hash32 hash;
	};

	ResourceType type_hash;
	ResourceNameHash name_hash;
	ResourceTagsHash tags_hash;
	StringRef type{};
	StringRef name{};
	FixedArray<Tag, 8> tags;
};

/// Path to compiled resource.
struct ResourceCompiledPath {
	u32 id;
	FixedArray<char, 24> _data{};

	~ResourceCompiledPath() = default;

	ResourceCompiledPath(ResourceCompiledPath const&) = delete;
	ResourceCompiledPath(ResourceCompiledPath&&) = delete;
	ResourceCompiledPath& operator=(ResourceCompiledPath const&) = delete;
	ResourceCompiledPath& operator=(ResourceCompiledPath&&) = delete;

	ResourceCompiledPath();

	operator StringRef() const;

	u32 size() const;
	char const* data() const;
};

/// Resource metadata.
struct ResourceMetadata {
	u32 id;

	// Serial
	ResourceNameHash name_hash;
	ResourceTagsHash tags_hash;
	ResourceType type;
	u32 data_format_version;
	u32 data_offset;
	u32 data_size;
};

/// Test resource.
struct TestResource {
	s64 x;
};

// Forward declarations
struct ResourceHandler;
struct ResourcePackage;
struct ResourceManager;

/**
	@addtogroup resource_handler
	@{
*/

/// Resource handler.
struct ResourceHandler {
	/// Load a resource.
	///
	/// Returns pointer to resource, or nullptr on error.
	using load_func_type = void* (
		void* /*type_data*/,
		ResourceManager& /*manager*/,
		ResourceNameHash /*name_hash*/,
		IReader& /*stream*/
	);

	/// Unload a resource.
	using unload_func_type = void (
		void* /*type_data*/,
		ResourceManager& /*manager*/,
		ResourceNameHash /*name_hash*/,
		void* /*resource*/
	);

	ResourceType type;
	load_func_type* func_load;
	unload_func_type* func_unload;
};

/** @} */ // end of doc-group resource_handler

/**
	@addtogroup resource_package
	@{
*/

/// Resource package.
struct ResourcePackage {
	using LookupNode = HashMapNode<ResourceNameHash, u32>;

	ResourcePackageNameHash _name_hash;
	u32 _open_resource_id;
	FileReader _stream;
	HashMap<ResourceNameHash, u32> _lookup;
	Array<ResourceMetadata> _manifest;
	FixedArray<char, 48> _name;
	FixedArray<char, 256> _path;

	ResourcePackage() = delete;
	ResourcePackage(ResourcePackage const&) = delete;
	ResourcePackage(ResourcePackage&&) = delete;
	ResourcePackage& operator=(ResourcePackage const&) = delete;
	ResourcePackage& operator=(ResourcePackage&&) = delete;

	~ResourcePackage() = default;

	ResourcePackage(
		StringRef const& name,
		StringRef const& path,
		Allocator& allocator
	);
};

/** @} */ // end of doc-group resource_package

/**
	@addtogroup resource_manager
	@{
*/

/// Resource manager.
struct ResourceManager {
	struct BoundHandler {
		ResourceHandler handler;
		void* type_data;
	};

	struct TypedResource {
		void* value;
		ResourceType type;
	};

	HashMap<ResourceType, BoundHandler> _handlers;
	HashMap<ResourceNameHash, TypedResource> _resources;
	Array<ResourcePackage*> _packages;
	FixedArray<char, 128> _base_path;

	ResourceManager() = delete;
	ResourceManager(ResourceManager const&) = delete;
	ResourceManager(ResourceManager&&) = delete;
	ResourceManager& operator=(ResourceManager const&) = delete;
	ResourceManager& operator=(ResourceManager&&) = delete;

	~ResourceManager();
	ResourceManager(
		StringRef const base_path,
		Allocator& allocator
	);
};

/** @} */ // end of doc-group resource_manager

/** @} */ // end of doc-group resource

} // namespace togo
<commit_msg>resource: added ResourceTagsHash constants.<commit_after>#line 2 "togo/resource/types.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief Resource types.
@ingroup types
@ingroup resource
*/

#pragma once

#include <togo/config.hpp>
#include <togo/types.hpp>
#include <togo/utility/traits.hpp>
#include <togo/string/types.hpp>
#include <togo/hash/types.hpp>
#include <togo/hash/hash.hpp>
#include <togo/memory/types.hpp>
#include <togo/collection/types.hpp>
#include <togo/io/types.hpp>
#include <togo/io/file_stream.hpp>

namespace togo {

/**
	@addtogroup resource
	@{
*/

/// Format versions.
enum : u32 {
	/// TestResource format version.
	SER_FORMAT_VERSION_TEST_RESOURCE = 1,

	/// ResourcePackage manifest format version.
	SER_FORMAT_VERSION_PKG_MANIFEST = 3,
};

/// Resource type.
using ResourceType = hash32;

/// Resource name hash.
using ResourceNameHash = hash64;

/// Combined resource tags hash.
using ResourceTagsHash = hash64;

/// Combined resource tags hash combiner.
using ResourceTagsHashCombiner = HashCombiner64;

/// Package name hash.
using ResourcePackageNameHash = hash32;

/** @cond INTERNAL */
static_assert(
	is_same<ResourceType, hash32>::value,
	"changed ResourceType type breaks binary formats,"
	" hash functions, and likely other things"
);
static_assert(
	is_same<ResourceNameHash, hash64>::value,
	"changed ResourceNameHash type breaks binary formats,"
	" hash functions, and likely other things"
);
static_assert(
	is_same<ResourceTagsHash, hash64>::value,
	"changed ResourceTagsHash type breaks binary formats,"
	" hash functions, and likely other things"
);
/** @endcond */ // INTERNAL

/// Resource type hash literal.
inline constexpr ResourceType
operator"" _resource_type(
	char const* const data,
	std::size_t const size
) {
	return hash::calc32_ce(data, size);
}

/// Resource name hash literal.
inline constexpr ResourceNameHash
operator"" _resource_name(
	char const* const data,
	std::size_t const size
) {
	return hash::calc64_ce(data, size);
}

/// Combined resource tags hash literal.
///
/// Note that this only takes a single string. Tags should be sorted
/// and separator-less for the return value of this literal to be
/// compatible with the runtime combiner-based hash function.
inline constexpr ResourceTagsHash
operator"" _resource_tags(
	char const* const data,
	std::size_t const size
) {
	return hash::calc64_ce(data, size);
}

/// Package name hash literal.
inline constexpr ResourcePackageNameHash
operator"" _resource_package_name(
	char const* const data,
	std::size_t const size
) {
	return hash::calc32_ce(data, size);
}

/// Resource types.
enum : ResourceType {
	/// Non-type.
	RES_TYPE_NULL = ""_resource_type,

	/// TestResource.
	RES_TYPE_TEST = "test"_resource_type,

	/// gfx::RenderConfig.
	RES_TYPE_RENDER_CONFIG = "render_config"_resource_type,
};

/// Resource names.
enum : ResourceNameHash {
	/// Null name.
	RES_NAME_NULL = ""_resource_name,
};

/// Combined resource tags.
enum : ResourceTagsHash {
	/// Null name.
	RES_TAGS_NULL = ""_resource_tags,
};

/// Resource package names.
enum : ResourcePackageNameHash {
	/// Null name.
	PKG_NAME_NULL = ""_resource_package_name,
};

/// Resource path parts.
struct ResourcePathParts {
	struct Tag {
		StringRef name{};
		hash32 hash;
	};

	ResourceType type_hash;
	ResourceNameHash name_hash;
	ResourceTagsHash tags_hash;
	StringRef type{};
	StringRef name{};
	FixedArray<Tag, 8> tags;
};

/// Path to compiled resource.
struct ResourceCompiledPath {
	u32 id;
	FixedArray<char, 24> _data{};

	~ResourceCompiledPath() = default;

	ResourceCompiledPath(ResourceCompiledPath const&) = delete;
	ResourceCompiledPath(ResourceCompiledPath&&) = delete;
	ResourceCompiledPath& operator=(ResourceCompiledPath const&) = delete;
	ResourceCompiledPath& operator=(ResourceCompiledPath&&) = delete;

	ResourceCompiledPath();

	operator StringRef() const;

	u32 size() const;
	char const* data() const;
};

/// Resource metadata.
struct ResourceMetadata {
	u32 id;

	// Serial
	ResourceNameHash name_hash;
	ResourceTagsHash tags_hash;
	ResourceType type;
	u32 data_format_version;
	u32 data_offset;
	u32 data_size;
};

/// Test resource.
struct TestResource {
	s64 x;
};

// Forward declarations
struct ResourceHandler;
struct ResourcePackage;
struct ResourceManager;

/**
	@addtogroup resource_handler
	@{
*/

/// Resource handler.
struct ResourceHandler {
	/// Load a resource.
	///
	/// Returns pointer to resource, or nullptr on error.
	using load_func_type = void* (
		void* /*type_data*/,
		ResourceManager& /*manager*/,
		ResourceNameHash /*name_hash*/,
		IReader& /*stream*/
	);

	/// Unload a resource.
	using unload_func_type = void (
		void* /*type_data*/,
		ResourceManager& /*manager*/,
		ResourceNameHash /*name_hash*/,
		void* /*resource*/
	);

	ResourceType type;
	load_func_type* func_load;
	unload_func_type* func_unload;
};

/** @} */ // end of doc-group resource_handler

/**
	@addtogroup resource_package
	@{
*/

/// Resource package.
struct ResourcePackage {
	using LookupNode = HashMapNode<ResourceNameHash, u32>;

	ResourcePackageNameHash _name_hash;
	u32 _open_resource_id;
	FileReader _stream;
	HashMap<ResourceNameHash, u32> _lookup;
	Array<ResourceMetadata> _manifest;
	FixedArray<char, 48> _name;
	FixedArray<char, 256> _path;

	ResourcePackage() = delete;
	ResourcePackage(ResourcePackage const&) = delete;
	ResourcePackage(ResourcePackage&&) = delete;
	ResourcePackage& operator=(ResourcePackage const&) = delete;
	ResourcePackage& operator=(ResourcePackage&&) = delete;

	~ResourcePackage() = default;

	ResourcePackage(
		StringRef const& name,
		StringRef const& path,
		Allocator& allocator
	);
};

/** @} */ // end of doc-group resource_package

/**
	@addtogroup resource_manager
	@{
*/

/// Resource manager.
struct ResourceManager {
	struct BoundHandler {
		ResourceHandler handler;
		void* type_data;
	};

	struct TypedResource {
		void* value;
		ResourceType type;
	};

	HashMap<ResourceType, BoundHandler> _handlers;
	HashMap<ResourceNameHash, TypedResource> _resources;
	Array<ResourcePackage*> _packages;
	FixedArray<char, 128> _base_path;

	ResourceManager() = delete;
	ResourceManager(ResourceManager const&) = delete;
	ResourceManager(ResourceManager&&) = delete;
	ResourceManager& operator=(ResourceManager const&) = delete;
	ResourceManager& operator=(ResourceManager&&) = delete;

	~ResourceManager();
	ResourceManager(
		StringRef const base_path,
		Allocator& allocator
	);
};

/** @} */ // end of doc-group resource_manager

/** @} */ // end of doc-group resource

} // namespace togo
<|endoftext|>


<commit_before>#include <cmath>

#include "qniteaxes.h"
#include "qniteaxis.h"
#include "qnitemapper.h"
#include "qnitezoompainter.h"
#include "qnitezoomtool.h"

QniteZoomTool::QniteZoomTool(QQuickItem *parent)
    : QniteTool{parent}, m_minZoomFactor{4}, m_pen{new QnitePen} {
  setAcceptedMouseButtons(Qt::RightButton);

  // Default pen style
  m_pen->setFill("#6EDCDCDC");
  m_pen->setStroke("#7E7E7E");
  m_pen->setWidth(1.0);

  connect(this, &QniteZoomTool::axesChanged, this,
          &QniteZoomTool::connectAxesBoundsSignals);

  connect(this, &QniteZoomTool::minZoomFactorChanged, this,
          &QniteZoomTool::updateEnabled);
}

QniteZoomTool::~QniteZoomTool() {}

QNanoQuickItemPainter *QniteZoomTool::createItemPainter() const {
  return new QniteZoomPainter;
}

void QniteZoomTool::reset() {
  auto xAxis = axes()->axisX();
  auto yAxis = axes()->axisY();

  xAxis->setLowerBound(m_baseZoomRect.x());
  xAxis->setUpperBound(m_baseZoomRect.width());
  yAxis->setLowerBound(m_baseZoomRect.y());
  yAxis->setUpperBound(m_baseZoomRect.height());
  setEnabled(true);
  update();
  axes()->updateArtists();
}

void QniteZoomTool::setMinZoomFactor(int factor) {
  if (m_minZoomFactor != factor) {
    m_minZoomFactor = factor;
    emit minZoomFactorChanged();
  }
}

void QniteZoomTool::mousePressEvent(QMouseEvent *event) {
  if (!isEnabled()) {
    return;
  }

  m_zoomRect.setTopLeft(event->pos());
}

void QniteZoomTool::mouseMoveEvent(QMouseEvent *event) {
  if (!isEnabled()) {
    return;
  }

  m_zoomRect.setBottomRight(event->pos());
  update();
}

void QniteZoomTool::mouseReleaseEvent(QMouseEvent *event) {
  if (m_zoomRect.isNull() || event->pos() == m_zoomRect.topLeft()) {
    m_zoomRect = QRectF{};
    return;
  }

  // Calculates new axes bounds and updates them
  auto yMin = qMin(m_zoomRect.top(), m_zoomRect.bottom());
  auto yMax = qMax(m_zoomRect.top(), m_zoomRect.bottom());

  auto yAxis = axes()->axisY();
  auto yMappedMin =
      yAxis->mapper()->mapTo(0, axes()->height(), yAxis->lowerBound(),
                             yAxis->upperBound(), yMin, yAxis->flip());
  auto yMappedMax =
      yAxis->mapper()->mapTo(0, axes()->height(), yAxis->lowerBound(),
                             yAxis->upperBound(), yMax, yAxis->flip());

  auto xMin = qMin(m_zoomRect.left(), m_zoomRect.right());
  auto xMax = qMax(m_zoomRect.left(), m_zoomRect.right());

  auto xAxis = axes()->axisX();
  auto xMappedMin =
      xAxis->mapper()->mapTo(0, axes()->width(), xAxis->lowerBound(),
                             xAxis->upperBound(), xMin, xAxis->flip());

  auto xMappedMax =
      xAxis->mapper()->mapTo(0, axes()->width(), xAxis->lowerBound(),
                             xAxis->upperBound(), xMax, xAxis->flip());

  yAxis->setLowerBound(qMin(yMappedMin, yMappedMax));
  yAxis->setUpperBound(qMax(yMappedMin, yMappedMax));
  xAxis->setLowerBound(qMin(xMappedMin, xMappedMax));
  xAxis->setUpperBound(qMax(xMappedMin, xMappedMax));

  m_zoomRect = QRectF{};

  update();
  axes()->updateArtists();

  // Disables tool if calculated bounds are smaller than the minimum zoom size
  auto minSize = minimumZoomSize();
  auto axisYSize = qAbs(yMappedMin - yMappedMax);
  auto axisXSize = qAbs(xMappedMin - xMappedMax);

  if (axisXSize <= minSize.width() || axisYSize <= minSize.height()) {
    setEnabled(false);
  }
}

void QniteZoomTool::connectAxesBoundsSignals() const {
  connect(axes(), &QniteAxes::xBoundsChanged, this,
          &QniteZoomTool::updateBaseZoomRectXBounds);
  connect(axes(), &QniteAxes::yBoundsChanged, this,
          &QniteZoomTool::updateBaseZoomRectYBounds);
  disconnect(this, &QniteZoomTool::axesChanged, this,
             &QniteZoomTool::connectAxesBoundsSignals);
}

void QniteZoomTool::updateBaseZoomRectXBounds() {
  auto xBounds = axes()->xBounds();
  m_baseZoomRect.setX(xBounds.first());
  m_baseZoomRect.setWidth(xBounds.last());
  disconnect(axes(), &QniteAxes::xBoundsChanged, this,
             &QniteZoomTool::updateBaseZoomRectXBounds);
}

void QniteZoomTool::updateBaseZoomRectYBounds() {
  auto yBounds = axes()->yBounds();
  m_baseZoomRect.setY(yBounds.first());
  m_baseZoomRect.setHeight(yBounds.last());
  disconnect(axes(), &QniteAxes::yBoundsChanged, this,
             &QniteZoomTool::updateBaseZoomRectYBounds);
}

QSizeF QniteZoomTool::minimumZoomSize() const {
  qreal factor = std::pow(10, m_minZoomFactor);
  return {qAbs(m_baseZoomRect.width() / factor),
          qAbs(m_baseZoomRect.height() / factor)};
}

void QniteZoomTool::updateEnabled() {
  // Disables tool if current bounds are smaller than the minimum zoom size,
  // enables it otherwise
  auto axisX = axes()->axisX();
  auto axisY = axes()->axisY();

  auto axisXSize = qAbs(axisX->lowerBound() - axisX->upperBound());
  auto axisYSize = qAbs(axisY->lowerBound() - axisY->upperBound());

  auto minSize = minimumZoomSize();
  auto enable = axisXSize > minSize.width() || axisYSize > minSize.height();
  setEnabled(enable);
}
<commit_msg>Fix padding not applied on zoom reset<commit_after>#include <cmath>

#include "qniteaxes.h"
#include "qniteaxis.h"
#include "qnitemapper.h"
#include "qnitezoompainter.h"
#include "qnitezoomtool.h"

QniteZoomTool::QniteZoomTool(QQuickItem *parent)
    : QniteTool{parent}, m_minZoomFactor{4}, m_pen{new QnitePen} {
  setAcceptedMouseButtons(Qt::RightButton);

  // Default pen style
  m_pen->setFill("#6EDCDCDC");
  m_pen->setStroke("#7E7E7E");
  m_pen->setWidth(1.0);

  connect(this, &QniteZoomTool::axesChanged, this,
          &QniteZoomTool::connectAxesBoundsSignals);

  connect(this, &QniteZoomTool::minZoomFactorChanged, this,
          &QniteZoomTool::updateEnabled);
}

QniteZoomTool::~QniteZoomTool() {}

QNanoQuickItemPainter *QniteZoomTool::createItemPainter() const {
  return new QniteZoomPainter;
}

void QniteZoomTool::reset() {
  auto xAxis = axes()->axisX();
  auto yAxis = axes()->axisY();
  auto xPadding = axes()->xPadding();
  auto yPadding = axes()->yPadding();

  xAxis->setLowerBound(m_baseZoomRect.x() - xPadding);
  xAxis->setUpperBound(m_baseZoomRect.width() + xPadding);
  yAxis->setLowerBound(m_baseZoomRect.y() - yPadding);
  yAxis->setUpperBound(m_baseZoomRect.height() + yPadding);
  setEnabled(true);
  update();
  axes()->updateArtists();
}

void QniteZoomTool::setMinZoomFactor(int factor) {
  if (m_minZoomFactor != factor) {
    m_minZoomFactor = factor;
    emit minZoomFactorChanged();
  }
}

void QniteZoomTool::mousePressEvent(QMouseEvent *event) {
  if (!isEnabled()) {
    return;
  }

  m_zoomRect.setTopLeft(event->pos());
}

void QniteZoomTool::mouseMoveEvent(QMouseEvent *event) {
  if (!isEnabled()) {
    return;
  }

  m_zoomRect.setBottomRight(event->pos());
  update();
}

void QniteZoomTool::mouseReleaseEvent(QMouseEvent *event) {
  if (m_zoomRect.isNull() || event->pos() == m_zoomRect.topLeft()) {
    m_zoomRect = QRectF{};
    return;
  }

  // Calculates new axes bounds and updates them
  auto yMin = qMin(m_zoomRect.top(), m_zoomRect.bottom());
  auto yMax = qMax(m_zoomRect.top(), m_zoomRect.bottom());

  auto yAxis = axes()->axisY();
  auto yMappedMin =
      yAxis->mapper()->mapTo(0, axes()->height(), yAxis->lowerBound(),
                             yAxis->upperBound(), yMin, yAxis->flip());
  auto yMappedMax =
      yAxis->mapper()->mapTo(0, axes()->height(), yAxis->lowerBound(),
                             yAxis->upperBound(), yMax, yAxis->flip());

  auto xMin = qMin(m_zoomRect.left(), m_zoomRect.right());
  auto xMax = qMax(m_zoomRect.left(), m_zoomRect.right());

  auto xAxis = axes()->axisX();
  auto xMappedMin =
      xAxis->mapper()->mapTo(0, axes()->width(), xAxis->lowerBound(),
                             xAxis->upperBound(), xMin, xAxis->flip());

  auto xMappedMax =
      xAxis->mapper()->mapTo(0, axes()->width(), xAxis->lowerBound(),
                             xAxis->upperBound(), xMax, xAxis->flip());

  yAxis->setLowerBound(qMin(yMappedMin, yMappedMax));
  yAxis->setUpperBound(qMax(yMappedMin, yMappedMax));
  xAxis->setLowerBound(qMin(xMappedMin, xMappedMax));
  xAxis->setUpperBound(qMax(xMappedMin, xMappedMax));

  m_zoomRect = QRectF{};

  update();
  axes()->updateArtists();

  // Disables tool if calculated bounds are smaller than the minimum zoom size
  auto minSize = minimumZoomSize();
  auto axisYSize = qAbs(yMappedMin - yMappedMax);
  auto axisXSize = qAbs(xMappedMin - xMappedMax);

  if (axisXSize <= minSize.width() || axisYSize <= minSize.height()) {
    setEnabled(false);
  }
}

void QniteZoomTool::connectAxesBoundsSignals() const {
  connect(axes(), &QniteAxes::xBoundsChanged, this,
          &QniteZoomTool::updateBaseZoomRectXBounds);
  connect(axes(), &QniteAxes::yBoundsChanged, this,
          &QniteZoomTool::updateBaseZoomRectYBounds);
  disconnect(this, &QniteZoomTool::axesChanged, this,
             &QniteZoomTool::connectAxesBoundsSignals);
}

void QniteZoomTool::updateBaseZoomRectXBounds() {
  auto xBounds = axes()->xBounds();
  m_baseZoomRect.setX(xBounds.first());
  m_baseZoomRect.setWidth(xBounds.last());
  disconnect(axes(), &QniteAxes::xBoundsChanged, this,
             &QniteZoomTool::updateBaseZoomRectXBounds);
}

void QniteZoomTool::updateBaseZoomRectYBounds() {
  auto yBounds = axes()->yBounds();
  m_baseZoomRect.setY(yBounds.first());
  m_baseZoomRect.setHeight(yBounds.last());
  disconnect(axes(), &QniteAxes::yBoundsChanged, this,
             &QniteZoomTool::updateBaseZoomRectYBounds);
}

QSizeF QniteZoomTool::minimumZoomSize() const {
  qreal factor = std::pow(10, m_minZoomFactor);
  return {qAbs(m_baseZoomRect.width() / factor),
          qAbs(m_baseZoomRect.height() / factor)};
}

void QniteZoomTool::updateEnabled() {
  // Disables tool if current bounds are smaller than the minimum zoom size,
  // enables it otherwise
  auto axisX = axes()->axisX();
  auto axisY = axes()->axisY();

  auto axisXSize = qAbs(axisX->lowerBound() - axisX->upperBound());
  auto axisYSize = qAbs(axisY->lowerBound() - axisY->upperBound());

  auto minSize = minimumZoomSize();
  auto enable = axisXSize > minSize.width() || axisYSize > minSize.height();
  setEnabled(enable);
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
//  Treap - randomized binary search tree
///////////////////////////////////////////////////////////////////////////////

#include <iostream>
#include <cstdio>
#include <cassert>

using namespace std;

template<class T1, class T2>
ostream& operator << (ostream &out, pair<T1, T2> pair) { return out << "(" << pair.first << ", " << pair.second << ")"; }

typedef long long LL;
typedef pair<int, int> PII;

/*
 * Treap Class Declaration
 *
 * DO NOT FORGET TO CALL SRAND IN MAIN: srand(time(NULL));
 */
template<class T>
class Treap {
    typedef struct Treapnode {
        T key; // (x = key, y = id) can differentiate the duplicate keys
        int fix;
        Treapnode *left, *right;
        int subtree_size;

        LL sum; // sum of all keys
        Treapnode() {
            left = right = NULL;
            subtree_size = 0;
            sum = 0;
        }
    } *Treapnode_ptr;

public:
    Treapnode_ptr root;

    Treap() {
        root = NULL;
    }

    void insert(T key) {
        insert(this->root, key);
    }

    void remove(T key) {
        remove(this->root, key);
    }

    void display() {
        display(this->root, 1);
    }

    bool find(T key) {
        return find(this->root, key);
    }

    T find_ksmallest(int k) {
        assert(k >= 1 && k <= this->root->subtree_size);
        return find_ksmallest(this->root, k);
    }

    LL find_ksmallest_sum(int k) {
        assert(k >= 1 && k <= this->root->subtree_size);
        return find_ksmallest_sum(this->root, k);
    }

private:
    void insert(Treapnode_ptr &node, T key) {
        if (node == NULL) {
            node = new Treapnode();
            node->left = node->right = NULL;
            node->key = key;
            node->fix = rand();
        } else {
            if (node->key == key) {
                // do nothing
            } else if (node->key > key) {
                insert(node->left, key);
                if (node->left->fix > node->fix)
                    rotate_right(node);
            } else {
                insert(node->right, key);
                if (node->right->fix > node->fix)
                    rotate_left(node);
            }
        }
        update_size(node);
        update_sum(node);
    }

    void remove(Treapnode_ptr &node, T key) {
        if (node) {
            if (key > node->key) {
                remove(node->right, key);
                update_size(node);
                update_sum(node);
            } else if (key < node->key) {
                remove(node->left, key);
                update_size(node);
                update_sum(node);
            } else {
                if (node->left == NULL && node->right == NULL) {
                    delete node;
                    node = NULL;
                } else if (node->left == NULL) {
                    Treapnode_ptr temp = node;
                    node = node->right;
                    delete temp;
                } else if (node->right == NULL) {
                    Treapnode_ptr temp = node;
                    node = node->left;
                    delete temp;
                } else {
                    if (node->left->fix < node->right->fix) {
                        rotate_left(node);
                        remove(node->left, key);
                    } else {
                        rotate_right(node);
                        remove(node->right, key);
                    }
                    update_size(node);
                    update_sum(node);
                }
            }
        }
    }

    bool find(Treapnode_ptr node, T key) {
        if (node) {
            if (node->key == key) return true;
            else if (key < node->key) return find(node->left, key);
            else return find(node->right, key);
        }
        return false;
    }

    void rotate_left(Treapnode_ptr &node) {
        Treapnode_ptr temp;
        temp = node->right;
        node->right = temp->left;
        temp->left = node;
        node = temp;
        update_size(node->left);
        update_size(node);
        update_sum(node->left);
        update_sum(node);
    }

    void rotate_right(Treapnode_ptr &node) {
        Treapnode_ptr temp;
        temp = node->left;
        node->left = temp->right;
        temp->right = node;
        node = temp;
        update_size(node->right);
        update_size(node);
        update_sum(node->right);
        update_sum(node);
    }

    void display(Treapnode_ptr node, int level) {
        if (node) {
            display(node->right, level + 1);
            if (node == this->root)
                cout << "Root->: ";
            else
                for (int i = 0; i < level; i++)
                    cout << "\t";
            cout << "key: " << node->key << ", sz: " << node->subtree_size << endl;
            display(node->left, level + 1);
        }
    }

    void update_size(Treapnode_ptr node) {
        node->subtree_size = 1;
        if (node->left) node->subtree_size += node->left->subtree_size;
        if (node->right) node->subtree_size += node->right->subtree_size;
    }

    void update_sum(Treapnode_ptr node) {
        node->sum = node->key.first;
        if (node->left) node->sum += node->left->sum;
        if (node->right) node->sum += node->right->sum;
    }

    T find_ksmallest(Treapnode_ptr node, int k) {
        if (node->left == NULL) {
            if (k == 1)
                return node->key;
            return find_ksmallest(node->right, k - 1);
        } else {
            int num_left = node->left->subtree_size;
            if (k <= num_left)
                return find_ksmallest(node->left, k);
            else if (k == num_left + 1)
                return node->key;
            else
                return find_ksmallest(node->right, k - num_left - 1);
        }
    }

    LL find_ksmallest_sum(Treapnode_ptr node, int k) {
        LL res = 0;
        if (node && k) {
            if (node->left == NULL) {
                if (k == node->subtree_size)
                    res = node->sum;
                else
                    res = node->key.first + find_ksmallest_sum(node->right, k - 1);
            } else {
                int num_left = node->left->subtree_size;
                if (k <= num_left)
                    res = find_ksmallest_sum(node->left, k);
                else if (k == num_left + 1)
                    res = node->key.first + node->left->sum;
                else
                    res = node->key.first + node->left->sum + find_ksmallest_sum(node->right, k - num_left - 1);
            }
        }
        return res;
    }
};

////////////////
//  USAGE
////////////////

int main() {
    srand(time(NULL));
    Treap<PII> tree;
    tree.insert(PII(1, 0));
    tree.insert(PII(5, 0));
    tree.insert(PII(2, 0));
    tree.insert(PII(3, 0));
    tree.insert(PII(10, 0));
    tree.insert(PII(8, 0));
    tree.insert(PII(4, 0));
    tree.insert(PII(7, 0));
    tree.insert(PII(6, 0));
    tree.insert(PII(9, 0));
    tree.display();

    for (int i = 0; i <= 11; i++) cout << tree.find(PII(i, 0)) << endl;

    cout << endl;

    for (int i = 1; i <= 10; i++)
        cout << tree.find_ksmallest(i) << endl;

    cout << endl;
    for (int i = 1; i <= 10; i++)
        cout << tree.find_ksmallest_sum(i) << endl;
    return 0;
}
<commit_msg>Modified Treap.cpp<commit_after>///////////////////////////////////////////////////////////////////////////////
//  Treap - randomized binary search tree
///////////////////////////////////////////////////////////////////////////////

#include <iostream>
#include <cstdio>
#include <cassert>

using namespace std;

template<class T1, class T2>
ostream& operator << (ostream &out, pair<T1, T2> pair) { return out << "(" << pair.first << ", " << pair.second << ")"; }

typedef long long LL;
typedef pair<int, int> PII;

/*
 * Treap Class Declaration
 *
 * DO NOT FORGET TO CALL SRAND IN MAIN: srand(time(NULL));
 */
template<class T>
class Treap {
    typedef struct Treapnode {
        T key; // (x = key, y = id) can differentiate the duplicate keys
        int fix;
        Treapnode *left, *right;
        int subtree_size;

        LL sum; // sum of all keys
        Treapnode() {
            left = right = NULL;
            subtree_size = 0;
            sum = 0;
        }
    } *Treapnode_ptr;

public:
    Treapnode_ptr root;

    Treap() {
        root = NULL;
        srand(time(NULL));
    }

    void insert(T key) {
        insert(this->root, key);
    }

    void remove(T key) {
        remove(this->root, key);
    }

    void display() {
        display(this->root, 1);
    }

    bool find(T key) {
        return find(this->root, key);
    }

    T find_ksmallest(int k) {
        assert(k >= 1 && k <= this->root->subtree_size);
        return find_ksmallest(this->root, k);
    }

    LL find_ksmallest_sum(int k) {
        assert(k >= 1 && k <= this->root->subtree_size);
        return find_ksmallest_sum(this->root, k);
    }

private:
    void insert(Treapnode_ptr &node, T key) {
        if (node == NULL) {
            node = new Treapnode();
            node->left = node->right = NULL;
            node->key = key;
            node->fix = rand();
        } else {
            if (node->key == key) {
                // do nothing
            } else if (node->key > key) {
                insert(node->left, key);
                if (node->left->fix > node->fix)
                    rotate_right(node);
            } else {
                insert(node->right, key);
                if (node->right->fix > node->fix)
                    rotate_left(node);
            }
        }
        update_size(node);
        update_sum(node);
    }

    void remove(Treapnode_ptr &node, T key) {
        if (node) {
            if (key > node->key) {
                remove(node->right, key);
                update_size(node);
                update_sum(node);
            } else if (key < node->key) {
                remove(node->left, key);
                update_size(node);
                update_sum(node);
            } else {
                if (node->left == NULL && node->right == NULL) {
                    delete node;
                    node = NULL;
                } else if (node->left == NULL) {
                    Treapnode_ptr temp = node;
                    node = node->right;
                    delete temp;
                } else if (node->right == NULL) {
                    Treapnode_ptr temp = node;
                    node = node->left;
                    delete temp;
                } else {
                    if (node->left->fix < node->right->fix) {
                        rotate_left(node);
                        remove(node->left, key);
                    } else {
                        rotate_right(node);
                        remove(node->right, key);
                    }
                    update_size(node);
                    update_sum(node);
                }
            }
        }
    }

    bool find(Treapnode_ptr node, T key) {
        if (node) {
            if (node->key == key) return true;
            else if (key < node->key) return find(node->left, key);
            else return find(node->right, key);
        }
        return false;
    }

    void rotate_left(Treapnode_ptr &node) {
        Treapnode_ptr temp;
        temp = node->right;
        node->right = temp->left;
        temp->left = node;
        node = temp;
        update_size(node->left);
        update_size(node);
        update_sum(node->left);
        update_sum(node);
    }

    void rotate_right(Treapnode_ptr &node) {
        Treapnode_ptr temp;
        temp = node->left;
        node->left = temp->right;
        temp->right = node;
        node = temp;
        update_size(node->right);
        update_size(node);
        update_sum(node->right);
        update_sum(node);
    }

    void display(Treapnode_ptr node, int level) {
        if (node) {
            display(node->right, level + 1);
            if (node == this->root)
                cout << "Root->: ";
            else
                for (int i = 0; i < level; i++)
                    cout << "\t";
            cout << "key: " << node->key << ", sz: " << node->subtree_size << endl;
            display(node->left, level + 1);
        }
    }

    void update_size(Treapnode_ptr node) {
        node->subtree_size = 1;
        if (node->left) node->subtree_size += node->left->subtree_size;
        if (node->right) node->subtree_size += node->right->subtree_size;
    }

    void update_sum(Treapnode_ptr node) {
        node->sum = node->key.first;
        if (node->left) node->sum += node->left->sum;
        if (node->right) node->sum += node->right->sum;
    }

    T find_ksmallest(Treapnode_ptr node, int k) {
        if (node->left == NULL) {
            if (k == 1)
                return node->key;
            return find_ksmallest(node->right, k - 1);
        } else {
            int num_left = node->left->subtree_size;
            if (k <= num_left)
                return find_ksmallest(node->left, k);
            else if (k == num_left + 1)
                return node->key;
            else
                return find_ksmallest(node->right, k - num_left - 1);
        }
    }

    LL find_ksmallest_sum(Treapnode_ptr node, int k) {
        LL res = 0;
        if (node && k) {
            if (node->left == NULL) {
                if (k == node->subtree_size)
                    res = node->sum;
                else
                    res = node->key.first + find_ksmallest_sum(node->right, k - 1);
            } else {
                int num_left = node->left->subtree_size;
                if (k <= num_left)
                    res = find_ksmallest_sum(node->left, k);
                else if (k == num_left + 1)
                    res = node->key.first + node->left->sum;
                else
                    res = node->key.first + node->left->sum + find_ksmallest_sum(node->right, k - num_left - 1);
            }
        }
        return res;
    }
};

////////////////
//  USAGE
////////////////

int main() {
    Treap<PII> tree;
    tree.insert(PII(1, 0));
    tree.insert(PII(5, 0));
    tree.insert(PII(2, 0));
    tree.insert(PII(3, 0));
    tree.insert(PII(10, 0));
    tree.insert(PII(8, 0));
    tree.insert(PII(4, 0));
    tree.insert(PII(7, 0));
    tree.insert(PII(6, 0));
    tree.insert(PII(9, 0));
    tree.display();

    for (int i = 0; i <= 11; i++) cout << tree.find(PII(i, 0)) << endl;

    cout << endl;

    for (int i = 1; i <= 10; i++)
        cout << tree.find_ksmallest(i) << endl;

    cout << endl;
    for (int i = 1; i <= 10; i++)
        cout << tree.find_ksmallest_sum(i) << endl;
    return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "aboutdialog.h"
#include "ui_aboutdialog.h"

#include "clientmodel.h"
#include "clientversion.h"

// Copyright year (2009-this)
// Todo: update this when changing our copyright comments in the source
const int ABOUTDIALOG_COPYRIGHT_YEAR = 2014;

AboutDialog::AboutDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AboutDialog)
{
    ui->setupUi(this);

    // Set current copyright year
    ui->copyrightLabel->setText(tr("Copyright") + QString(" © 2009-%1 ").arg(COPYRIGHT_YEAR) + tr("The Bitcoin developers") + QString("
") + tr("Copyright") + QString(" © ") + tr("2011-%1 The Fastcoin developers").arg(ABOUTDIALOG_COPYRIGHT_YEAR));
}

void AboutDialog::setModel(ClientModel *model)
{
    if(model)
    {
        ui->versionLabel->setText(model->formatFullVersion());
    }
}

AboutDialog::~AboutDialog()
{
    delete ui;
}

void AboutDialog::on_buttonBox_accepted()
{
    close();
}
<commit_msg>Fastcoin: update copyright notices (2015)<commit_after>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "aboutdialog.h"
#include "ui_aboutdialog.h"

#include "clientmodel.h"
#include "clientversion.h"

// Copyright year (2009-this)
// Todo: update this when changing our copyright comments in the source
const int ABOUTDIALOG_COPYRIGHT_YEAR = 2015;

AboutDialog::AboutDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AboutDialog)
{
    ui->setupUi(this);

    // Set current copyright year
    ui->copyrightLabel->setText(tr("Copyright") + QString(" © 2009-%1 ").arg(COPYRIGHT_YEAR) + tr("The Bitcoin developers") + QString("
") + tr("Copyright") + QString(" © ") + tr("2011-%1 The Fastcoin developers").arg(ABOUTDIALOG_COPYRIGHT_YEAR));
}

void AboutDialog::setModel(ClientModel *model)
{
    if(model)
    {
        ui->versionLabel->setText(model->formatFullVersion());
    }
}

AboutDialog::~AboutDialog()
{
    delete ui;
}

void AboutDialog::on_buttonBox_accepted()
{
    close();
}
<|endoftext|>


<commit_before>// Copyright 2005-2016 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.

#include "../mumble_plugin_win32_x86.h"

static int fetch(float *avatar_pos, float *avatar_front, float *avatar_top, float *camera_pos, float *camera_front, float *camera_top, std::string &context, std::wstring &identity) {
	for (int i=0;i<3;i++)
		avatar_pos[i]=avatar_front[i]=avatar_top[i]=camera_pos[i]=camera_front[i]=camera_top[i]=0.0f;

	// Boolean value to check if game addresses retrieval is successful
	bool ok;

	// Create containers to stuff our raw data into, so we can convert it to Mumble's coordinate system
	float avatar_pos_corrector[3], camera_pos_corrector[3], avatar_front_corrector[3], camera_front_corrector[3], camera_top_corrector[3];

	// Avatar pointers
	procptr32_t avatar_base = peekProc<procptr32_t>(pModule + 0x016FEC04);
	if (!avatar_base) return false;
	procptr32_t avatar_offset_0 = peekProc<procptr32_t>(avatar_base + 0x448);
	if (!avatar_offset_0) return false;
	procptr32_t avatar_offset_1 = peekProc<procptr32_t>(avatar_offset_0 + 0x440);
	if (!avatar_offset_1) return false;
	procptr32_t avatar_offset_2 = peekProc<procptr32_t>(avatar_offset_1 + 0x0);
	if (!avatar_offset_2) return false;
	procptr32_t avatar_offset = peekProc<procptr32_t>(avatar_offset_2 + 0x1C);
	if (!avatar_offset) return false;

	// Peekproc and assign game addresses to our containers, so we can retrieve positional data
	ok = peekProc(avatar_offset + 0x0, &avatar_pos_corrector, 12) && // Avatar Position values (Z, Y and X).
			peekProc(pModule + 0x016FEE40, &camera_pos_corrector, 12) && // Camera Position values (Z, Y and X).
			peekProc(avatar_offset + 0xC, &avatar_front_corrector, 12) && // Avatar Front values (Z, Y and X).
			peekProc(pModule + 0x016FEE28, &camera_front_corrector, 12) && // Camera Front Vector values (Z, Y and X).
			peekProc(pModule + 0x016FEE34, &camera_top_corrector, 12); // Camera Top Vector values (Z, Y and X).

	// This prevents the plugin from linking to the game in case something goes wrong during values retrieval from memory addresses.
	if (! ok)
		return false;

	/*
	Mumble | Game
	X      | Z
	Y      | Y
	Z      | -X
	*/
	avatar_pos[0] = avatar_pos_corrector[2];
	avatar_pos[1] = avatar_pos_corrector[1];
	avatar_pos[2] = -avatar_pos_corrector[0]; // Convert from right handed to left handed coordinate system

	camera_pos[0] = camera_pos_corrector[2];
	camera_pos[1] = camera_pos_corrector[1];
	camera_pos[2] = -camera_pos_corrector[0]; // Convert from right handed to left handed coordinate system

	avatar_front[0] = avatar_front_corrector[2];
	avatar_front[1] = avatar_front_corrector[1];
	avatar_front[2] = avatar_front_corrector[0];

	avatar_top[2] = -1; // This tells Mumble to automatically calculate top vector using front vector.

	camera_front[0] = camera_front_corrector[2];
	camera_front[1] = camera_front_corrector[1];
	camera_front[2] = camera_front_corrector[0];

	camera_top[0] = camera_top_corrector[2];
	camera_top[1] = camera_top_corrector[1];
	camera_top[2] = camera_top_corrector[0];

	// Scale from centimeters to meters
	for (int i=0;i<3;i++) {
		avatar_pos[i]/=100.0f;
		camera_pos[i]/=100.0f;
	}

	return true;
}

static int trylock(const std::multimap<std::wstring, unsigned long long int> &pids) {

	if (! initialize(pids, L"RocketLeague.exe")) // Link the game executable
		return false;

	// Check if we can get meaningful data from it
	float apos[3], afront[3], atop[3], cpos[3], cfront[3], ctop[3];
	std::wstring sidentity;
	std::string scontext;

	if (fetch(apos, afront, atop, cpos, cfront, ctop, scontext, sidentity)) {
		return true;
	} else {
		generic_unlock();
		return false;
	}
}

static const std::wstring longdesc() {
	return std::wstring(L"Supports Rocket League version 1.18 without context or identity support yet."); // Plugin long description
}

static std::wstring description(L"Rocket League (v1.18)"); // Plugin short description
static std::wstring shortname(L"Rocket League"); // Plugin short name

static int trylock1() {
	return trylock(std::multimap<std::wstring, unsigned long long int>());
}

static MumblePlugin rlplug = {
	MUMBLE_PLUGIN_MAGIC,
	description,
	shortname,
	NULL,
	NULL,
	trylock1,
	generic_unlock,
	longdesc,
	fetch
};

static MumblePlugin2 rlplug2 = {
	MUMBLE_PLUGIN_MAGIC_2,
	MUMBLE_PLUGIN_VERSION,
	trylock
};

extern "C" __declspec(dllexport) MumblePlugin *getMumblePlugin() {
	return &rlplug;
}

extern "C" __declspec(dllexport) MumblePlugin2 *getMumblePlugin2() {
	return &rlplug2;
}
<commit_msg>plugins/rl: Plugin update for game's latest version<commit_after>// Copyright 2005-2016 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.

#include "../mumble_plugin_win32_x86.h"

static int fetch(float *avatar_pos, float *avatar_front, float *avatar_top, float *camera_pos, float *camera_front, float *camera_top, std::string &context, std::wstring &identity) {
	for (int i=0;i<3;i++)
		avatar_pos[i]=avatar_front[i]=avatar_top[i]=camera_pos[i]=camera_front[i]=camera_top[i]=0.0f;

	// Boolean value to check if game addresses retrieval is successful
	bool ok;

	// Avatar pointers
	procptr32_t avatar_base = peekProc<procptr32_t>(pModule + 0x0170B5A4);
	if (!avatar_base) return false;
	procptr32_t avatar_offset_0 = peekProc<procptr32_t>(avatar_base + 0x448);
	if (!avatar_offset_0) return false;
	procptr32_t avatar_offset_1 = peekProc<procptr32_t>(avatar_offset_0 + 0x440);
	if (!avatar_offset_1) return false;
	procptr32_t avatar_offset_2 = peekProc<procptr32_t>(avatar_offset_1 + 0x0);
	if (!avatar_offset_2) return false;
	procptr32_t avatar_offset = peekProc<procptr32_t>(avatar_offset_2 + 0x1C);
	if (!avatar_offset) return false;

	// Peekproc and assign game addresses to our containers, so we can retrieve positional data
	ok = peekProc(avatar_offset + 0x0, avatar_pos, 12) && // Avatar Position values (X, Y and -Z).
			peekProc(pModule + 0x0170B7E0, camera_pos, 12) && // Camera Position values (X, Y and -Z).
			peekProc(avatar_offset + 0xC, avatar_front, 12) && // Avatar Front values (X, Y and -Z).
			peekProc(pModule + 0x0170B7C8, camera_front, 12) && // Camera Front Vector values (X, Y and -Z).
			peekProc(pModule + 0x0170B7D4, camera_top, 12); // Camera Top Vector values (X, Y and -Z).

	// This prevents the plugin from linking to the game in case something goes wrong during values retrieval from memory addresses.
	if (! ok)
		return false;

	avatar_top[2] = -1; // This tells Mumble to automatically calculate top vector using front vector.

	// Scale from centimeters to meters
	for (int i=0;i<3;i++) {
		avatar_pos[i]/=100.0f;
		camera_pos[i]/=100.0f;
	}

	return true;
}

static int trylock(const std::multimap<std::wstring, unsigned long long int> &pids) {

	if (! initialize(pids, L"RocketLeague.exe")) // Link the game executable
		return false;

	// Check if we can get meaningful data from it
	float apos[3], afront[3], atop[3], cpos[3], cfront[3], ctop[3];
	std::wstring sidentity;
	std::string scontext;

	if (fetch(apos, afront, atop, cpos, cfront, ctop, scontext, sidentity)) {
		return true;
	} else {
		generic_unlock();
		return false;
	}
}

static const std::wstring longdesc() {
	return std::wstring(L"Supports Rocket League version 1.19 without context or identity support yet."); // Plugin long description
}

static std::wstring description(L"Rocket League (v1.19)"); // Plugin short description
static std::wstring shortname(L"Rocket League"); // Plugin short name

static int trylock1() {
	return trylock(std::multimap<std::wstring, unsigned long long int>());
}

static MumblePlugin rlplug = {
	MUMBLE_PLUGIN_MAGIC,
	description,
	shortname,
	NULL,
	NULL,
	trylock1,
	generic_unlock,
	longdesc,
	fetch
};

static MumblePlugin2 rlplug2 = {
	MUMBLE_PLUGIN_MAGIC_2,
	MUMBLE_PLUGIN_VERSION,
	trylock
};

extern "C" __declspec(dllexport) MumblePlugin *getMumblePlugin() {
	return &rlplug;
}

extern "C" __declspec(dllexport) MumblePlugin2 *getMumblePlugin2() {
	return &rlplug2;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "notificator.h"

#include <QApplication>
#include <QByteArray>
#include <QIcon>
#include <QImageWriter>
#include <QMessageBox>
#include <QMetaType>
#include <QStyle>
#include <QSystemTrayIcon>
#include <QTemporaryFile>
#include <QVariant>

#ifdef Q_OS_MAC
#include "macnotificationhandler.h"

#include <ApplicationServices/ApplicationServices.h>
#endif

#ifdef USE_DBUS
#include <stdint.h>

#include <QtDBus>
#endif

// https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128
const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128;

Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon, QWidget *parent) :
    QObject(parent),
    parent(parent),
    programName(programName),
    mode(None),
    trayIcon(trayicon)
#ifdef USE_DBUS
    ,interface(0)
#endif
{
    if(trayicon && trayicon->supportsMessages())
    {
        mode = QSystemTray;
    }
#ifdef USE_DBUS
    interface = new QDBusInterface("org.freedesktop.Notifications",
        "/org/freedesktop/Notifications", "org.freedesktop.Notifications");
    if(interface->isValid())
    {
        mode = Freedesktop;
    }
#endif
#ifdef Q_OS_MAC
    // check if users OS has support for NSUserNotification
    if( MacNotificationHandler::instance()->hasUserNotificationCenterSupport()) {
        mode = UserNotificationCenter;
    }
    else {
        // Check if Growl is installed (based on Qt's tray icon implementation)
        CFURLRef cfurl;
        OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl);
        if (status != kLSApplicationNotFoundErr) {
            CFBundleRef bundle = CFBundleCreate(0, cfurl);
            if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) {
                if (CFStringHasSuffix(CFURLGetString(cfurl), CFSTR("/Growl.app/")))
                    mode = Growl13;
                else
                    mode = Growl12;
            }
            CFRelease(cfurl);
            CFRelease(bundle);
        }
    }
#endif
}

Notificator::~Notificator()
{
#ifdef USE_DBUS
    delete interface;
#endif
}

#ifdef USE_DBUS

// Loosely based on http://www.qtcentre.org/archive/index.php/t-25879.html
class FreedesktopImage
{
public:
    FreedesktopImage() {}
    FreedesktopImage(const QImage &img);

    static int metaType();

    // Image to variant that can be marshalled over DBus
    static QVariant toVariant(const QImage &img);

private:
    int width, height, stride;
    bool hasAlpha;
    int channels;
    int bitsPerSample;
    QByteArray image;

    friend QDBusArgument &operator<<(QDBusArgument &a, const FreedesktopImage &i);
    friend const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i);
};

Q_DECLARE_METATYPE(FreedesktopImage);

// Image configuration settings
const int CHANNELS = 4;
const int BYTES_PER_PIXEL = 4;
const int BITS_PER_SAMPLE = 8;

FreedesktopImage::FreedesktopImage(const QImage &img):
    width(img.width()),
    height(img.height()),
    stride(img.width() * BYTES_PER_PIXEL),
    hasAlpha(true),
    channels(CHANNELS),
    bitsPerSample(BITS_PER_SAMPLE)
{
    // Convert 00xAARRGGBB to RGBA bytewise (endian-independent) format
    QImage tmp = img.convertToFormat(QImage::Format_ARGB32);
    const uint32_t *data = reinterpret_cast<const uint32_t*>(tmp.bits());

    unsigned int num_pixels = width * height;
    image.resize(num_pixels * BYTES_PER_PIXEL);

    for(unsigned int ptr = 0; ptr < num_pixels; ++ptr)
    {
        image[ptr*BYTES_PER_PIXEL+0] = data[ptr] >> 16; // R
        image[ptr*BYTES_PER_PIXEL+1] = data[ptr] >> 8;  // G
        image[ptr*BYTES_PER_PIXEL+2] = data[ptr];       // B
        image[ptr*BYTES_PER_PIXEL+3] = data[ptr] >> 24; // A
    }
}

QDBusArgument &operator<<(QDBusArgument &a, const FreedesktopImage &i)
{
    a.beginStructure();
    a << i.width << i.height << i.stride << i.hasAlpha << i.bitsPerSample << i.channels << i.image;
    a.endStructure();
    return a;
}

const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i)
{
    a.beginStructure();
    a >> i.width >> i.height >> i.stride >> i.hasAlpha >> i.bitsPerSample >> i.channels >> i.image;
    a.endStructure();
    return a;
}

int FreedesktopImage::metaType()
{
    return qDBusRegisterMetaType<FreedesktopImage>();
}

QVariant FreedesktopImage::toVariant(const QImage &img)
{
    FreedesktopImage fimg(img);
    return QVariant(FreedesktopImage::metaType(), &fimg);
}

void Notificator::notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
{
    Q_UNUSED(cls);
    // Arguments for DBus call:
    QList<QVariant> args;

    // Program Name:
    args.append(programName);

    // Unique ID of this notification type:
    args.append(0U);

    // Application Icon, empty string
    args.append(QString());

    // Summary
    args.append(title);

    // Body
    args.append(text);

    // Actions (none, actions are deprecated)
    QStringList actions;
    args.append(actions);

    // Hints
    QVariantMap hints;

    // If no icon specified, set icon based on class
    QIcon tmpicon;
    if(icon.isNull())
    {
        QStyle::StandardPixmap sicon = QStyle::SP_MessageBoxQuestion;
        switch(cls)
        {
        case Information: sicon = QStyle::SP_MessageBoxInformation; break;
        case Warning: sicon = QStyle::SP_MessageBoxWarning; break;
        case Critical: sicon = QStyle::SP_MessageBoxCritical; break;
        default: break;
        }
        tmpicon = QApplication::style()->standardIcon(sicon);
    }
    else
    {
        tmpicon = icon;
    }
    hints["icon_data"] = FreedesktopImage::toVariant(tmpicon.pixmap(FREEDESKTOP_NOTIFICATION_ICON_SIZE).toImage());
    args.append(hints);

    // Timeout (in msec)
    args.append(millisTimeout);

    // "Fire and forget"
    interface->callWithArgumentList(QDBus::NoBlock, "Notify", args);
}
#endif

void Notificator::notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
{
    Q_UNUSED(icon);
    QSystemTrayIcon::MessageIcon sicon = QSystemTrayIcon::NoIcon;
    switch(cls) // Set icon based on class
    {
    case Information: sicon = QSystemTrayIcon::Information; break;
    case Warning: sicon = QSystemTrayIcon::Warning; break;
    case Critical: sicon = QSystemTrayIcon::Critical; break;
    }
    trayIcon->showMessage(title, text, sicon, millisTimeout);
}

// Based on Qt's tray icon implementation
#ifdef Q_OS_MAC
void Notificator::notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon)
{
    const QString script(
        "tell application \"%5\"\n"
        "  set the allNotificationsList to {\"Notification\"}\n" // -- Make a list of all the notification types (all)
        "  set the enabledNotificationsList to {\"Notification\"}\n" // -- Make a list of the notifications (enabled)
        "  register as application \"%1\" all notifications allNotificationsList default notifications enabledNotificationsList\n" // -- Register our script with Growl
        "  notify with name \"Notification\" title \"%2\" description \"%3\" application name \"%1\"%4\n" // -- Send a Notification
        "end tell"
    );

    QString notificationApp(QApplication::applicationName());
    if (notificationApp.isEmpty())
        notificationApp = "Application";

    QPixmap notificationIconPixmap;
    if (icon.isNull()) { // If no icon specified, set icon based on class
        QStyle::StandardPixmap sicon = QStyle::SP_MessageBoxQuestion;
        switch (cls)
        {
        case Information: sicon = QStyle::SP_MessageBoxInformation; break;
        case Warning: sicon = QStyle::SP_MessageBoxWarning; break;
        case Critical: sicon = QStyle::SP_MessageBoxCritical; break;
        }
        notificationIconPixmap = QApplication::style()->standardPixmap(sicon);
    }
    else {
        QSize size = icon.actualSize(QSize(48, 48));
        notificationIconPixmap = icon.pixmap(size);
    }

    QString notificationIcon;
    QTemporaryFile notificationIconFile;
    if (!notificationIconPixmap.isNull() && notificationIconFile.open()) {
        QImageWriter writer(&notificationIconFile, "PNG");
        if (writer.write(notificationIconPixmap.toImage()))
            notificationIcon = QString(" image from location \"file://%1\"").arg(notificationIconFile.fileName());
    }

    QString quotedTitle(title), quotedText(text);
    quotedTitle.replace("\\", "\\\\").replace("\"", "\\");
    quotedText.replace("\\", "\\\\").replace("\"", "\\");
    QString growlApp(this->mode == Notificator::Growl13 ? "Growl" : "GrowlHelperApp");
    MacNotificationHandler::instance()->sendAppleScript(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon, growlApp));
}

void Notificator::notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon) {
    // icon is not supported by the user notification center yet. OSX will use the app icon.
    MacNotificationHandler::instance()->showNotification(title, text);
}

#endif

void Notificator::notify(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
{
    switch(mode)
    {
#ifdef USE_DBUS
    case Freedesktop:
        notifyDBus(cls, title, text, icon, millisTimeout);
        break;
#endif
    case QSystemTray:
        notifySystray(cls, title, text, icon, millisTimeout);
        break;
#ifdef Q_OS_MAC
    case UserNotificationCenter:
        notifyMacUserNotificationCenter(cls, title, text, icon);
        break;
    case Growl12:
    case Growl13:
        notifyGrowl(cls, title, text, icon);
        break;
#endif
    default:
        if(cls == Critical)
        {
            // Fall back to old fashioned pop-up dialog if critical and no other notification available
            QMessageBox::critical(parent, title, text, QMessageBox::Ok, QMessageBox::Ok);
        }
        break;
    }
}
<commit_msg>qt5: fix a build issue with osx and qtdbus<commit_after>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "notificator.h"

#include <QApplication>
#include <QByteArray>
#include <QIcon>
#include <QImageWriter>
#include <QMessageBox>
#include <QMetaType>
#include <QStyle>
#include <QSystemTrayIcon>
#include <QTemporaryFile>
#include <QVariant>
#ifdef USE_DBUS
#include <stdint.h>
#include <QtDBus>
#endif
// Include ApplicationServices.h after QtDbus to avoid redefinition of check().
// This affects at least OSX 10.6. See /usr/include/AssertMacros.h for details.
// Note: This could also be worked around using:
// #define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
#ifdef Q_OS_MAC
#include <ApplicationServices/ApplicationServices.h>
#include "macnotificationhandler.h"
#endif

// https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128
const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128;

Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon, QWidget *parent) :
    QObject(parent),
    parent(parent),
    programName(programName),
    mode(None),
    trayIcon(trayicon)
#ifdef USE_DBUS
    ,interface(0)
#endif
{
    if(trayicon && trayicon->supportsMessages())
    {
        mode = QSystemTray;
    }
#ifdef USE_DBUS
    interface = new QDBusInterface("org.freedesktop.Notifications",
        "/org/freedesktop/Notifications", "org.freedesktop.Notifications");
    if(interface->isValid())
    {
        mode = Freedesktop;
    }
#endif
#ifdef Q_OS_MAC
    // check if users OS has support for NSUserNotification
    if( MacNotificationHandler::instance()->hasUserNotificationCenterSupport()) {
        mode = UserNotificationCenter;
    }
    else {
        // Check if Growl is installed (based on Qt's tray icon implementation)
        CFURLRef cfurl;
        OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl);
        if (status != kLSApplicationNotFoundErr) {
            CFBundleRef bundle = CFBundleCreate(0, cfurl);
            if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) {
                if (CFStringHasSuffix(CFURLGetString(cfurl), CFSTR("/Growl.app/")))
                    mode = Growl13;
                else
                    mode = Growl12;
            }
            CFRelease(cfurl);
            CFRelease(bundle);
        }
    }
#endif
}

Notificator::~Notificator()
{
#ifdef USE_DBUS
    delete interface;
#endif
}

#ifdef USE_DBUS

// Loosely based on http://www.qtcentre.org/archive/index.php/t-25879.html
class FreedesktopImage
{
public:
    FreedesktopImage() {}
    FreedesktopImage(const QImage &img);

    static int metaType();

    // Image to variant that can be marshalled over DBus
    static QVariant toVariant(const QImage &img);

private:
    int width, height, stride;
    bool hasAlpha;
    int channels;
    int bitsPerSample;
    QByteArray image;

    friend QDBusArgument &operator<<(QDBusArgument &a, const FreedesktopImage &i);
    friend const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i);
};

Q_DECLARE_METATYPE(FreedesktopImage);

// Image configuration settings
const int CHANNELS = 4;
const int BYTES_PER_PIXEL = 4;
const int BITS_PER_SAMPLE = 8;

FreedesktopImage::FreedesktopImage(const QImage &img):
    width(img.width()),
    height(img.height()),
    stride(img.width() * BYTES_PER_PIXEL),
    hasAlpha(true),
    channels(CHANNELS),
    bitsPerSample(BITS_PER_SAMPLE)
{
    // Convert 00xAARRGGBB to RGBA bytewise (endian-independent) format
    QImage tmp = img.convertToFormat(QImage::Format_ARGB32);
    const uint32_t *data = reinterpret_cast<const uint32_t*>(tmp.bits());

    unsigned int num_pixels = width * height;
    image.resize(num_pixels * BYTES_PER_PIXEL);

    for(unsigned int ptr = 0; ptr < num_pixels; ++ptr)
    {
        image[ptr*BYTES_PER_PIXEL+0] = data[ptr] >> 16; // R
        image[ptr*BYTES_PER_PIXEL+1] = data[ptr] >> 8;  // G
        image[ptr*BYTES_PER_PIXEL+2] = data[ptr];       // B
        image[ptr*BYTES_PER_PIXEL+3] = data[ptr] >> 24; // A
    }
}

QDBusArgument &operator<<(QDBusArgument &a, const FreedesktopImage &i)
{
    a.beginStructure();
    a << i.width << i.height << i.stride << i.hasAlpha << i.bitsPerSample << i.channels << i.image;
    a.endStructure();
    return a;
}

const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i)
{
    a.beginStructure();
    a >> i.width >> i.height >> i.stride >> i.hasAlpha >> i.bitsPerSample >> i.channels >> i.image;
    a.endStructure();
    return a;
}

int FreedesktopImage::metaType()
{
    return qDBusRegisterMetaType<FreedesktopImage>();
}

QVariant FreedesktopImage::toVariant(const QImage &img)
{
    FreedesktopImage fimg(img);
    return QVariant(FreedesktopImage::metaType(), &fimg);
}

void Notificator::notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
{
    Q_UNUSED(cls);
    // Arguments for DBus call:
    QList<QVariant> args;

    // Program Name:
    args.append(programName);

    // Unique ID of this notification type:
    args.append(0U);

    // Application Icon, empty string
    args.append(QString());

    // Summary
    args.append(title);

    // Body
    args.append(text);

    // Actions (none, actions are deprecated)
    QStringList actions;
    args.append(actions);

    // Hints
    QVariantMap hints;

    // If no icon specified, set icon based on class
    QIcon tmpicon;
    if(icon.isNull())
    {
        QStyle::StandardPixmap sicon = QStyle::SP_MessageBoxQuestion;
        switch(cls)
        {
        case Information: sicon = QStyle::SP_MessageBoxInformation; break;
        case Warning: sicon = QStyle::SP_MessageBoxWarning; break;
        case Critical: sicon = QStyle::SP_MessageBoxCritical; break;
        default: break;
        }
        tmpicon = QApplication::style()->standardIcon(sicon);
    }
    else
    {
        tmpicon = icon;
    }
    hints["icon_data"] = FreedesktopImage::toVariant(tmpicon.pixmap(FREEDESKTOP_NOTIFICATION_ICON_SIZE).toImage());
    args.append(hints);

    // Timeout (in msec)
    args.append(millisTimeout);

    // "Fire and forget"
    interface->callWithArgumentList(QDBus::NoBlock, "Notify", args);
}
#endif

void Notificator::notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
{
    Q_UNUSED(icon);
    QSystemTrayIcon::MessageIcon sicon = QSystemTrayIcon::NoIcon;
    switch(cls) // Set icon based on class
    {
    case Information: sicon = QSystemTrayIcon::Information; break;
    case Warning: sicon = QSystemTrayIcon::Warning; break;
    case Critical: sicon = QSystemTrayIcon::Critical; break;
    }
    trayIcon->showMessage(title, text, sicon, millisTimeout);
}

// Based on Qt's tray icon implementation
#ifdef Q_OS_MAC
void Notificator::notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon)
{
    const QString script(
        "tell application \"%5\"\n"
        "  set the allNotificationsList to {\"Notification\"}\n" // -- Make a list of all the notification types (all)
        "  set the enabledNotificationsList to {\"Notification\"}\n" // -- Make a list of the notifications (enabled)
        "  register as application \"%1\" all notifications allNotificationsList default notifications enabledNotificationsList\n" // -- Register our script with Growl
        "  notify with name \"Notification\" title \"%2\" description \"%3\" application name \"%1\"%4\n" // -- Send a Notification
        "end tell"
    );

    QString notificationApp(QApplication::applicationName());
    if (notificationApp.isEmpty())
        notificationApp = "Application";

    QPixmap notificationIconPixmap;
    if (icon.isNull()) { // If no icon specified, set icon based on class
        QStyle::StandardPixmap sicon = QStyle::SP_MessageBoxQuestion;
        switch (cls)
        {
        case Information: sicon = QStyle::SP_MessageBoxInformation; break;
        case Warning: sicon = QStyle::SP_MessageBoxWarning; break;
        case Critical: sicon = QStyle::SP_MessageBoxCritical; break;
        }
        notificationIconPixmap = QApplication::style()->standardPixmap(sicon);
    }
    else {
        QSize size = icon.actualSize(QSize(48, 48));
        notificationIconPixmap = icon.pixmap(size);
    }

    QString notificationIcon;
    QTemporaryFile notificationIconFile;
    if (!notificationIconPixmap.isNull() && notificationIconFile.open()) {
        QImageWriter writer(&notificationIconFile, "PNG");
        if (writer.write(notificationIconPixmap.toImage()))
            notificationIcon = QString(" image from location \"file://%1\"").arg(notificationIconFile.fileName());
    }

    QString quotedTitle(title), quotedText(text);
    quotedTitle.replace("\\", "\\\\").replace("\"", "\\");
    quotedText.replace("\\", "\\\\").replace("\"", "\\");
    QString growlApp(this->mode == Notificator::Growl13 ? "Growl" : "GrowlHelperApp");
    MacNotificationHandler::instance()->sendAppleScript(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon, growlApp));
}

void Notificator::notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon) {
    // icon is not supported by the user notification center yet. OSX will use the app icon.
    MacNotificationHandler::instance()->showNotification(title, text);
}

#endif

void Notificator::notify(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
{
    switch(mode)
    {
#ifdef USE_DBUS
    case Freedesktop:
        notifyDBus(cls, title, text, icon, millisTimeout);
        break;
#endif
    case QSystemTray:
        notifySystray(cls, title, text, icon, millisTimeout);
        break;
#ifdef Q_OS_MAC
    case UserNotificationCenter:
        notifyMacUserNotificationCenter(cls, title, text, icon);
        break;
    case Growl12:
    case Growl13:
        notifyGrowl(cls, title, text, icon);
        break;
#endif
    default:
        if(cls == Critical)
        {
            // Fall back to old fashioned pop-up dialog if critical and no other notification available
            QMessageBox::critical(parent, title, text, QMessageBox::Ok, QMessageBox::Ok);
        }
        break;
    }
}
<|endoftext|>