<commit_before>/*
 * Copyright (c) 2010 ARM Limited
 * 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.
 *
 * Copyright (c) 2007-2008 The Florida State University
 * All rights reserved.
 *
 * 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: Stephen Hines
 */
#ifndef __ARCH_ARM_INSTS_STATICINST_HH__
#define __ARCH_ARM_INSTS_STATICINST_HH__

#include "base/trace.hh"
#include "cpu/static_inst.hh"

namespace ArmISA
{
class ArmStaticInst : public StaticInst
{
  protected:
    int32_t shift_rm_imm(uint32_t base, uint32_t shamt,
                         uint32_t type, uint32_t cfval) const;
    int32_t shift_rm_rs(uint32_t base, uint32_t shamt,
                        uint32_t type, uint32_t cfval) const;

    bool shift_carry_imm(uint32_t base, uint32_t shamt,
                         uint32_t type, uint32_t cfval) const;
    bool shift_carry_rs(uint32_t base, uint32_t shamt,
                        uint32_t type, uint32_t cfval) const;

    template<int width>
    static bool
    saturateOp(int32_t &res, int64_t op1, int64_t op2, bool sub=false)
    {
        int64_t midRes = sub ? (op1 - op2) : (op1 + op2);
        if (bits(midRes, width) != bits(midRes, width - 1)) {
            if (midRes > 0)
                res = (LL(1) << (width - 1)) - 1;
            else
                res = -(LL(1) << (width - 1));
            return true;
        } else {
            res = midRes;
            return false;
        }
    }

    static bool
    satInt(int32_t &res, int64_t op, int width)
    {
        width--;
        if (op >= (LL(1) << width)) {
            res = (LL(1) << width) - 1;
            return true;
        } else if (op < -(LL(1) << width)) {
            res = -(LL(1) << width);
            return true;
        } else {
            res = op;
            return false;
        }
    }

    template<int width>
    static bool
    uSaturateOp(uint32_t &res, int64_t op1, int64_t op2, bool sub=false)
    {
        int64_t midRes = sub ? (op1 - op2) : (op1 + op2);
        if (midRes >= (LL(1) << width)) {
            res = (LL(1) << width) - 1;
            return true;
        } else if (midRes < 0) {
            res = 0;
            return true;
        } else {
            res = midRes;
            return false;
        }
    }

    static bool
    uSatInt(int32_t &res, int64_t op, int width)
    {
        if (op >= (LL(1) << width)) {
            res = (LL(1) << width) - 1;
            return true;
        } else if (op < 0) {
            res = 0;
            return true;
        } else {
            res = op;
            return false;
        }
    }

    // Constructor
    ArmStaticInst(const char *mnem, ExtMachInst _machInst,
                  OpClass __opClass)
        : StaticInst(mnem, _machInst, __opClass)
    {
    }

    /// Print a register name for disassembly given the unique
    /// dependence tag number (FP or int).
    void printReg(std::ostream &os, int reg) const;
    void printMnemonic(std::ostream &os,
                       const std::string &suffix = "",
                       bool withPred = true) const;
    void printMemSymbol(std::ostream &os, const SymbolTable *symtab,
                        const std::string &prefix, const Addr addr,
                        const std::string &suffix) const;
    void printShiftOperand(std::ostream &os, IntRegIndex rm,
                           bool immShift, uint32_t shiftAmt,
                           IntRegIndex rs, ArmShiftType type) const;

    void printDataInst(std::ostream &os, bool withImm) const;
    void printDataInst(std::ostream &os, bool withImm, bool immShift, bool s,
                       IntRegIndex rd, IntRegIndex rn, IntRegIndex rm,
                       IntRegIndex rs, uint32_t shiftAmt, ArmShiftType type,
                       uint32_t imm) const;

    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;

    static uint32_t
    cpsrWriteByInstr(CPSR cpsr, uint32_t val,
            uint8_t byteMask, bool affectState, bool nmfi)
    {
        bool privileged = (cpsr.mode != MODE_USER);

        uint32_t bitMask = 0;

        if (bits(byteMask, 3)) {
            unsigned lowIdx = affectState ? 24 : 27;
            bitMask = bitMask | mask(31, lowIdx);
        }
        if (bits(byteMask, 2)) {
            bitMask = bitMask | mask(19, 16);
        }
        if (bits(byteMask, 1)) {
            unsigned highIdx = affectState ? 15 : 9;
            unsigned lowIdx = privileged ? 8 : 9;
            bitMask = bitMask | mask(highIdx, lowIdx);
        }
        if (bits(byteMask, 0)) {
            if (privileged) {
                bitMask = bitMask | mask(7, 6);
                if (!badMode((OperatingMode)(val & mask(5)))) {
                    bitMask = bitMask | mask(5);
                } else {
                    warn_once("Ignoring write of bad mode to CPSR.\n");
                }
            }
            if (affectState)
                bitMask = bitMask | (1 << 5);
        }

        bool cpsr_f = cpsr.f;
        uint32_t new_cpsr = ((uint32_t)cpsr & ~bitMask) | (val & bitMask);
        if (nmfi && !cpsr_f)
            new_cpsr &= ~(1 << 6);
        return new_cpsr;
    }

    static uint32_t
    spsrWriteByInstr(uint32_t spsr, uint32_t val,
            uint8_t byteMask, bool affectState)
    {
        uint32_t bitMask = 0;

        if (bits(byteMask, 3))
            bitMask = bitMask | mask(31, 24);
        if (bits(byteMask, 2))
            bitMask = bitMask | mask(19, 16);
        if (bits(byteMask, 1))
            bitMask = bitMask | mask(15, 8);
        if (bits(byteMask, 0))
            bitMask = bitMask | mask(7, 0);

        return ((spsr & ~bitMask) | (val & bitMask));
    }

    template<class XC>
    static Addr
    readPC(XC *xc)
    {
        Addr pc = xc->readPC();
        Addr tBit = pc & (ULL(1) << PcTBitShift);
        if (tBit)
            return pc + 4;
        else
            return pc + 8;
    }

    // Perform an regular branch.
    template<class XC>
    static void
    setNextPC(XC *xc, Addr val)
    {
        Addr npc = xc->readNextPC();
        if (npc & (ULL(1) << PcTBitShift)) {
            val &= ~mask(1);
        } else {
            val &= ~mask(2);
        }
        xc->setNextPC((npc & PcModeMask) |
                      (val & ~PcModeMask));
    }

    template<class T>
    static T
    cSwap(T val, bool big)
    {
        if (big) {
            return gtobe(val);
        } else {
            return gtole(val);
        }
    }

    // Perform an interworking branch.
    template<class XC>
    static void
    setIWNextPC(XC *xc, Addr val)
    {
        Addr stateBits = xc->readPC() & PcModeMask;
        Addr jBit = (ULL(1) << PcJBitShift);
        Addr tBit = (ULL(1) << PcTBitShift);
        bool thumbEE = (stateBits == (tBit | jBit));

        Addr newPc = (val & ~PcModeMask);
        if (thumbEE) {
            if (bits(newPc, 0)) {
                newPc = newPc & ~mask(1);
            } else {
                panic("Bad thumbEE interworking branch address %#x.\n", newPc);
            }
        } else {
            if (bits(newPc, 0)) {
                stateBits = tBit;
                newPc = newPc & ~mask(1);
            } else if (!bits(newPc, 1)) {
                stateBits = 0;
            } else {
                warn("Bad interworking branch address %#x.\n", newPc);
            }
        }
        newPc = newPc | stateBits;
        xc->setNextPC(newPc);
    }

    // Perform an interworking branch in ARM mode, a regular branch
    // otherwise.
    template<class XC>
    static void
    setAIWNextPC(XC *xc, Addr val)
    {
        Addr stateBits = xc->readPC() & PcModeMask;
        Addr jBit = (ULL(1) << PcJBitShift);
        Addr tBit = (ULL(1) << PcTBitShift);
        if (!jBit && !tBit) {
            setIWNextPC(xc, val);
        } else {
            setNextPC(xc, val);
        }
    }
};
}

#endif //__ARCH_ARM_INSTS_STATICINST_HH__
<commit_msg>ARM: Mark some ARM static inst functions as inline.<commit_after>/*
 * Copyright (c) 2010 ARM Limited
 * 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.
 *
 * Copyright (c) 2007-2008 The Florida State University
 * All rights reserved.
 *
 * 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: Stephen Hines
 */
#ifndef __ARCH_ARM_INSTS_STATICINST_HH__
#define __ARCH_ARM_INSTS_STATICINST_HH__

#include "base/trace.hh"
#include "cpu/static_inst.hh"

namespace ArmISA
{

class ArmStaticInst : public StaticInst
{
  protected:
    int32_t shift_rm_imm(uint32_t base, uint32_t shamt,
                         uint32_t type, uint32_t cfval) const;
    int32_t shift_rm_rs(uint32_t base, uint32_t shamt,
                        uint32_t type, uint32_t cfval) const;

    bool shift_carry_imm(uint32_t base, uint32_t shamt,
                         uint32_t type, uint32_t cfval) const;
    bool shift_carry_rs(uint32_t base, uint32_t shamt,
                        uint32_t type, uint32_t cfval) const;

    template<int width>
    static inline bool
    saturateOp(int32_t &res, int64_t op1, int64_t op2, bool sub=false)
    {
        int64_t midRes = sub ? (op1 - op2) : (op1 + op2);
        if (bits(midRes, width) != bits(midRes, width - 1)) {
            if (midRes > 0)
                res = (LL(1) << (width - 1)) - 1;
            else
                res = -(LL(1) << (width - 1));
            return true;
        } else {
            res = midRes;
            return false;
        }
    }

    static inline bool
    satInt(int32_t &res, int64_t op, int width)
    {
        width--;
        if (op >= (LL(1) << width)) {
            res = (LL(1) << width) - 1;
            return true;
        } else if (op < -(LL(1) << width)) {
            res = -(LL(1) << width);
            return true;
        } else {
            res = op;
            return false;
        }
    }

    template<int width>
    static inline bool
    uSaturateOp(uint32_t &res, int64_t op1, int64_t op2, bool sub=false)
    {
        int64_t midRes = sub ? (op1 - op2) : (op1 + op2);
        if (midRes >= (LL(1) << width)) {
            res = (LL(1) << width) - 1;
            return true;
        } else if (midRes < 0) {
            res = 0;
            return true;
        } else {
            res = midRes;
            return false;
        }
    }

    static inline bool
    uSatInt(int32_t &res, int64_t op, int width)
    {
        if (op >= (LL(1) << width)) {
            res = (LL(1) << width) - 1;
            return true;
        } else if (op < 0) {
            res = 0;
            return true;
        } else {
            res = op;
            return false;
        }
    }

    // Constructor
    ArmStaticInst(const char *mnem, ExtMachInst _machInst,
                  OpClass __opClass)
        : StaticInst(mnem, _machInst, __opClass)
    {
    }

    /// Print a register name for disassembly given the unique
    /// dependence tag number (FP or int).
    void printReg(std::ostream &os, int reg) const;
    void printMnemonic(std::ostream &os,
                       const std::string &suffix = "",
                       bool withPred = true) const;
    void printMemSymbol(std::ostream &os, const SymbolTable *symtab,
                        const std::string &prefix, const Addr addr,
                        const std::string &suffix) const;
    void printShiftOperand(std::ostream &os, IntRegIndex rm,
                           bool immShift, uint32_t shiftAmt,
                           IntRegIndex rs, ArmShiftType type) const;

    void printDataInst(std::ostream &os, bool withImm) const;
    void printDataInst(std::ostream &os, bool withImm, bool immShift, bool s,
                       IntRegIndex rd, IntRegIndex rn, IntRegIndex rm,
                       IntRegIndex rs, uint32_t shiftAmt, ArmShiftType type,
                       uint32_t imm) const;

    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;

    static inline uint32_t
    cpsrWriteByInstr(CPSR cpsr, uint32_t val,
            uint8_t byteMask, bool affectState, bool nmfi)
    {
        bool privileged = (cpsr.mode != MODE_USER);

        uint32_t bitMask = 0;

        if (bits(byteMask, 3)) {
            unsigned lowIdx = affectState ? 24 : 27;
            bitMask = bitMask | mask(31, lowIdx);
        }
        if (bits(byteMask, 2)) {
            bitMask = bitMask | mask(19, 16);
        }
        if (bits(byteMask, 1)) {
            unsigned highIdx = affectState ? 15 : 9;
            unsigned lowIdx = privileged ? 8 : 9;
            bitMask = bitMask | mask(highIdx, lowIdx);
        }
        if (bits(byteMask, 0)) {
            if (privileged) {
                bitMask = bitMask | mask(7, 6);
                if (!badMode((OperatingMode)(val & mask(5)))) {
                    bitMask = bitMask | mask(5);
                } else {
                    warn_once("Ignoring write of bad mode to CPSR.\n");
                }
            }
            if (affectState)
                bitMask = bitMask | (1 << 5);
        }

        bool cpsr_f = cpsr.f;
        uint32_t new_cpsr = ((uint32_t)cpsr & ~bitMask) | (val & bitMask);
        if (nmfi && !cpsr_f)
            new_cpsr &= ~(1 << 6);
        return new_cpsr;
    }

    static inline uint32_t
    spsrWriteByInstr(uint32_t spsr, uint32_t val,
            uint8_t byteMask, bool affectState)
    {
        uint32_t bitMask = 0;

        if (bits(byteMask, 3))
            bitMask = bitMask | mask(31, 24);
        if (bits(byteMask, 2))
            bitMask = bitMask | mask(19, 16);
        if (bits(byteMask, 1))
            bitMask = bitMask | mask(15, 8);
        if (bits(byteMask, 0))
            bitMask = bitMask | mask(7, 0);

        return ((spsr & ~bitMask) | (val & bitMask));
    }

    template<class XC>
    static inline Addr
    readPC(XC *xc)
    {
        Addr pc = xc->readPC();
        Addr tBit = pc & (ULL(1) << PcTBitShift);
        if (tBit)
            return pc + 4;
        else
            return pc + 8;
    }

    // Perform an regular branch.
    template<class XC>
    static inline void
    setNextPC(XC *xc, Addr val)
    {
        Addr npc = xc->readNextPC();
        if (npc & (ULL(1) << PcTBitShift)) {
            val &= ~mask(1);
        } else {
            val &= ~mask(2);
        }
        xc->setNextPC((npc & PcModeMask) |
                      (val & ~PcModeMask));
    }

    template<class T>
    static inline T
    cSwap(T val, bool big)
    {
        if (big) {
            return gtobe(val);
        } else {
            return gtole(val);
        }
    }

    // Perform an interworking branch.
    template<class XC>
    static inline void
    setIWNextPC(XC *xc, Addr val)
    {
        Addr stateBits = xc->readPC() & PcModeMask;
        Addr jBit = (ULL(1) << PcJBitShift);
        Addr tBit = (ULL(1) << PcTBitShift);
        bool thumbEE = (stateBits == (tBit | jBit));

        Addr newPc = (val & ~PcModeMask);
        if (thumbEE) {
            if (bits(newPc, 0)) {
                newPc = newPc & ~mask(1);
            } else {
                panic("Bad thumbEE interworking branch address %#x.\n", newPc);
            }
        } else {
            if (bits(newPc, 0)) {
                stateBits = tBit;
                newPc = newPc & ~mask(1);
            } else if (!bits(newPc, 1)) {
                stateBits = 0;
            } else {
                warn("Bad interworking branch address %#x.\n", newPc);
            }
        }
        newPc = newPc | stateBits;
        xc->setNextPC(newPc);
    }

    // Perform an interworking branch in ARM mode, a regular branch
    // otherwise.
    template<class XC>
    static inline void
    setAIWNextPC(XC *xc, Addr val)
    {
        Addr stateBits = xc->readPC() & PcModeMask;
        Addr jBit = (ULL(1) << PcJBitShift);
        Addr tBit = (ULL(1) << PcTBitShift);
        if (!jBit && !tBit) {
            setIWNextPC(xc, val);
        } else {
            setNextPC(xc, val);
        }
    }
};
}

#endif //__ARCH_ARM_INSTS_STATICINST_HH__
<|endoftext|>


<commit_before>/*
    Copyright 2016 Ahnaf Siddiqui

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

#include "gtest/gtest.h"
#include "D_StdConfigLoader.h"

using namespace Diamond;

class TestConfigLoader : public StdConfigLoader {
public:
    bool testParse(const std::string &line,
                   const std::string &expKey,
                   const std::string &expVal) {
        std::string key, val;
        bool ok = parseLine(line, key, val);

        EXPECT_EQ(expKey, key);
        EXPECT_EQ(expVal, val);

        return ok;
    }
};

TEST(ConfigTest, Parses) {
    TestConfigLoader configLoader;
    bool ok;

    ok = configLoader.testParse("Boss:Ahnaf", "Boss", "Ahnaf");
    EXPECT_TRUE(ok);

    ok = configLoader.testParse("MyPowerLevel:9001", "MyPowerLevel", "9001");
    EXPECT_TRUE(ok);
}

TEST(ConfigTest, InvalidParses) {
    TestConfigLoader configLoader;
    bool ok;

    ok = configLoader.testParse("iamerror", "", "");
    EXPECT_FALSE(ok);

    ok = configLoader.testParse(":wut", "", "");
    EXPECT_FALSE(ok);

    ok = configLoader.testParse("wut:", "", "");
    EXPECT_FALSE(ok);
}

TEST(ConfigTest, LoadsFile) {
    StdConfigLoader configLoader;

    ConfigTable config = configLoader.load("game.cfg");

    EXPECT_EQ(config.size(), 11);

    EXPECT_EQ(config.get("Game"), "Life");
    EXPECT_EQ(config.get("Difficulty"), "HardAF");

    EXPECT_EQ(config.getInt("PowerLevel"), 9001);
    EXPECT_EQ(config.getInt("Release"), 0);
    EXPECT_FLOAT_EQ(config.getFloat("pi"), 3.14);

    EXPECT_EQ(config.get("Price"), "Death");
    EXPECT_EQ(config.get("Graphics"), "Ultra");

    EXPECT_TRUE(config.getBool("Running"));
    EXPECT_TRUE(config.getBool("Purchased"));
    EXPECT_FALSE(config.getBool("Completed"));
    EXPECT_TRUE(config.getBool("Multiplayer"));
}

TEST(ConfigTest, WritesFile) {
    StdConfigLoader configLoader;
    ConfigTable config;

    config.set("Game", "Snake");
    config.set("Fun", true);
    config.set("Highscore", 300);
    config.set("pi", 3.14);

    EXPECT_EQ(config.size(), 4);

    configLoader.write(config, "dump.cfg");

    ConfigTable loadedConfig = configLoader.load("dump.cfg");

    EXPECT_EQ(loadedConfig.get("Game"), "Snake");
    EXPECT_TRUE(loadedConfig.getBool("Fun"));
    EXPECT_EQ(loadedConfig.getInt("Highscore"), 300);
    EXPECT_FLOAT_EQ(loadedConfig.getFloat("pi"), 3.14);
}
<commit_msg>Added test for SDLConfigLoader<commit_after>/*
    Copyright 2016 Ahnaf Siddiqui

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

#include "gtest/gtest.h"
#include "D_StdConfigLoader.h"
#include "D_SDLConfigLoader.h"

using namespace Diamond;

class TestConfigLoader : public StdConfigLoader {
public:
    bool testParse(const std::string &line,
                   const std::string &expKey,
                   const std::string &expVal) {
        std::string key, val;
        bool ok = parseLine(line, key, val);

        EXPECT_EQ(expKey, key);
        EXPECT_EQ(expVal, val);

        return ok;
    }
};

static ConfigTable testLoadsFile(ConfigLoader &configLoader) {
    ConfigTable config = configLoader.load("game.cfg");

    EXPECT_EQ(config.size(), 11);

    EXPECT_EQ(config.get("Game"), "Life");
    EXPECT_EQ(config.get("Difficulty"), "HardAF");

    EXPECT_EQ(config.getInt("PowerLevel"), 9001);
    EXPECT_EQ(config.getInt("Release"), 0);
    EXPECT_FLOAT_EQ(config.getFloat("pi"), 3.14);

    EXPECT_EQ(config.get("Price"), "Death");
    EXPECT_EQ(config.get("Graphics"), "Ultra");

    EXPECT_TRUE(config.getBool("Running"));
    EXPECT_TRUE(config.getBool("Purchased"));
    EXPECT_FALSE(config.getBool("Completed"));
    EXPECT_TRUE(config.getBool("Multiplayer"));

    return config;
}

TEST(ConfigTest, Parses) {
    TestConfigLoader configLoader;
    bool ok;

    ok = configLoader.testParse("Boss:Ahnaf", "Boss", "Ahnaf");
    EXPECT_TRUE(ok);

    ok = configLoader.testParse("MyPowerLevel:9001", "MyPowerLevel", "9001");
    EXPECT_TRUE(ok);
}

TEST(ConfigTest, InvalidParses) {
    TestConfigLoader configLoader;
    bool ok;

    ok = configLoader.testParse("iamerror", "", "");
    EXPECT_FALSE(ok);

    ok = configLoader.testParse(":wut", "", "");
    EXPECT_FALSE(ok);

    ok = configLoader.testParse("wut:", "", "");
    EXPECT_FALSE(ok);
}

TEST(StdConfigTest, LoadsFile) {
    StdConfigLoader configLoader;
    testLoadsFile(configLoader);
}

TEST(StdConfigTest, WritesFile) {
    StdConfigLoader configLoader;
    ConfigTable config;

    config.set("Game", "Snake");
    config.set("Fun", true);
    config.set("Highscore", 300);
    config.set("pi", 3.14);

    EXPECT_EQ(config.size(), 4);

    configLoader.write(config, "dump.cfg");

    ConfigTable loadedConfig = configLoader.load("dump.cfg");

    EXPECT_EQ(loadedConfig.get("Game"), "Snake");
    EXPECT_TRUE(loadedConfig.getBool("Fun"));
    EXPECT_EQ(loadedConfig.getInt("Highscore"), 300);
    EXPECT_FLOAT_EQ(loadedConfig.getFloat("pi"), 3.14);
}

TEST(SDLConfigTest, LoadsFile) {
    SDLConfigLoader configLoader;
    testLoadsFile(configLoader);
}
<|endoftext|>


<commit_before>// Copyright Steinwurf ApS 2015.
// All Rights Reserved
//
// Distributed under the "BSD License". See the accompanying LICENSE.rst file.

#include <meta/typelist.hpp>
#include <meta/template_is_same.hpp>

#include <gtest/gtest.h>

#include <vector>

namespace
{
    struct dummy{};
}

TEST(test_type_list, append)
{
    {
        using types = meta::typelist<>::append<int>::append<bool>;

        bool value = std::is_same<types,
            meta::typelist<int,bool>>::value;

        EXPECT_TRUE(value);
    }

    {
        using types = meta::typelist<double, float>::append<int>::append<bool>;

        bool value = std::is_same<types,
            meta::typelist<double,float,int,bool>>::value;

        EXPECT_TRUE(value);
    }
}

TEST(test_type_list, find)
{
    {
        // Test find when no type exists using default NotFound
        using types = meta::typelist<double,float>;
        using result = types::find<std::is_integral>;

        bool value = std::is_same<result, meta::not_found>::value;

        EXPECT_TRUE(value);
    }

    {
        // Test find when no type exists using custom NotFound
        using types = meta::typelist<double,float>;
        using result = types::find<std::is_integral, dummy>;

        bool value = std::is_same<result, dummy>::value;

        EXPECT_TRUE(value);
    }

    {
        // Test find when type exists
        using types = meta::typelist<double,int,float>;
        using result = types::find<std::is_integral>;

        bool value = std::is_same<result, int>::value;

        EXPECT_TRUE(value);
    }

    {
        // Test find when type exists and custom NotFound is used
        using types = meta::typelist<double,int,float>;
        using result = types::find<std::is_integral, dummy>;

        bool value = std::is_same<result, int>::value;

        EXPECT_TRUE(value);
    }
}

TEST(test_type_list, visit)
{
    struct count
    {
        void operator()(int){ m_int = true; }
        void operator()(float){ m_float = true; }
        void operator()(double){ m_double = true; }

        bool m_int = false;
        bool m_float = false;
        bool m_double = false;
    };

    using types1 = meta::typelist<double,float>;

    count check1;
    types1::visit(check1);

    EXPECT_FALSE(check1.m_int);
    EXPECT_TRUE(check1.m_float);
    EXPECT_TRUE(check1.m_double);

    using types2 = types1::append<int>;

    count check2;
    types2::visit(check2);

    EXPECT_TRUE(check2.m_int);
    EXPECT_TRUE(check2.m_float);
    EXPECT_TRUE(check2.m_double);
}

TEST(test_type_list, remove)
{
    {
        // Test remove when type matches
        using types = meta::typelist<double,int,float,int>;
        using result = types::remove<std::is_integral>;

        bool value = std::is_same<result,
            meta::typelist<double,float>>::value;

        EXPECT_TRUE(value);
    }

    {
        // Test remove when no type matches
        using types = meta::typelist<double, float>;
        using result = types::remove<std::is_integral>;

        bool value = std::is_same<result,
            meta::typelist<double,float>>::value;

        EXPECT_TRUE(value);
    }

    {
        // Test remove with empty list
        using types = meta::typelist<>;
        using result = types::remove<std::is_integral>;

        bool value = std::is_same<result,
            meta::typelist<>>::value;

        EXPECT_TRUE(value);
    }
}
<commit_msg>Adding missing unit test<commit_after>// Copyright Steinwurf ApS 2015.
// All Rights Reserved
//
// Distributed under the "BSD License". See the accompanying LICENSE.rst file.

#include <meta/typelist.hpp>
#include <meta/template_is_same.hpp>

#include <gtest/gtest.h>

#include <vector>

namespace
{
    struct dummy{};
}

// Tests that our concatenate meta function works properly
TEST(test_type_list, append)
{
    {
        using types = meta::typelist<>::append<int>::append<bool>;

        bool value = std::is_same<types,
            meta::typelist<int,bool>>::value;

        EXPECT_TRUE(value);
    }

    {
        using types = meta::typelist<double, float>::append<int>::append<bool>;

        bool value = std::is_same<types,
            meta::typelist<double,float,int,bool>>::value;

        EXPECT_TRUE(value);
    }
}

TEST(test_type_list, extend)
{
    {
        using list_one = meta::typelist<>;
        using list_two = meta::typelist<>;

        using result = list_one::extend<list_two>;

        bool value = std::is_same<result,
            meta::typelist<>>::value;

        EXPECT_TRUE(value);
    }

    {
        using list_one = meta::typelist<>;
        using list_two = meta::typelist<int>;

        using result = list_one::extend<list_two>;

        bool value = std::is_same<result,
            meta::typelist<int>>::value;

        EXPECT_TRUE(value);
    }

    {
        using list_one = meta::typelist<int>;
        using list_two = meta::typelist<>;

        using result = list_one::extend<list_two>;

        bool value = std::is_same<result,
            meta::typelist<int>>::value;

        EXPECT_TRUE(value);
    }

    {
        using list_one = meta::typelist<int, double>;
        using list_two = meta::typelist<float, bool>;

        using result = list_one::extend<list_two>;

        bool value = std::is_same<result,
            meta::typelist<int, double, float, bool>>::value;
        EXPECT_TRUE(value);
    }

    {
        using list_one = meta::typelist<int>;
        using list_two = meta::typelist<float, bool>;

        using result = list_one::extend<list_two>;

        bool value = std::is_same<result,
            meta::typelist<int, float, bool>>::value;
        EXPECT_TRUE(value);
    }
}

TEST(test_type_list, find)
{
    {
        // Test find when no type exists using default NotFound
        using types = meta::typelist<double,float>;
        using result = types::find<std::is_integral>;

        bool value = std::is_same<result, meta::not_found>::value;

        EXPECT_TRUE(value);
    }

    {
        // Test find when no type exists using custom NotFound
        using types = meta::typelist<double,float>;
        using result = types::find<std::is_integral, dummy>;

        bool value = std::is_same<result, dummy>::value;

        EXPECT_TRUE(value);
    }

    {
        // Test find when type exists
        using types = meta::typelist<double,int,float>;
        using result = types::find<std::is_integral>;

        bool value = std::is_same<result, int>::value;

        EXPECT_TRUE(value);
    }

    {
        // Test find when type exists and custom NotFound is used
        using types = meta::typelist<double,int,float>;
        using result = types::find<std::is_integral, dummy>;

        bool value = std::is_same<result, int>::value;

        EXPECT_TRUE(value);
    }
}

TEST(test_type_list, visit)
{
    struct count
    {
        void operator()(int){ m_int = true; }
        void operator()(float){ m_float = true; }
        void operator()(double){ m_double = true; }

        bool m_int = false;
        bool m_float = false;
        bool m_double = false;
    };

    using types1 = meta::typelist<double,float>;

    count check1;
    types1::visit(check1);

    EXPECT_FALSE(check1.m_int);
    EXPECT_TRUE(check1.m_float);
    EXPECT_TRUE(check1.m_double);

    using types2 = types1::append<int>;

    count check2;
    types2::visit(check2);

    EXPECT_TRUE(check2.m_int);
    EXPECT_TRUE(check2.m_float);
    EXPECT_TRUE(check2.m_double);
}

TEST(test_type_list, remove)
{
    {
        // Test remove when type matches
        using types = meta::typelist<double,int,float,int>;
        using result = types::remove<std::is_integral>;

        bool value = std::is_same<result,
            meta::typelist<double,float>>::value;

        EXPECT_TRUE(value);
    }

    {
        // Test remove when no type matches
        using types = meta::typelist<double, float>;
        using result = types::remove<std::is_integral>;

        bool value = std::is_same<result,
            meta::typelist<double,float>>::value;

        EXPECT_TRUE(value);
    }

    {
        // Test remove with empty list
        using types = meta::typelist<>;
        using result = types::remove<std::is_integral>;

        bool value = std::is_same<result,
            meta::typelist<>>::value;

        EXPECT_TRUE(value);
    }
}
<|endoftext|>


<commit_before>
/* An example of the minimal Win32 & OpenGL program.  It only works in
16 bit color modes or higher (since it doesn't create a
palette). */

// clang-format off
#include <stdio.h>
#include <windows.h> /* must include this before GL/gl.h */
#include <GL/gl.h> /* OpenGL header file */
#include <GL/glu.h> /* OpenGL utilities header file */
#include "gl_loader.h"
#include <iostream>

// clang-format on

void display()
{
    /* rotate a triangle around */
    glActiveTexture(GL_TEXTURE0);
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_TRIANGLES);
    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex2i(0, 1);
    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex2i(-1, -1);
    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex2i(1, -1);
    glEnd();
    glFlush();
}

LONG WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static PAINTSTRUCT ps;

    switch (uMsg) {
    case WM_PAINT:
        display();
        BeginPaint(hWnd, &ps);
        EndPaint(hWnd, &ps);
        return 0;

    case WM_SIZE:
        glViewport(0, 0, LOWORD(lParam), HIWORD(lParam));
        PostMessage(hWnd, WM_PAINT, 0, 0);
        return 0;

    case WM_CHAR:
        switch (wParam) {
        case 27: /* ESC key */
            PostQuitMessage(0);
            break;
        }
        return 0;

    case WM_CLOSE:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

HWND CreateOpenGLWindow(char* title, int x, int y, int width, int height,
    BYTE type, DWORD flags)
{
    int pf;
    HDC hDC;
    HWND hWnd;
    WNDCLASS wc;
    PIXELFORMATDESCRIPTOR pfd;
    static HINSTANCE hInstance = 0;

    /* only register the window class once - use hInstance as a flag. */
    if (!hInstance) {
        hInstance = GetModuleHandle(NULL);
        wc.style = CS_OWNDC;
        wc.lpfnWndProc = (WNDPROC)WindowProc;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = hInstance;
        wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = NULL;
        wc.lpszMenuName = NULL;
        wc.lpszClassName = L"OpenGL";

        if (!RegisterClass(&wc)) {
            MessageBox(NULL, L"RegisterClass() failed:  "
                             "Cannot register window class.",
                L"Error", MB_OK);
            return NULL;
        }
    }

    hWnd = CreateWindow(L"OpenGL", L"Hej", WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
        x, y, width, height, NULL, NULL, hInstance, NULL);

    if (hWnd == NULL) {
        MessageBox(NULL, L"CreateWindow() failed:  Cannot create a window.",
            L"Error", MB_OK);
        return NULL;
    }

    hDC = GetDC(hWnd);

    /* there is no guarantee that the contents of the stack that become
	the pfd are zeroed, therefore _make sure_ to clear these bits. */
    memset(&pfd, 0, sizeof(pfd));
    pfd.nSize = sizeof(pfd);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | flags;
    pfd.iPixelType = type;
    pfd.cColorBits = 32;

    pf = ChoosePixelFormat(hDC, &pfd);
    if (pf == 0) {
        MessageBox(NULL, L"ChoosePixelFormat() failed:  "
                         "Cannot find a suitable pixel format.",
            L"Error", MB_OK);
        return 0;
    }

    if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
        MessageBox(NULL, L"SetPixelFormat() failed:  "
                         "Cannot set format specified.",
            L"Error", MB_OK);
        return 0;
    }

    DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

    ReleaseDC(hWnd, hDC);

    return hWnd;
}

int main()
{
    HDC hDC; /* device context */
    HGLRC hRC; /* opengl context */
    HWND hWnd; /* window */
    MSG msg; /* message */

    hWnd = CreateOpenGLWindow("minimal", 0, 0, 256, 256, PFD_TYPE_RGBA, 0);
    if (hWnd == NULL)
        exit(1);

    hDC = GetDC(hWnd);
    hRC = wglCreateContext(hDC);
    wglMakeCurrent(hDC, hRC);
    std::cout << load_gl_functions();

    ShowWindow(hWnd, 1);

    while (GetMessage(&msg, hWnd, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    wglMakeCurrent(NULL, NULL);
    ReleaseDC(hWnd, hDC);
    wglDeleteContext(hRC);
    DestroyWindow(hWnd);

    return msg.wParam;
}
<commit_msg>Simpel raymarching<commit_after>/* An example of the minimal Win32 & OpenGL program.  It only works in
16 bit color modes or higher (since it doesn't create a
palette). */

// clang-format off
#include <stdio.h>
#include <windows.h> /* must include this before GL/gl.h */
#include <GL/gl.h> /* OpenGL header file */
#include <GL/glu.h> /* OpenGL utilities header file */
#include "gl_loader.h"
#include <iostream>
#include <string>
#include <memory>

// clang-format on

using namespace std;

int programID;
const int vertexCount = 6;
GLuint vaoID, vboID;

string vertexShader = "#version 430\n\
layout (location = 0) in vec3 position;\n \
out vec2 fragCoord;\n \
\n\
void main()\n \
{\n \
	fragCoord.x = (position.x + 1) * 1 / 2.0;\n \
	fragCoord.y = (position.y + 1) * 1 / 2.0;\n \
	gl_Position = vec4(position, 1);\n \
}";
string fragmentShader = "#version 430\n\
in vec2 fragCoord; \n\
out vec4 fragColor;\n\
float udRoundBox( vec3 p, vec3 b, float r ) {\n\
	return length(max(abs(p) - b, 0.0)) - r;\n\
}\n\
\n\
void main() {\n\
	float iGlobalTime = 0.0; \n\
	vec2 uv = fragCoord.xy;\n\
	vec3 ro = vec3(iGlobalTime * 10.0, 2.0 * sin(iGlobalTime * 0.5), 2.0 * sin(iGlobalTime));\n\
	vec3 rd = normalize(vec3(1.0, uv.y - 0.5, uv.x - 0.5));\n\
	float t = 0.0;\n\
	vec3 color = vec3(0.0);\n\
	float b = (0.5 + 0.5 * sin(iGlobalTime * 10.0)) * 0.2 + 0.3;\n\
\n\
	for (int i = 0; i < 100; i++) {\n\
		vec3 p = ro + rd * t;\n\
		vec3 q = mod(p, 8.0) - 4.0;\n\
		vec3 r = p / 8.0;\n\
		float d = udRoundBox(q, vec3(0.5), 0.3);\n\
\n\
		if (d < 0.01) {\n\
			color = vec3(0.5 + 0.5 * sin(r * 1.3));\n\
\n\
			vec3 lpos = ro + vec3(-1.0, 0, 0); \n\
			float dis = length(lpos - p);\n\
			vec3 invLight = normalize(lpos - p);\n\
\n\
			vec3 normal;\n\
			vec3 ep = vec3(0.01, 0, 0);\n\
			normal.x = udRoundBox(q + ep.xyz, vec3(0.5), 0.3) - udRoundBox(q - ep.xyz, vec3(0.5), 0.3);\n\
			normal.y = udRoundBox(q + ep.yxz, vec3(0.5), 0.3) - udRoundBox(q - ep.yxz, vec3(0.5), 0.3);\n\
			normal.z = udRoundBox(q + ep.yzx, vec3(0.5), 0.3) - udRoundBox(q - ep.yzx, vec3(0.5), 0.3);\n\
			normal = normalize(normal);\n\
\n\
			float diffuse = max(0.0, dot(invLight, normal));\n\
			float s = 10.0;\n\
			float k = max(0.0, dot(rd, reflect(invLight, normal))); \n\
			float spec = pow(k, s);\n\
			float str = 80.0 / (0.1 + 0.1*dis + 0.1*dis*dis);\n\
			color = color * (0.0 + 1.0*diffuse*str) + spec*str;\n\
			break; \n\
		}\n\
		t += d;\n\
	}\n\
	fragColor = vec4(color, 1.0);\n\
	fragColor.rgb = fragColor.rgb / (fragColor.rgb + vec3(1.0));\n\
}";

void setupQuad()
{
	float vertices[] = {
		-1, 1, 0, -1, -1, 0, 1, -1, 0,
		1, -1, 0, 1, 1, 0, -1, 1, 0 };

	glGenVertexArrays(1, &vaoID);
	glBindVertexArray(vaoID);
	glEnableVertexAttribArray(0);
	glGenBuffers(1, &vboID);
	glBindBuffer(GL_ARRAY_BUFFER, vboID);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW);
	glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindVertexArray(0);
}

void loadShader()
{

	programID = glCreateProgram();
	int vertID = glCreateShader(GL_VERTEX_SHADER);
	int fragID = glCreateShader(GL_FRAGMENT_SHADER);

	int vertexShaderLength = vertexShader.length();
	auto vertexChar = vertexShader.c_str();
	glShaderSource(vertID, 1, &vertexChar, &vertexShaderLength);

	int fragmentShaderLength = fragmentShader.length();
	auto fragmentChar = fragmentShader.c_str();
	glShaderSource(fragID, 1, &fragmentChar, &fragmentShaderLength);

	glCompileShader(vertID);
	GLint param;
	glGetShaderiv(vertID, GL_COMPILE_STATUS, &param);
	if (param == GL_FALSE) {
		cout << "Failed to compile vertex shader!\n";
		int len;
		auto log = make_unique<GLchar>(1024);
		glGetShaderInfoLog(vertID, 1024, &len, log.get());
		cout << log.get();
	}

	glCompileShader(fragID);

	glGetShaderiv(fragID, GL_COMPILE_STATUS, &param);
	if (param == GL_FALSE) {
		cout << "Failed to compile fragment shader!\n";
		int len;
		char log[1024];
		glGetShaderInfoLog(fragID, 1024, &len, log);
		cout << log;
	}

	glAttachShader(programID, vertID);
	glAttachShader(programID, fragID);
	glLinkProgram(programID);

	//glValidateProgram(program);
	//System.out.println();
	//glGetProgramiv(program, GL_VALIDATE_STATUS, bb2);

	//Delete the shaders
	//glDetachShader(program, vertID);
	//glDetachShader(program, fragID);
	glDeleteShader(vertID);
	glDeleteShader(fragID);
}

void display()
{
	/* rotate a triangle around
	glActiveTexture(GL_TEXTURE0);
	glClear(GL_COLOR_BUFFER_BIT);
	glBegin(GL_TRIANGLES);
	glColor3f(1.0f, 0.0f, 0.0f);
	glVertex2i(0, 1);
	glColor3f(0.0f, 1.0f, 0.0f);
	glVertex2i(-1, -1);
	glColor3f(0.0f, 0.0f, 1.0f);
	glVertex2i(1, -1);
	glEnd();
	glFlush();*/

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glUseProgram(programID);
	glBindVertexArray(vaoID);
	glDrawArrays(GL_TRIANGLES, 0, vertexCount);
	glBindVertexArray(0);
	glFlush();
}

LONG WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static PAINTSTRUCT ps;

	switch (uMsg) {
	case WM_PAINT:
		display();
		BeginPaint(hWnd, &ps);
		EndPaint(hWnd, &ps);
		return 0;

	case WM_SIZE:
		glViewport(0, 0, LOWORD(lParam), HIWORD(lParam));
		PostMessage(hWnd, WM_PAINT, 0, 0);
		return 0;

	case WM_CHAR:
		switch (wParam) {
		case 27: /* ESC key */
			PostQuitMessage(0);
			break;
		}
		return 0;

	case WM_CLOSE:
		PostQuitMessage(0);
		return 0;
	}

	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

HWND CreateOpenGLWindow(char* title, int x, int y, int width, int height,
	BYTE type, DWORD flags)
{
	int pf;
	HDC hDC;
	HWND hWnd;
	WNDCLASS wc;
	PIXELFORMATDESCRIPTOR pfd;
	static HINSTANCE hInstance = 0;

	/* only register the window class once - use hInstance as a flag. */
	if (!hInstance) {
		hInstance = GetModuleHandle(NULL);
		wc.style = CS_OWNDC;
		wc.lpfnWndProc = (WNDPROC)WindowProc;
		wc.cbClsExtra = 0;
		wc.cbWndExtra = 0;
		wc.hInstance = hInstance;
		wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
		wc.hCursor = LoadCursor(NULL, IDC_ARROW);
		wc.hbrBackground = NULL;
		wc.lpszMenuName = NULL;
		wc.lpszClassName = L"OpenGL";

		if (!RegisterClass(&wc)) {
			MessageBox(NULL, L"RegisterClass() failed:  "
				"Cannot register window class.",
				L"Error", MB_OK);
			return NULL;
		}
	}

	hWnd = CreateWindow(L"OpenGL", L"Hej", WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
		x, y, width, height, NULL, NULL, hInstance, NULL);

	if (hWnd == NULL) {
		MessageBox(NULL, L"CreateWindow() failed:  Cannot create a window.",
			L"Error", MB_OK);
		return NULL;
	}

	hDC = GetDC(hWnd);

	/* there is no guarantee that the contents of the stack that become
	the pfd are zeroed, therefore _make sure_ to clear these bits. */
	memset(&pfd, 0, sizeof(pfd));
	pfd.nSize = sizeof(pfd);
	pfd.nVersion = 1;
	pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | flags;
	pfd.iPixelType = type;
	pfd.cColorBits = 32;

	pf = ChoosePixelFormat(hDC, &pfd);
	if (pf == 0) {
		MessageBox(NULL, L"ChoosePixelFormat() failed:  "
			"Cannot find a suitable pixel format.",
			L"Error", MB_OK);
		return 0;
	}

	if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
		MessageBox(NULL, L"SetPixelFormat() failed:  "
			"Cannot set format specified.",
			L"Error", MB_OK);
		return 0;
	}

	DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

	ReleaseDC(hWnd, hDC);

	return hWnd;
}

int main()
{
	HDC hDC; /* device context */
	HGLRC hRC; /* opengl context */
	HWND hWnd; /* window */
	MSG msg; /* message */

	hWnd = CreateOpenGLWindow("minimal", 0, 0, 256, 256, PFD_TYPE_RGBA, 0);
	if (hWnd == NULL)
		exit(1);

	hDC = GetDC(hWnd);
	hRC = wglCreateContext(hDC);
	wglMakeCurrent(hDC, hRC);
	std::cout << load_gl_functions();
	setupQuad();
	loadShader();

	ShowWindow(hWnd, 1);

	while (GetMessage(&msg, hWnd, 0, 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	wglMakeCurrent(NULL, NULL);
	ReleaseDC(hWnd, hDC);
	wglDeleteContext(hRC);
	DestroyWindow(hWnd);

	return msg.wParam;
}<|endoftext|>


<commit_before>// __BEGIN_LICENSE__
// Copyright (C) 2010 United States Government as represented by
// the Administrator of the National Aeronautics and Space Administration.
// All Rights Reserved.
// __END_LICENSE__

// What's this file supposed to do ?
//
// (Pho)tometry (It)eration Exposure (Time) Update
//
// With Reflectance
// .... see docs
//
// With out Relectance
//      T = T + sum((Ik-Tk*A)*A*Sk)/sum((A*Sk)^2)

#include <vw/Image.h>
using namespace vw;

#include <boost/program_options.hpp>
namespace po = boost::program_options;

using namespace std;

struct Options {

  // For spawning multiple jobs
  int job_id, num_jobs;
};

void handle_arguments( int argc, char *argv[], Options& opt ) {
  po::options_description general_options("");
  general_options.add_options()
    ("job_id,j", po::value<int>(&opt.job_id)->default_value(0), "")
    ("num_jobs,n", po::value<int>(&opt.num_jobs)->default_value(1), "")
    ("help,h", "Display this help message");

  po::variables_map vm;
  try {
    po::store( po::command_line_parser( argc, argv ).options(general_options).run(), vm );
    po::notify( vm );
  } catch (po::error &e) {
    vw_throw( ArgumentErr() << "Error parsing input:\n\t"
              << e.what() << general_options );
  }

  std::ostringstream usage;
  usage << "Usage: " << argv[0] << " [programmer hasn't filled this out]\n";

  if ( vm.count("help") )
    vw_throw( ArgumentErr() << usage.str() << general_options );
}

int main( int argc, char *argv[] ) {

  Options opt;
  try {
    handle_arguments( argc, argv, opt );
  } catch ( const ArgumentErr& e ) {
    vw_out() << e.what() << std::endl;
    return 1;
  } catch ( const Exception& e ) {
    std::cerr << "Error: " << e.what() << std::endl;
    return 1;
  }

  return 0;
}
<commit_msg>Phoittime works<commit_after>// __BEGIN_LICENSE__
// Copyright (C) 2010 United States Government as represented by
// the Administrator of the National Aeronautics and Space Administration.
// All Rights Reserved.
// __END_LICENSE__

// What's this file supposed to do ?
//
// (Pho)tometry (It)eration Exposure (Time) Update
//
// With Reflectance
// .... see docs
//
// With out Relectance
//      T = T + sum((Ik-Tk*A)*A*Sk)/sum((A*Sk)^2)

#include <vw/Image.h>
#include <vw/Plate/PlateFile.h>
#include <asp/PhotometryTK/RemoteProjectFile.h>
#include <asp/PhotometryTK/TimeAccumulators.h>
using namespace vw;
using namespace vw::platefile;
using namespace asp::pho;

#include <boost/foreach.hpp>
#include <boost/program_options.hpp>
namespace po = boost::program_options;

using namespace std;

struct Options {
  // Input
  std::string ptk_url;
  bool dry_run;

  // For spawning multiple jobs
  int job_id, num_jobs, level;
};

void update_exposure( Options& opt ) {

  // Open up project file
  RemoteProjectFile remote_ptk( opt.ptk_url );
  ProjectMeta project_info;
  remote_ptk.OpenProjectMeta( project_info );

  // Deciding what cameras
  int minidx, maxidx;
  minidx = float(project_info.num_cameras()*opt.job_id)/float(opt.num_jobs);
  maxidx = float(project_info.num_cameras()*(opt.job_id+1))/float(opt.num_jobs);

  // Load platefile
  boost::shared_ptr<PlateFile> drg_plate, albedo_plate, reflect_plate;
  drg_plate =
    boost::shared_ptr<PlateFile>( new PlateFile("pf://index/DRG.plate",
                                                "equi", "", 256, "tif",
                                                VW_PIXEL_GRAYA,
                                                VW_CHANNEL_UINT8 ) );
  albedo_plate =
    boost::shared_ptr<PlateFile>( new PlateFile("pf://index/Albedo.plate",
                                                "equi", "", 256, "tif",
                                                VW_PIXEL_GRAYA,
                                                VW_CHANNEL_UINT8 ) );
  if ( project_info.reflectance() != ProjectMeta::NONE )
    boost::shared_ptr<PlateFile>( new PlateFile("pf://index/Reflectance.plate",
                                                "equi", "", 256, "tif",
                                                VW_PIXEL_GRAYA,
                                                VW_CHANNEL_FLOAT32 ) );
  for (int j = minidx; j < maxidx; j++ ) {
    // Pick up current time exposure
    CameraMeta cam_info;
    remote_ptk.ReadCameraMeta(j, cam_info);
    std::cout << "Camera[" << j << "]         exposure time: "
              << cam_info.exposure_t() << "\n";

    // Deciding working area
    if ( opt.level < 0 )
      opt.level = drg_plate->num_levels() - 1;
    int full = pow(2.0,opt.level);
    int quarter = full/4;
    BBox2i affected_tiles(0,quarter,full-1,quarter*2-1);
    std::list<TileHeader> drg_tiles =
      drg_plate->search_by_region(opt.level, affected_tiles,j+1,j+1,1);
    ImageView<PixelGrayA<uint8> > drg_temp, albedo_temp;
    std::cout << "Num drg tiles: " << drg_tiles.size() << "\n";

    if ( project_info.reflectance() == ProjectMeta::NONE ) {
      // Accumulating time exposure
      TimeDeltaNRAccumulator<PixelGrayA<uint8> > taccum(cam_info.exposure_t());

      // Updating current time exposure
      BOOST_FOREACH( const TileHeader& drg_tile, drg_tiles ) {
        drg_plate->read( drg_temp, drg_tile.col(), drg_tile.row(),
                         opt.level, j+1, true );
        albedo_plate->read( albedo_temp, drg_tile.col(), drg_tile.row(),
                            opt.level, -1, true );
        for_each_pixel(drg_temp, albedo_temp, taccum);
      }
      cam_info.set_exposure_t(cam_info.exposure_t()+taccum.value());
    } else {
      vw_throw( NoImplErr() << "Sorry, reflectance code is incomplete.\n" );
      // Accumulating time exposure
      TimeDeltaAccumulator<PixelGrayA<uint8>, float> taccum(cam_info.exposure_t());

      // Updating current time exposure
    }
    if ( !opt.dry_run )
      remote_ptk.WriteCameraMeta(j, cam_info);
    std::cout << "Camera[" << j << "] updated exposure time: "
              << cam_info.exposure_t() << "\n";

  }
}

void handle_arguments( int argc, char *argv[], Options& opt ) {
  po::options_description general_options("");
  general_options.add_options()
    ("level,l", po::value<int>(&opt.level)->default_value(-1), "Default is to process lowest level.")
    ("dry-run", "Don't write results")
    ("job_id,j", po::value<int>(&opt.job_id)->default_value(0), "")
    ("num_jobs,n", po::value<int>(&opt.num_jobs)->default_value(1), "")
    ("help,h", "Display this help message");

  po::options_description positional("");
  positional.add_options()
    ("ptk_url",  po::value<std::string>(&opt.ptk_url),  "Input PTK Url");

  po::positional_options_description positional_desc;
  positional_desc.add("ptk_url", 1);

  po::options_description all_options;
  all_options.add(general_options).add(positional);

  po::variables_map vm;
  try {
    po::store( po::command_line_parser( argc, argv ).options(all_options).positional(positional_desc).run(), vm );
    po::notify( vm );
  } catch (po::error &e) {
    vw_throw( ArgumentErr() << "Error parsing input:\n\t"
              << e.what() << general_options );
  }

  std::ostringstream usage;
  usage << "Usage: " << argv[0] << " [programmer hasn't filled this out]\n";
  opt.dry_run = vm.count("dry-run");

  if ( vm.count("help") )
    vw_throw( ArgumentErr() << usage.str() << general_options );
  if ( opt.ptk_url.empty() )
    vw_throw( ArgumentErr() << "Missing project file url!\n"
              << usage.str() << general_options );
}

int main( int argc, char *argv[] ) {

  Options opt;
  try {
    handle_arguments( argc, argv, opt );
    update_exposure( opt );
  } catch ( const ArgumentErr& e ) {
    vw_out() << e.what() << std::endl;
    return 1;
  } catch ( const Exception& e ) {
    std::cerr << "Error: " << e.what() << std::endl;
    return 1;
  }

  return 0;
}
<|endoftext|>


<commit_before>/*******************************************************************************
  The MIT License (MIT)

  Copyright (c) 2015 Manuel Freiberger

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
*******************************************************************************/

#include "catch.hpp"

#include "../src/threadedstate.hpp"
#include "../src/statemachine.hpp"

#include <condition_variable>
#include <mutex>
#include <thread>

using StateMachine_t = fsm11::StateMachine<>;
using State_t = fsm11::ThreadedState<StateMachine_t>;

std::mutex g_mutex;
std::thread::id g_id;
std::condition_variable g_cv;
bool g_notify;
int g_invokeState;

class TestState : public State_t
{
public:
    using State_t::State_t;

    virtual void invoke(fsm11::ExitRequest&) override
    {
        std::lock_guard<std::mutex> lock(g_mutex);
        g_id = std::this_thread::get_id();
    }
};

template <unsigned TFn>
class WaitingState : public State_t
{
public:
    using State_t::State_t;

    virtual void invoke(fsm11::ExitRequest& request) override
    {
        g_mutex.lock();
        g_notify = true;
        g_invokeState = 1;
        g_mutex.unlock();
        g_cv.notify_all();

        switch (TFn)
        {
        case 0: request.wait(); break;
        case 1: request.waitFor(std::chrono::milliseconds(500)); break;
        default: REQUIRE(false); break;
        }

        g_mutex.lock();
        g_notify = true;
        g_invokeState = 2;
        g_mutex.unlock();
        g_cv.notify_all();
    }
};

TEST_CASE("construct threaded state", "[threadedstate]")
{
    TestState s1("s1");
    TestState s2("s2", &s1);
    REQUIRE(s2.parent() == &s1);
}

TEST_CASE("start invoke action in threaded state", "[threadedstate]")
{
    StateMachine_t sm;
    TestState s1("s1", &sm);

    g_mutex.lock();
    g_id = std::this_thread::get_id();
    g_mutex.unlock();

    sm.start();
    sm.stop();
    REQUIRE(g_id != std::this_thread::get_id());
}

TEST_CASE("waitForExitRequest blocks an invoked action", "[threadedstate]")
{
    StateMachine_t sm;
    WaitingState<0> s1("s1", &sm);

    g_notify = false;
    g_invokeState = 0;

    sm.start();

    std::unique_lock<std::mutex> lock(g_mutex);
    g_cv.wait(lock, [&] { return g_notify; });
    REQUIRE(g_invokeState == 1);
    lock.unlock();

    std::this_thread::sleep_for(std::chrono::seconds(1));

    // The invoked action must still be blocked.
    lock.lock();
    g_cv.wait(lock, [&] { return g_notify; });
    REQUIRE(g_invokeState == 1);
    g_notify = false;
    lock.unlock();

    sm.stop();

    lock.lock();
    g_cv.wait(lock, [&] { return g_notify; });
    REQUIRE(g_invokeState == 2);
    lock.unlock();
}

TEST_CASE("waitForExitRequestFor blocks an invoked action", "[threadedstate]")
{
    StateMachine_t sm;
    WaitingState<1> s1("s1", &sm);

    g_notify = false;
    g_invokeState = 0;

    sm.start();

    std::unique_lock<std::mutex> lock(g_mutex);
    g_cv.wait(lock, [&] { return g_notify; });
    REQUIRE(g_invokeState == 1);
    g_notify = false;
    lock.unlock();

    SECTION("timeout")
    {
        std::this_thread::sleep_for(std::chrono::seconds(1));

        lock.lock();
        g_cv.wait(lock, [&] { return g_notify; });
        REQUIRE(g_invokeState == 2);
        lock.unlock();

        sm.stop();
    }

    SECTION("no timeout")
    {
        sm.stop();

        lock.lock();
        g_cv.wait(lock, [&] { return g_notify; });
        REQUIRE(g_invokeState == 2);
        lock.unlock();
    }
}

TEST_CASE("invoked action is left when state machine is destructed",
          "[threadedstate]")
{
    g_notify = false;
    g_invokeState = 0;
    std::unique_lock<std::mutex> lock(g_mutex, std::defer_lock);
    std::unique_ptr<WaitingState<0>> s1;

    {
        StateMachine_t sm;
        // The state must be destructed after sm's destructor has been called.
        s1.reset(new WaitingState<0>("s1", &sm));

        sm.start();

        lock.lock();
        g_cv.wait(lock, [&] { return g_notify; });
        REQUIRE(g_invokeState == 1);
        g_notify = false;
        lock.unlock();
    }

    lock.lock();
    g_cv.wait(lock, [&] { return g_notify; });
    REQUIRE(g_invokeState == 2);
    lock.unlock();
}
<commit_msg>Added a test throwing an exception in an invoke() thread.<commit_after>/*******************************************************************************
  The MIT License (MIT)

  Copyright (c) 2015 Manuel Freiberger

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
*******************************************************************************/

#include "catch.hpp"

#include "../src/threadedstate.hpp"
#include "../src/statemachine.hpp"

#include <condition_variable>
#include <mutex>
#include <thread>

using namespace fsm11;

namespace syncSM
{
using StateMachine_t = StateMachine<>;
using State_t = ThreadedState<StateMachine_t>;
} // namespace syncSM

namespace asyncSM
{
using StateMachine_t = StateMachine<AsynchronousEventDispatching,
                                    ConfigurationChangeCallbacksEnable<true>>;
using State_t = ThreadedState<StateMachine_t>;
} // namespace asyncSM

std::mutex g_mutex;
std::thread::id g_id;
std::condition_variable g_cv;
bool g_notify;
int g_invokeState;

template <typename TBaseState>
class TestState : public TBaseState
{
public:
    using TBaseState::TBaseState;

    virtual void invoke(fsm11::ExitRequest&) override
    {
        std::lock_guard<std::mutex> lock(g_mutex);
        g_id = std::this_thread::get_id();
    }
};

template <typename TBaseState, unsigned TFn>
class WaitingState : public TBaseState
{
public:
    using TBaseState::TBaseState;

    virtual void invoke(fsm11::ExitRequest& request) override
    {
        g_mutex.lock();
        g_notify = true;
        g_invokeState = 1;
        g_mutex.unlock();
        g_cv.notify_all();

        switch (TFn)
        {
        case 0: request.wait(); break;
        case 1: request.waitFor(std::chrono::milliseconds(500)); break;
        default: REQUIRE(false); break;
        }

        g_mutex.lock();
        g_notify = true;
        g_invokeState = 2;
        g_mutex.unlock();
        g_cv.notify_all();
    }
};

TEST_CASE("construct threaded state", "[threadedstate]")
{
    using namespace syncSM;

    TestState<State_t> s1("s1");
    TestState<State_t> s2("s2", &s1);
    REQUIRE(s2.parent() == &s1);
}

TEST_CASE("start invoke action in threaded state", "[threadedstate]")
{
    using namespace syncSM;

    StateMachine_t sm;
    TestState<State_t> s1("s1", &sm);

    g_mutex.lock();
    g_id = std::this_thread::get_id();
    g_mutex.unlock();

    sm.start();
    sm.stop();
    REQUIRE(g_id != std::this_thread::get_id());
}

TEST_CASE("waitForExitRequest blocks an invoked action", "[threadedstate]")
{
    using namespace syncSM;

    StateMachine_t sm;
    WaitingState<State_t, 0> s1("s1", &sm);

    g_notify = false;
    g_invokeState = 0;

    sm.start();

    std::unique_lock<std::mutex> lock(g_mutex);
    g_cv.wait(lock, [&] { return g_notify; });
    REQUIRE(g_invokeState == 1);
    lock.unlock();

    std::this_thread::sleep_for(std::chrono::seconds(1));

    // The invoked action must still be blocked.
    lock.lock();
    g_cv.wait(lock, [&] { return g_notify; });
    REQUIRE(g_invokeState == 1);
    g_notify = false;
    lock.unlock();

    sm.stop();

    lock.lock();
    g_cv.wait(lock, [&] { return g_notify; });
    REQUIRE(g_invokeState == 2);
    lock.unlock();
}

TEST_CASE("waitForExitRequestFor blocks an invoked action", "[threadedstate]")
{
    using namespace syncSM;

    StateMachine_t sm;
    WaitingState<State_t, 1> s1("s1", &sm);

    g_notify = false;
    g_invokeState = 0;

    sm.start();

    std::unique_lock<std::mutex> lock(g_mutex);
    g_cv.wait(lock, [&] { return g_notify; });
    REQUIRE(g_invokeState == 1);
    g_notify = false;
    lock.unlock();

    SECTION("timeout")
    {
        std::this_thread::sleep_for(std::chrono::seconds(1));

        lock.lock();
        g_cv.wait(lock, [&] { return g_notify; });
        REQUIRE(g_invokeState == 2);
        lock.unlock();

        sm.stop();
    }

    SECTION("no timeout")
    {
        sm.stop();

        lock.lock();
        g_cv.wait(lock, [&] { return g_notify; });
        REQUIRE(g_invokeState == 2);
        lock.unlock();
    }
}

TEST_CASE("invoked action is left when state machine is destructed",
          "[threadedstate]")
{
    using namespace syncSM;

    g_notify = false;
    g_invokeState = 0;
    std::unique_lock<std::mutex> lock(g_mutex, std::defer_lock);
    std::unique_ptr<WaitingState<State_t, 0>> s1;

    {
        StateMachine_t sm;
        // The state must be destructed after sm's destructor has been called.
        s1.reset(new WaitingState<State_t, 0>("s1", &sm));

        sm.start();

        lock.lock();
        g_cv.wait(lock, [&] { return g_notify; });
        REQUIRE(g_invokeState == 1);
        g_notify = false;
        lock.unlock();
    }

    lock.lock();
    g_cv.wait(lock, [&] { return g_notify; });
    REQUIRE(g_invokeState == 2);
    lock.unlock();
}

struct ThreadedInvokeException
{
};

#include <iostream>
using namespace std;

template <typename TBaseState>
struct ThrowingState : public TBaseState
{
public:
    using TBaseState::TBaseState;

    virtual void invoke(fsm11::ExitRequest&) override
    {
        if (stdException)
        {
            throw std::bad_alloc();
        }
        else
        {
#ifdef FSM11_USE_WEOS
            throw WEOS_EXCEPTION(ThreadedInvokeException());
#else
            throw ThreadedInvokeException();
#endif
        }
    }

    bool stdException{false};
};

SCENARIO("throwing an exception in a threaded state", "[threadedstate]")
{
    GIVEN ("a synchronous FSM")
    {
        using namespace syncSM;
        std::unique_ptr<ThrowingState<State_t>> s;
        StateMachine_t sm;
        s.reset(new ThrowingState<State_t>("s", &sm));

        WHEN ("a standard exception is thrown in the invoked action")
        {
            s->stdException = true;
            sm.start();
            THEN ("it arrives at the caller")
            {
                REQUIRE_THROWS_AS(sm.stop(), std::bad_alloc);
            }
        }

        WHEN ("a custom exception is thrown in the invoked action")
        {
            s->stdException = false;
            sm.start();
            THEN ("it arrives at the caller")
            {
                REQUIRE_THROWS_AS(sm.stop(), ThreadedInvokeException);
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Intel Corporation
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include "umc_defs.h"
#if defined (MFX_ENABLE_MJPEG_VIDEO_DECODE)

#include "umc_jpeg_frame_constructor.h"
#include "jpegdec_base.h"

namespace UMC
{

//////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////
JpegFrameConstructor::JpegFrameConstructor()
    : m_prevLengthOfSegment(0)
    , m_code(0)
    , m_pts(-1)
    , m_suggestedSize(0)
{
    m_mediaData.SetExData(&m_mediaDataEx);
    Reset();
}

JpegFrameConstructor::~JpegFrameConstructor()
{
}

void JpegFrameConstructor::Init()
{
}

void JpegFrameConstructor::Reset()
{
    m_code = 0;
    m_pts = -1;
    m_suggestedSize = 0;
    m_prevLengthOfSegment = 0;
    m_RestartCount = 0;

    m_prev.clear();
    m_frame.clear();
    m_mediaDataEx.count = 0;
    m_mediaData.Close();

    m_flags.isSOI = 0;
    m_flags.isEOI = 0;
    m_flags.isSOS = 0;
}

void JpegFrameConstructor::Close()
{
    Reset();
}

int32_t JpegFrameConstructor::FindMarkerCode(uint8_t * (&source), size_t & size, int32_t & startCodeSize)
{
    uint32_t ffCount = 0;

    if (m_prevLengthOfSegment)
    {
        size_t copySize = MFX_MIN(m_prevLengthOfSegment, size);
        m_prevLengthOfSegment -= copySize;
        source += copySize;
        size -= copySize;

        if (m_prevLengthOfSegment)
            return 0;
    }

    for (;;)
    {
        uint32_t i = 0;
        ffCount = 0;
        for (; i < (uint32_t)size; i++)
        {
            if (source[i] == 0xff)
            {
                ffCount = 1;
                i++;
                break;
            }
        }

        for (; i < (uint32_t)size; i++, ffCount++)
        {
            if (source[i] != 0xff)
            {
                break;
            }
        }

        source += i;
        size -= i;

        if (size <= 0)
        {
            break;
        }

        if (!source[0])
        {
            ffCount = 0;
        }
        else
        {
            ffCount = 1;
            startCodeSize = ffCount + 1;
            size -= 1;
            int32_t code = source[0];
            source++;
            return code;
        }
    }

    source -= ffCount;
    size = ffCount;
    ffCount = 0;
    startCodeSize = 0;
    return 0;
}

int32_t JpegFrameConstructor::CheckMarker(MediaData * pSource)
{
    if (!pSource)
        return 0;

    if (!m_code)
        m_prev.clear();

    uint8_t * source = (uint8_t *)pSource->GetDataPointer();
    size_t  size = pSource->GetDataSize();

    int32_t startCodeSize;
    int32_t iCodeNext = FindMarkerCode(source, size, startCodeSize);

    pSource->MoveDataPointer((int32_t)(source - (uint8_t *)pSource->GetDataPointer()));
    if (iCodeNext)
    {
         pSource->MoveDataPointer(-startCodeSize);
    }

    return iCodeNext;
}

int32_t JpegFrameConstructor::GetMarker(MediaData * pSource, MediaData * pDst)
{
    if (!pSource)
        return EndOfStream(pDst);

    if (!m_code)
        m_prev.clear();

    uint8_t * source = (uint8_t *)pSource->GetDataPointer();
    size_t  size = pSource->GetDataSize();

    if (!size)
        return 0;

    int32_t startCodeSize;

    int32_t iCodeNext = FindMarkerCode(source, size, startCodeSize);

    if (m_prev.size())
    {
        if (!iCodeNext)
        {
            size_t sz = source - (uint8_t *)pSource->GetDataPointer();
            if (m_suggestedSize && m_prev.size() + sz >  m_suggestedSize)
            {
                m_prev.clear();
                sz = MFX_MIN(sz, m_suggestedSize);
            }

            m_prev.insert(m_prev.end(), (uint8_t *)pSource->GetDataPointer(), (uint8_t *)pSource->GetDataPointer() + sz);
            pSource->MoveDataPointer((int32_t)sz);
            return 0;
        }

        source -= startCodeSize;
        m_prev.insert(m_prev.end(), (uint8_t *)pSource->GetDataPointer(), source);
        pSource->MoveDataPointer((int32_t)(source - (uint8_t *)pSource->GetDataPointer()));

        pDst->SetBufferPointer(&(m_prev[0]), m_prev.size());
        pDst->SetDataSize(m_prev.size());
        pDst->SetTime(m_pts);
        int32_t code = m_code;
        m_code = 0;
        m_pts = -1;

        return code;
    }

    if (!iCodeNext)
    {
        pSource->MoveDataPointer((int32_t)(source - (uint8_t *)pSource->GetDataPointer()));
        return 0;
    }

    m_pts = pSource->GetTime();
    m_code = iCodeNext;

    // move before start code
    pSource->MoveDataPointer((int32_t)(source - (uint8_t *)pSource->GetDataPointer() - startCodeSize));

    uint32_t flags = pSource->GetFlags();

    bool wasNextMarkerFound = true;

    switch(iCodeNext)
    {
    case JM_RST0:  // standalone markers
    case JM_RST1:
    case JM_RST2:
    case JM_RST3:
    case JM_RST4:
    case JM_RST5:
    case JM_RST6:
    case JM_RST7:
    case JM_SOI:
    case JM_EOI:
    case JM_TEM:
        break;
    case JM_SOS:
        break;
    default:   // marker's segment.
        {
            if (size >= 2)
            {
                size_t length = (source[0] << 8) | source[1];

                m_prevLengthOfSegment = length;
                wasNextMarkerFound = true;
            }
            else
            {
                return 0;
            }
        }
        break;
    }

    if(m_code != JM_EOI)
    {
        int32_t startCodeSize1 = 0;

        iCodeNext = wasNextMarkerFound ? FindMarkerCode(source, size, startCodeSize1) : 0;

        //pSource->MoveDataPointer(startCodeSize);

        if (!iCodeNext && !(flags & MediaData::FLAG_VIDEO_DATA_NOT_FULL_UNIT))
        {
            iCodeNext = 1;
            startCodeSize1 = 0;
        }

        if (!iCodeNext)
        {
            VM_ASSERT(!m_prev.size());
            size_t sz = source - (uint8_t *)pSource->GetDataPointer();
            if (m_suggestedSize && sz >  m_suggestedSize)
            {
                sz = m_suggestedSize;
            }

            m_prev.insert(m_prev.end(), (uint8_t *)pSource->GetDataPointer(), (uint8_t *)pSource->GetDataPointer() + sz);
            pSource->MoveDataPointer((int32_t)sz);
            return 0;
        }

        // fill
        size_t nal_size = source - (uint8_t *)pSource->GetDataPointer() - startCodeSize1;
        pDst->SetBufferPointer((uint8_t*)pSource->GetDataPointer(), nal_size);
        pDst->SetDataSize(nal_size);
        pSource->MoveDataPointer((int32_t)nal_size);
    }
    else
    {
        pSource->MoveDataPointer(2);
    }

    int32_t code = m_code;
    m_code = 0;

    pDst->SetTime(m_pts);
    m_pts = -1;
    return code;
}

int32_t JpegFrameConstructor::EndOfStream(MediaData * pDst)
{
    if (!m_code)
    {
        m_prev.clear();
        return 0;
    }

    if (m_prev.size())
    {
        pDst->SetBufferPointer(&(m_prev[0]), m_prev.size());
        pDst->SetDataSize(m_prev.size());
        pDst->SetTime(m_pts);
        int32_t code = m_code;
        m_code = 0;
        m_pts = -1;
        return code;
    }

    m_code = 0;
    return 0;
}

Status JpegFrameConstructor::AddMarker(uint32_t marker, MediaDataEx::_MediaDataEx* pMediaDataEx, size_t nBufferSize, MediaData *dst)
{
    if (!dst->GetDataSize())
        return UMC_OK;

    uint32_t element = pMediaDataEx->count;

    if (element >= pMediaDataEx->limit - 1)
        return UMC_ERR_FAILED;

    m_frame.insert(m_frame.end(), (uint8_t*)dst->GetDataPointer(), (uint8_t*)dst->GetDataPointer() + dst->GetDataSize() );

    pMediaDataEx->offsets[0] = 0;
    // process RST marker
    if((JM_RST0 <= marker) && (JM_RST7 >= marker))
    {
        // add marker to MediaDataEx
        if((unsigned long long)m_frame.size() > ((unsigned long long)nBufferSize * element) / (pMediaDataEx->limit - 2))
        {
            pMediaDataEx->values[element] = marker | (m_RestartCount << 8);
            pMediaDataEx->offsets[element + 1] = (uint32_t)m_frame.size();
            pMediaDataEx->count++;
        }
        // the end of previous interval would be the start of next
        else
        {
            pMediaDataEx->offsets[element] = (uint32_t)m_frame.size();
        }
        m_RestartCount++;
    }
    // process SOS marker (add it anyway)
    else if(JM_SOS == marker)
    {
        pMediaDataEx->values[element] = marker | (m_RestartCount << 8);
        pMediaDataEx->offsets[element + 1] = (uint32_t)m_frame.size();
        pMediaDataEx->count++;
        m_RestartCount++;
    }
    else
    {
        pMediaDataEx->values[element] = marker | (m_RestartCount << 8);
        pMediaDataEx->offsets[element + 1] = (uint32_t)m_frame.size();
        pMediaDataEx->count++;
    }

    return UMC_OK;
}

void JpegFrameConstructor::ResetForNewFrame()
{
    m_frame.clear();
    m_mediaDataEx.count = 0;
    m_flags.isSOI = 0;
    m_flags.isEOI = 0;
    m_flags.isSOS = 0;
    m_RestartCount = 0;
}

MediaDataEx * JpegFrameConstructor::GetFrame(MediaData * in, uint32_t maxBitstreamSize)
{
    for (;;)
    {
        MediaData dst;
        uint32_t marker = GetMarker(in, &dst);

        if (marker == JM_NONE)
        {
            if(!in)
                break;

            // frame is not declared as "complete", and next marker is not found
            if(in->GetFlags() & MediaData::FLAG_VIDEO_DATA_NOT_FULL_FRAME)
                break;

            // frame is declared as "complete", but it does not contain SOS marker
            if(!(in->GetFlags() & MediaData::FLAG_VIDEO_DATA_NOT_FULL_FRAME) && m_flags.isSOS == 0)
                break;
        }

        switch(marker)
        {
        case JM_SOI:
            if (m_flags.isSOI && m_flags.isSOS && m_frame.size() && !m_flags.isEOI) // EOI wasn't received
            {
                m_flags.isEOI = 1; // emulate EOI
                m_mediaData.SetBufferPointer(&m_frame[0], m_frame.size());
                m_mediaData.SetDataSize(m_frame.size());
                m_mediaData.SetFlags(in ? in->GetFlags() : 0);
                return &m_mediaData;
            }

            m_mediaData.SetTime(in->GetTime());
            m_frame.clear();
            m_mediaDataEx.count = 0;
            m_flags.isSOI = 1;
            m_flags.isEOI = 0;
            m_flags.isSOS = 0;
            m_RestartCount = 0;
            break;

            // JPEG picture data
        case JM_RST0:
        case JM_RST1:
        case JM_RST2:
        case JM_RST3:
        case JM_RST4:
        case JM_RST5:
        case JM_RST6:
        case JM_RST7:
        case JM_SOS:
            if (m_flags.isSOI)
            {
                m_flags.isSOS = 1;
            }
            else
            {
                continue;
            }
            break;

        case JM_EOI:
        default:
            break;
        }

        if (AddMarker(marker, &m_mediaDataEx, MFX_MAX(in ? in->GetBufferSize() : 0, maxBitstreamSize), &dst) != UMC_OK)
        {
            ResetForNewFrame();
            continue;
        }

        if (marker == JM_EOI)
        {
            if (m_flags.isEOI || !m_frame.size() || !m_flags.isSOS)
            {
                ResetForNewFrame();
                continue;
            }

            m_flags.isEOI = 1;

            if (m_frame.size())
            {
                m_flags.isEOI = 0;
                m_flags.isSOS = 0;

                m_mediaData.SetBufferPointer(&m_frame[0], m_frame.size());
                m_mediaData.SetDataSize(m_frame.size());
                m_mediaData.SetFlags(in ? in->GetFlags() : 0);
                return &m_mediaData;
            }
        }

        if(marker == JM_NONE && !(in->GetFlags() & MediaData::FLAG_VIDEO_DATA_NOT_FULL_FRAME) && m_flags.isSOS == 1)
        {
            if (m_frame.size())
            {
                m_flags.isEOI = 0;
                m_flags.isSOS = 0;

                m_mediaData.SetBufferPointer(&m_frame[0], m_frame.size());
                m_mediaData.SetDataSize(m_frame.size());
                m_mediaData.SetFlags(in ? in->GetFlags() : 0);
                return &m_mediaData;
            }
        }
    }

    return 0;
}

} // end namespace UMC

#endif // MFX_ENABLE_MJPEG_VIDEO_DECODE
<commit_msg>[MJPEGd/UMC]Aviod possinle dereferencing nullptr "in"<commit_after>// Copyright (c) 2017 Intel Corporation
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include "umc_defs.h"
#if defined (MFX_ENABLE_MJPEG_VIDEO_DECODE)

#include "umc_jpeg_frame_constructor.h"
#include "jpegdec_base.h"

namespace UMC
{

//////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////
JpegFrameConstructor::JpegFrameConstructor()
    : m_prevLengthOfSegment(0)
    , m_code(0)
    , m_pts(-1)
    , m_suggestedSize(0)
{
    m_mediaData.SetExData(&m_mediaDataEx);
    Reset();
}

JpegFrameConstructor::~JpegFrameConstructor()
{
}

void JpegFrameConstructor::Init()
{
}

void JpegFrameConstructor::Reset()
{
    m_code = 0;
    m_pts = -1;
    m_suggestedSize = 0;
    m_prevLengthOfSegment = 0;
    m_RestartCount = 0;

    m_prev.clear();
    m_frame.clear();
    m_mediaDataEx.count = 0;
    m_mediaData.Close();

    m_flags.isSOI = 0;
    m_flags.isEOI = 0;
    m_flags.isSOS = 0;
}

void JpegFrameConstructor::Close()
{
    Reset();
}

int32_t JpegFrameConstructor::FindMarkerCode(uint8_t * (&source), size_t & size, int32_t & startCodeSize)
{
    uint32_t ffCount = 0;

    if (m_prevLengthOfSegment)
    {
        size_t copySize = MFX_MIN(m_prevLengthOfSegment, size);
        m_prevLengthOfSegment -= copySize;
        source += copySize;
        size -= copySize;

        if (m_prevLengthOfSegment)
            return 0;
    }

    for (;;)
    {
        uint32_t i = 0;
        ffCount = 0;
        for (; i < (uint32_t)size; i++)
        {
            if (source[i] == 0xff)
            {
                ffCount = 1;
                i++;
                break;
            }
        }

        for (; i < (uint32_t)size; i++, ffCount++)
        {
            if (source[i] != 0xff)
            {
                break;
            }
        }

        source += i;
        size -= i;

        if (size <= 0)
        {
            break;
        }

        if (!source[0])
        {
            ffCount = 0;
        }
        else
        {
            ffCount = 1;
            startCodeSize = ffCount + 1;
            size -= 1;
            int32_t code = source[0];
            source++;
            return code;
        }
    }

    source -= ffCount;
    size = ffCount;
    ffCount = 0;
    startCodeSize = 0;
    return 0;
}

int32_t JpegFrameConstructor::CheckMarker(MediaData * pSource)
{
    if (!pSource)
        return 0;

    if (!m_code)
        m_prev.clear();

    uint8_t * source = (uint8_t *)pSource->GetDataPointer();
    size_t  size = pSource->GetDataSize();

    int32_t startCodeSize;
    int32_t iCodeNext = FindMarkerCode(source, size, startCodeSize);

    pSource->MoveDataPointer((int32_t)(source - (uint8_t *)pSource->GetDataPointer()));
    if (iCodeNext)
    {
         pSource->MoveDataPointer(-startCodeSize);
    }

    return iCodeNext;
}

int32_t JpegFrameConstructor::GetMarker(MediaData * pSource, MediaData * pDst)
{
    if (!pSource)
        return EndOfStream(pDst);

    if (!m_code)
        m_prev.clear();

    uint8_t * source = (uint8_t *)pSource->GetDataPointer();
    size_t  size = pSource->GetDataSize();

    if (!size)
        return 0;

    int32_t startCodeSize;

    int32_t iCodeNext = FindMarkerCode(source, size, startCodeSize);

    if (m_prev.size())
    {
        if (!iCodeNext)
        {
            size_t sz = source - (uint8_t *)pSource->GetDataPointer();
            if (m_suggestedSize && m_prev.size() + sz >  m_suggestedSize)
            {
                m_prev.clear();
                sz = MFX_MIN(sz, m_suggestedSize);
            }

            m_prev.insert(m_prev.end(), (uint8_t *)pSource->GetDataPointer(), (uint8_t *)pSource->GetDataPointer() + sz);
            pSource->MoveDataPointer((int32_t)sz);
            return 0;
        }

        source -= startCodeSize;
        m_prev.insert(m_prev.end(), (uint8_t *)pSource->GetDataPointer(), source);
        pSource->MoveDataPointer((int32_t)(source - (uint8_t *)pSource->GetDataPointer()));

        pDst->SetBufferPointer(&(m_prev[0]), m_prev.size());
        pDst->SetDataSize(m_prev.size());
        pDst->SetTime(m_pts);
        int32_t code = m_code;
        m_code = 0;
        m_pts = -1;

        return code;
    }

    if (!iCodeNext)
    {
        pSource->MoveDataPointer((int32_t)(source - (uint8_t *)pSource->GetDataPointer()));
        return 0;
    }

    m_pts = pSource->GetTime();
    m_code = iCodeNext;

    // move before start code
    pSource->MoveDataPointer((int32_t)(source - (uint8_t *)pSource->GetDataPointer() - startCodeSize));

    uint32_t flags = pSource->GetFlags();

    bool wasNextMarkerFound = true;

    switch(iCodeNext)
    {
    case JM_RST0:  // standalone markers
    case JM_RST1:
    case JM_RST2:
    case JM_RST3:
    case JM_RST4:
    case JM_RST5:
    case JM_RST6:
    case JM_RST7:
    case JM_SOI:
    case JM_EOI:
    case JM_TEM:
        break;
    case JM_SOS:
        break;
    default:   // marker's segment.
        {
            if (size >= 2)
            {
                size_t length = (source[0] << 8) | source[1];

                m_prevLengthOfSegment = length;
                wasNextMarkerFound = true;
            }
            else
            {
                return 0;
            }
        }
        break;
    }

    if(m_code != JM_EOI)
    {
        int32_t startCodeSize1 = 0;

        iCodeNext = wasNextMarkerFound ? FindMarkerCode(source, size, startCodeSize1) : 0;

        //pSource->MoveDataPointer(startCodeSize);

        if (!iCodeNext && !(flags & MediaData::FLAG_VIDEO_DATA_NOT_FULL_UNIT))
        {
            iCodeNext = 1;
            startCodeSize1 = 0;
        }

        if (!iCodeNext)
        {
            VM_ASSERT(!m_prev.size());
            size_t sz = source - (uint8_t *)pSource->GetDataPointer();
            if (m_suggestedSize && sz >  m_suggestedSize)
            {
                sz = m_suggestedSize;
            }

            m_prev.insert(m_prev.end(), (uint8_t *)pSource->GetDataPointer(), (uint8_t *)pSource->GetDataPointer() + sz);
            pSource->MoveDataPointer((int32_t)sz);
            return 0;
        }

        // fill
        size_t nal_size = source - (uint8_t *)pSource->GetDataPointer() - startCodeSize1;
        pDst->SetBufferPointer((uint8_t*)pSource->GetDataPointer(), nal_size);
        pDst->SetDataSize(nal_size);
        pSource->MoveDataPointer((int32_t)nal_size);
    }
    else
    {
        pSource->MoveDataPointer(2);
    }

    int32_t code = m_code;
    m_code = 0;

    pDst->SetTime(m_pts);
    m_pts = -1;
    return code;
}

int32_t JpegFrameConstructor::EndOfStream(MediaData * pDst)
{
    if (!m_code)
    {
        m_prev.clear();
        return 0;
    }

    if (m_prev.size())
    {
        pDst->SetBufferPointer(&(m_prev[0]), m_prev.size());
        pDst->SetDataSize(m_prev.size());
        pDst->SetTime(m_pts);
        int32_t code = m_code;
        m_code = 0;
        m_pts = -1;
        return code;
    }

    m_code = 0;
    return 0;
}

Status JpegFrameConstructor::AddMarker(uint32_t marker, MediaDataEx::_MediaDataEx* pMediaDataEx, size_t nBufferSize, MediaData *dst)
{
    if (!dst->GetDataSize())
        return UMC_OK;

    uint32_t element = pMediaDataEx->count;

    if (element >= pMediaDataEx->limit - 1)
        return UMC_ERR_FAILED;

    m_frame.insert(m_frame.end(), (uint8_t*)dst->GetDataPointer(), (uint8_t*)dst->GetDataPointer() + dst->GetDataSize() );

    pMediaDataEx->offsets[0] = 0;
    // process RST marker
    if((JM_RST0 <= marker) && (JM_RST7 >= marker))
    {
        // add marker to MediaDataEx
        if((unsigned long long)m_frame.size() > ((unsigned long long)nBufferSize * element) / (pMediaDataEx->limit - 2))
        {
            pMediaDataEx->values[element] = marker | (m_RestartCount << 8);
            pMediaDataEx->offsets[element + 1] = (uint32_t)m_frame.size();
            pMediaDataEx->count++;
        }
        // the end of previous interval would be the start of next
        else
        {
            pMediaDataEx->offsets[element] = (uint32_t)m_frame.size();
        }
        m_RestartCount++;
    }
    // process SOS marker (add it anyway)
    else if(JM_SOS == marker)
    {
        pMediaDataEx->values[element] = marker | (m_RestartCount << 8);
        pMediaDataEx->offsets[element + 1] = (uint32_t)m_frame.size();
        pMediaDataEx->count++;
        m_RestartCount++;
    }
    else
    {
        pMediaDataEx->values[element] = marker | (m_RestartCount << 8);
        pMediaDataEx->offsets[element + 1] = (uint32_t)m_frame.size();
        pMediaDataEx->count++;
    }

    return UMC_OK;
}

void JpegFrameConstructor::ResetForNewFrame()
{
    m_frame.clear();
    m_mediaDataEx.count = 0;
    m_flags.isSOI = 0;
    m_flags.isEOI = 0;
    m_flags.isSOS = 0;
    m_RestartCount = 0;
}

MediaDataEx * JpegFrameConstructor::GetFrame(MediaData * in, uint32_t maxBitstreamSize)
{
    for (;;)
    {
        MediaData dst;
        uint32_t marker = GetMarker(in, &dst);

        if (marker == JM_NONE)
        {
            if(in == nullptr)
                break;

            // frame is not declared as "complete", and next marker is not found
            if(in->GetFlags() & MediaData::FLAG_VIDEO_DATA_NOT_FULL_FRAME)
                break;

            // frame is declared as "complete", but it does not contain SOS marker
            if(!(in->GetFlags() & MediaData::FLAG_VIDEO_DATA_NOT_FULL_FRAME) && m_flags.isSOS == 0)
                break;
        }

        switch(marker)
        {
        case JM_SOI:
            if (m_flags.isSOI && m_flags.isSOS && m_frame.size() && !m_flags.isEOI) // EOI wasn't received
            {
                m_flags.isEOI = 1; // emulate EOI
                m_mediaData.SetBufferPointer(&m_frame[0], m_frame.size());
                m_mediaData.SetDataSize(m_frame.size());
                m_mediaData.SetFlags(in != nullptr ? in->GetFlags() : 0);
                return &m_mediaData;
            }

            m_mediaData.SetTime(in != nullptr ? in->GetTime() : 0);
            m_frame.clear();
            m_mediaDataEx.count = 0;
            m_flags.isSOI = 1;
            m_flags.isEOI = 0;
            m_flags.isSOS = 0;
            m_RestartCount = 0;
            break;

            // JPEG picture data
        case JM_RST0:
        case JM_RST1:
        case JM_RST2:
        case JM_RST3:
        case JM_RST4:
        case JM_RST5:
        case JM_RST6:
        case JM_RST7:
        case JM_SOS:
            if (m_flags.isSOI)
            {
                m_flags.isSOS = 1;
            }
            else
            {
                continue;
            }
            break;

        case JM_EOI:
        default:
            break;
        }

        if (AddMarker(marker, &m_mediaDataEx, std::max(in != nullptr ? in->GetBufferSize() : 0, (size_t)maxBitstreamSize), &dst) != UMC_OK)
        {
            ResetForNewFrame();
            continue;
        }

        if (marker == JM_EOI)
        {
            if (m_flags.isEOI || !m_frame.size() || !m_flags.isSOS)
            {
                ResetForNewFrame();
                continue;
            }

            m_flags.isEOI = 1;

            if (m_frame.size())
            {
                m_flags.isEOI = 0;
                m_flags.isSOS = 0;

                m_mediaData.SetBufferPointer(&m_frame[0], m_frame.size());
                m_mediaData.SetDataSize(m_frame.size());
                m_mediaData.SetFlags(in != nullptr ? in->GetFlags() : 0);
                return &m_mediaData;
            }
        }

        if(marker == JM_NONE &&
           (in == nullptr || !(in->GetFlags() & MediaData::FLAG_VIDEO_DATA_NOT_FULL_FRAME)) &&
           m_flags.isSOS == 1)
        {
            if (m_frame.size())
            {
                m_flags.isEOI = 0;
                m_flags.isSOS = 0;

                m_mediaData.SetBufferPointer(&m_frame[0], m_frame.size());
                m_mediaData.SetDataSize(m_frame.size());
                m_mediaData.SetFlags(in != nullptr ? in->GetFlags() : 0);
                return &m_mediaData;
            }
        }
    }

    return 0;
}

} // end namespace UMC

#endif // MFX_ENABLE_MJPEG_VIDEO_DECODE
<|endoftext|>